init
This commit is contained in:
commit
83007b6f04
32
.editorconfig
Normal file
32
.editorconfig
Normal file
@ -0,0 +1,32 @@
|
||||
; http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.txt]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[*.m]
|
||||
indent_size = 4
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
|
||||
[*.{js,json,ts}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
72
.eslintrc.json
Normal file
72
.eslintrc.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": false
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es2020": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": ["eslint:recommended"],
|
||||
"rules": {
|
||||
"no-console": 2,
|
||||
"no-with": 2,
|
||||
"brace-style": [
|
||||
2,
|
||||
"1tbs",
|
||||
{
|
||||
"allowSingleLine": true
|
||||
}
|
||||
],
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"one-var": [
|
||||
2,
|
||||
{
|
||||
"uninitialized": "always",
|
||||
"initialized": "never"
|
||||
}
|
||||
],
|
||||
"quote-props": [2, "as-needed"],
|
||||
"key-spacing": [
|
||||
2,
|
||||
{
|
||||
"beforeColon": false,
|
||||
"afterColon": true
|
||||
}
|
||||
],
|
||||
"space-unary-ops": [
|
||||
2,
|
||||
{
|
||||
"nonwords": false,
|
||||
"overrides": {}
|
||||
}
|
||||
],
|
||||
"space-before-function-paren": [2, "never"],
|
||||
"space-in-parens": [2, "never"],
|
||||
"no-trailing-spaces": 2,
|
||||
"max-len": [2, 160],
|
||||
"camelcase": 0,
|
||||
"curly": [2, "all"],
|
||||
"keyword-spacing": [2, {}],
|
||||
"spaced-comment": [2, "always"],
|
||||
"space-infix-ops": 2,
|
||||
"space-before-blocks": [2, "always"],
|
||||
"comma-dangle": 0,
|
||||
"no-else-return": 0,
|
||||
"indent": [
|
||||
2,
|
||||
2,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"linebreak-style": [2, "unix"],
|
||||
"quotes": [2, "single"]
|
||||
}
|
||||
}
|
182
.gitignore
vendored
Normal file
182
.gitignore
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Archives template
|
||||
# It's better to unpack these files and commit the raw source because
|
||||
# git has its own built in compression methods.
|
||||
*.7z
|
||||
*.jar
|
||||
*.rar
|
||||
*.zip
|
||||
*.gz
|
||||
*.bzip
|
||||
*.bz2
|
||||
*.xz
|
||||
*.lzma
|
||||
*.cab
|
||||
|
||||
#packing-only formats
|
||||
*.iso
|
||||
*.tar
|
||||
|
||||
#package management formats
|
||||
*.dmg
|
||||
*.xpi
|
||||
*.gem
|
||||
*.egg
|
||||
*.deb
|
||||
*.rpm
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
### Windows template
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
### OSX template
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
### Node template
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
||||
node_modules
|
||||
bower_components
|
||||
|
||||
### VisualStudioCode template
|
||||
.settings
|
||||
|
||||
### Xcode template
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
|
||||
## Other
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
dist
|
||||
.nyc_output
|
||||
.prettierc
|
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"semi": true,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
166
lib/carpark.js
Normal file
166
lib/carpark.js
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
|
||||
The following charges are used:
|
||||
|
||||
Short Stay
|
||||
£1.10 per hour between 8am and 6pm on weekdays, free outside of these times.
|
||||
Visits need not be whole hours and can last more than one day.
|
||||
|
||||
Long Stay
|
||||
£7.50 per day or part day including weekends, so the minimum charge will be for one day.
|
||||
|
||||
|
||||
A stay entirely outside of a chargeable period will return £0.00
|
||||
A short stay from 07/09/2017 16:50:00 to 09/09/2017 19:15:00 would cost £12.28
|
||||
Thursday => Saturday ( 1504803000 => 1504984500)
|
||||
|
||||
Thursday: 1h 10m = 1.28
|
||||
Friday: 10h = 11.00
|
||||
Saturday: free
|
||||
|
||||
A long stay from 07/09/2017 07:50:00 to 09/09/2017 05:20:00 would cost £22.50
|
||||
Thursday => Saturday ( 1504770600 => 1504934400)
|
||||
|
||||
Thursday: 1 = 7.5
|
||||
Friday: 1
|
||||
Saturday: 1
|
||||
Total: 22.50
|
||||
|
||||
---
|
||||
|
||||
hour = 3600 seconds
|
||||
|
||||
|
||||
|
||||
1604414190894
|
||||
|
||||
*/
|
||||
|
||||
const fecha = require('fecha');
|
||||
|
||||
class Carpark {
|
||||
#_startDT;
|
||||
#_endDT;
|
||||
#_dayLength = 60 * 60 * 24;
|
||||
#_hourLength = 60 * 60;
|
||||
#_validDays = [1, 2, 3, 4, 5]; // Monday, Tuesday, Wednesday, Thursday, Friday
|
||||
#_validStart = this.#_hourLength * 8; // 8AM // 08:00
|
||||
#_validEnd = this.#_hourLength * 18; // 6PM // 18:00
|
||||
#_longPrice = 7.5;
|
||||
#_shortPrice = 1.1;
|
||||
#_secondPrice = this.#_shortPrice / this.#_hourLength;
|
||||
|
||||
/**
|
||||
* Check if a specific timestamp is a valid date
|
||||
* @param workTime
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isValidTime(workTime) {
|
||||
const day = new Date(workTime * 1000).getDay();
|
||||
|
||||
if (this.#_validDays.indexOf(day) > -1) {
|
||||
const dayBase = ~~(workTime / this.#_dayLength) * this.#_dayLength;
|
||||
const dayPosition = workTime - dayBase;
|
||||
|
||||
return dayPosition >= this.#_validStart && dayPosition < this.#_validEnd - 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate short term parking costs
|
||||
* @returns {number}
|
||||
* @private
|
||||
*/
|
||||
_calcShortTerm() {
|
||||
let startSeconds = this.#_startDT.getTime() / 1000;
|
||||
let endSeconds = this.#_endDT.getTime() / 1000;
|
||||
let workTime, total;
|
||||
let validHours = 0;
|
||||
let startHourPart = 0;
|
||||
|
||||
// Calculate Start Hour
|
||||
let startBaseHour = ~~(startSeconds / this.#_hourLength) * this.#_hourLength;
|
||||
|
||||
// Calculate End Hour
|
||||
let endBaseHour = ~~(endSeconds / this.#_hourLength) * this.#_hourLength;
|
||||
|
||||
// Check if the very first portion of the hour is valid
|
||||
if (this._isValidTime(startSeconds)) {
|
||||
startHourPart = this.#_hourLength - (startSeconds - startBaseHour);
|
||||
}
|
||||
|
||||
// Go to the next hour after the initial start
|
||||
workTime = startBaseHour + this.#_hourLength;
|
||||
|
||||
// If there's more of an hours worth of time then loop through the next hours
|
||||
if (endBaseHour - workTime > this.#_hourLength) {
|
||||
do {
|
||||
validHours = validHours + (this._isValidTime(workTime) ? 1 : 0);
|
||||
workTime = workTime + this.#_hourLength;
|
||||
} while (workTime <= endBaseHour);
|
||||
}
|
||||
|
||||
// Sum it all
|
||||
total = startHourPart * this.#_secondPrice + validHours * this.#_shortPrice;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate long term parking costs
|
||||
* @returns {number}
|
||||
* @private
|
||||
*/
|
||||
_calcLongTerm() {
|
||||
// convert to time stamps and make them second based
|
||||
const startSeconds = this.#_startDT.getTime() / 1000;
|
||||
const endSeconds = this.#_endDT.getTime() / 1000;
|
||||
|
||||
// Very start of the first day
|
||||
const startBaseSeconds = ~~(startSeconds / this.#_dayLength) * this.#_dayLength;
|
||||
|
||||
// Very end of the second day
|
||||
const endBaseSeconds = ~~(endSeconds / this.#_dayLength) * this.#_dayLength + this.#_dayLength;
|
||||
|
||||
// Subtract the start seconds from the end seconds
|
||||
const distance = endBaseSeconds - startBaseSeconds;
|
||||
|
||||
// divide them by number of seconds in a day and multiply by cost
|
||||
|
||||
return (distance / this.#_dayLength) * this.#_longPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* The public calculate method
|
||||
* @param start
|
||||
* @param end
|
||||
* @param mode
|
||||
* @returns {number}
|
||||
*/
|
||||
calculate(start, end, mode = 'longterm') {
|
||||
let workVal = 0.0;
|
||||
this.#_startDT = fecha.parse(start, 'DD/MM/YYYY HH:mm:ssZ');
|
||||
this.#_endDT = fecha.parse(end, 'DD/MM/YYYY HH:mm:ssZ');
|
||||
|
||||
switch (mode.toLowerCase()) {
|
||||
case 'short':
|
||||
case 'shortterm':
|
||||
workVal = this._calcShortTerm();
|
||||
break;
|
||||
|
||||
case 'long':
|
||||
case 'longterm':
|
||||
workVal = this._calcLongTerm();
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
return parseFloat(workVal.toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Carpark;
|
4378
package-lock.json
generated
Normal file
4378
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
package.json
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "hotdocs",
|
||||
"version": "1.0.0",
|
||||
"description": "Parking Charge Calculator",
|
||||
"main": "lib/carpark.js",
|
||||
"scripts": {
|
||||
"test:js": "mocha test/**/*.js",
|
||||
"test:ts": "mocha -r ts-node/register test/**/*.ts",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"coverage": "nyc npm run test:js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Martin Donnelly",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.14",
|
||||
"@types/mocha": "^8.0.3",
|
||||
"@types/node": "^14.14.6",
|
||||
"@typescript-eslint/eslint-plugin": "^4.6.1",
|
||||
"@typescript-eslint/parser": "^4.6.1",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.12.1",
|
||||
"expect.js": "^0.3.1",
|
||||
"mocha": "^8.2.1",
|
||||
"nyc": "^15.1.0",
|
||||
"ts-node": "^9.0.0",
|
||||
"typings": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"fecha": "^4.2.0"
|
||||
}
|
||||
}
|
68
test/carpark-ts.ts
Normal file
68
test/carpark-ts.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import Carpark from '../ts-lib/carpark-calc';
|
||||
|
||||
import { expect } from 'chai';
|
||||
// const expect = require('expect.js');
|
||||
|
||||
|
||||
describe('Carpark Calculator', () => {
|
||||
let carPark: Carpark;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
carPark = new Carpark();
|
||||
});
|
||||
|
||||
it('Should return 0.00 outside of a chargeable period', () => {
|
||||
|
||||
const start = '09/09/2017 05:20:00';
|
||||
const end = '09/09/2017 19:15:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'short')).to.equal(0);
|
||||
});
|
||||
|
||||
|
||||
it('A specific short stay should cost £12.28', () => {
|
||||
|
||||
const start = '07/09/2017 16:50:00';
|
||||
const end = '09/09/2017 19:15:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'short')).to.equal(12.28);
|
||||
|
||||
});
|
||||
|
||||
it('A specific long stay should cost £22.50', () => {
|
||||
|
||||
const start = '07/09/2017 07:50:00';
|
||||
const end = '09/09/2017 05:20:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.equal(22.50);
|
||||
|
||||
});
|
||||
|
||||
it('A very specific long stay should cost £15.00', () => {
|
||||
|
||||
const start = '24/10/2020 10:00:00';
|
||||
const end = '25/10/2020 10:00:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.equal(15.00);
|
||||
|
||||
});
|
||||
|
||||
it('A single day of long stay should cost £7.50', () => {
|
||||
|
||||
const start = '24/10/2020 10:00:00';
|
||||
const end = '24/10/2020 23:59:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.equal(7.50);
|
||||
|
||||
});
|
||||
|
||||
it('A single week of long stay should cost £52.50', () => {
|
||||
|
||||
const start = '24/10/2020 10:00:00';
|
||||
const end = '30/10/2020 10:00:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.equal(52.50);
|
||||
|
||||
});
|
||||
});
|
53
test/carpark.js
Normal file
53
test/carpark.js
Normal file
@ -0,0 +1,53 @@
|
||||
const Carpark = require('../lib/carpark');
|
||||
|
||||
const expect = require('expect.js');
|
||||
|
||||
describe('Carpark Calculator', () => {
|
||||
let carPark;
|
||||
|
||||
beforeEach(() => {
|
||||
carPark = new Carpark();
|
||||
});
|
||||
|
||||
it('Should return 0.00 outside of a chargeable period', () => {
|
||||
const start = '09/09/2017 05:20:00';
|
||||
const end = '09/09/2017 19:15:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'short')).to.be(0);
|
||||
});
|
||||
|
||||
it('A specific short stay should cost £12.28', () => {
|
||||
const start = '07/09/2017 16:50:00';
|
||||
const end = '09/09/2017 19:15:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'short')).to.be(12.28);
|
||||
});
|
||||
|
||||
it('A specific long stay should cost £22.50', () => {
|
||||
const start = '07/09/2017 07:50:00';
|
||||
const end = '09/09/2017 05:20:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.be(22.5);
|
||||
});
|
||||
|
||||
it('A very specific long stay should cost £15.00', () => {
|
||||
const start = '24/10/2020 10:00:00';
|
||||
const end = '25/10/2020 10:00:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.be(15.0);
|
||||
});
|
||||
|
||||
it('A single day of long stay should cost £7.50', () => {
|
||||
const start = '24/10/2020 10:00:00';
|
||||
const end = '24/10/2020 23:59:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.be(7.5);
|
||||
});
|
||||
|
||||
it('A single week of long stay should cost £52.50', () => {
|
||||
const start = '24/10/2020 10:00:00';
|
||||
const end = '30/10/2020 10:00:00';
|
||||
|
||||
expect(carPark.calculate(start, end, 'long')).to.be(52.5);
|
||||
});
|
||||
});
|
123
ts-lib/carpark-calc.ts
Normal file
123
ts-lib/carpark-calc.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import { parse } from 'fecha';
|
||||
|
||||
class Carpark {
|
||||
private _startDT: Date;
|
||||
private _endDT: Date;
|
||||
private _dayLength: number = 60 * 60 * 24;
|
||||
private _hourLength: number = 60 * 60;
|
||||
private _validDays: number[] = [1, 2, 3, 4, 5]; // Monday, Tuesday, Wednesday, Thursday, Friday
|
||||
private _validStart: number = this._hourLength * 8; // 8AM // 08:00
|
||||
private _validEnd: number = this._hourLength * 18; // 6PM // 18:00
|
||||
private _longPrice = 7.5;
|
||||
private _shortPrice = 1.1;
|
||||
private _secondPrice: number = this._shortPrice / this._hourLength;
|
||||
|
||||
/**
|
||||
* Check if a specific timestamp is a valid date
|
||||
* @param workTime
|
||||
*/
|
||||
private _isValidTime(workTime: number): boolean {
|
||||
const day = new Date(workTime * 1000).getDay();
|
||||
|
||||
if (this._validDays.indexOf(day) > -1) {
|
||||
const dayBase: number = ~~(workTime / this._dayLength) * this._dayLength;
|
||||
const dayPosition: number = workTime - dayBase;
|
||||
|
||||
return dayPosition >= this._validStart && dayPosition < this._validEnd - 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate short term parking costs
|
||||
*/
|
||||
private _calcShortTerm(): number {
|
||||
const startSeconds: number = this._startDT.getTime() / 1000;
|
||||
const endSeconds: number = this._endDT.getTime() / 1000;
|
||||
let workTime: number;
|
||||
|
||||
let validHours = 0;
|
||||
let startHourPart = 0;
|
||||
|
||||
// Calculate Start Hour
|
||||
const startBaseHour: number = ~~(startSeconds / this._hourLength) * this._hourLength;
|
||||
|
||||
// Calculate End Hour
|
||||
const endBaseHour: number = ~~(endSeconds / this._hourLength) * this._hourLength;
|
||||
|
||||
// Check if the very first portion of the hour is valid
|
||||
if (this._isValidTime(startSeconds)) {
|
||||
startHourPart = this._hourLength - (startSeconds - startBaseHour);
|
||||
}
|
||||
|
||||
// Go to the next hour after the initial start
|
||||
workTime = startBaseHour + this._hourLength;
|
||||
|
||||
// If there's more of an hours worth of time then loop through the next hours
|
||||
if (endBaseHour - workTime > this._hourLength) {
|
||||
do {
|
||||
validHours = validHours + (this._isValidTime(workTime) ? 1 : 0);
|
||||
workTime = workTime + this._hourLength;
|
||||
} while (workTime <= endBaseHour);
|
||||
}
|
||||
|
||||
// Sum it all
|
||||
return startHourPart * this._secondPrice + validHours * this._shortPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate long term parking costs
|
||||
* @returns {number}
|
||||
* @private
|
||||
*/
|
||||
private _calcLongTerm(): number {
|
||||
// convert to time stamps and make them second based
|
||||
const startSeconds: number = this._startDT.getTime() / 1000;
|
||||
const endSeconds: number = this._endDT.getTime() / 1000;
|
||||
|
||||
// Very start of the first day
|
||||
const startBaseSeconds: number = ~~(startSeconds / this._dayLength) * this._dayLength;
|
||||
|
||||
// Very end of the second day
|
||||
const endBaseSeconds: number = ~~(endSeconds / this._dayLength) * this._dayLength + this._dayLength;
|
||||
|
||||
// Subtract the start seconds from the end seconds
|
||||
const distance: number = endBaseSeconds - startBaseSeconds;
|
||||
|
||||
// divide them by number of seconds in a day and multiply by cost
|
||||
|
||||
return (distance / this._dayLength) * this._longPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* The public calculate method
|
||||
* @param start
|
||||
* @param end
|
||||
* @param mode
|
||||
* @returns {number}
|
||||
*/
|
||||
calculate(start: string, end: string, mode: string = 'longterm'): number {
|
||||
let workVal = 0.0;
|
||||
this._startDT = parse(start, 'DD/MM/YYYY HH:mm:ssZ');
|
||||
this._endDT = parse(end, 'DD/MM/YYYY HH:mm:ssZ');
|
||||
|
||||
switch (mode.toLowerCase()) {
|
||||
case 'short':
|
||||
case 'shortterm':
|
||||
workVal = this._calcShortTerm();
|
||||
break;
|
||||
|
||||
case 'long':
|
||||
case 'longterm':
|
||||
workVal = this._calcLongTerm();
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
return parseFloat(workVal.toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
export default Carpark;
|
Loading…
Reference in New Issue
Block a user