Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SRoC Supplementary Billing - Determine Abstraction Period #97

Merged
merged 18 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,22 @@
* - 1 Jan 2022 to 30 Jun 2022
* - 1 Jan 2023 to 30 Jun 2023
*
* This is why we always return 2 abstraction periods for each charge purpose. For each period, we calculate the
* 'billable days'. This is how much of the period intersects with the billing period. Finally, we add a 'consider'
* flag. This is a boolean which identifies whether a period intersects the billing period. For example, if the
* abstraction period was 1 Jan to 31 Mar, only one of the periods we create would intersect with a billing period of
* 2022-04-01 to 2023-03-31
*
* - 1 Jan 2022 to 31 Mar 2022 - `false`
* - 1 Jan 2023 to 31 Mar 2023 - `true`
* This is why we always calculate 2 abstraction periods for each charge purpose which we then subsequently check and
* disgard if they fall outside the billing period. For each valid period we calculate the 'billing period', from
* which we calculate the 'billable days'. This is how much of the period intersects with the billing period.
*
* @param {Object} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period
* @param {module:ChargePurposeModel} chargePurpose The abstraction period to be checked
*
* @returns {Object[]} An array of abstraction periods
* @returns {Date} periods[].startDate
* @returns {Date} periods[].endDate
* @returns {boolean} periods[].consider
* @returns {number} periods[].billableDays
*/
function go (billingPeriod, chargePurpose) {
const abstractionPeriods = _abstractionPeriods(billingPeriod, chargePurpose)

_flagPeriodsForConsideration(billingPeriod, abstractionPeriods)

_calculateBillableDays(abstractionPeriods)
for (const abstractionPeriod of abstractionPeriods) {
_calculateBillablePeriods(abstractionPeriod, billingPeriod)
Jozzey marked this conversation as resolved.
Show resolved Hide resolved
_calculateBillableDays(abstractionPeriod)
}

return abstractionPeriods
}
Expand Down Expand Up @@ -92,12 +84,13 @@ function go (billingPeriod, chargePurpose) {
* We also handle the edge case of the months being equal. If this is the case we still treat the abstraction period as
* in-year and out-year, only we use the days in the comparison instead of the months.
*
* The date ranges that are created are then checked to see if they fall within the billing period and added to the
* `abstractionPeriods` array if valid.
*
* @param {Object} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period
* @param {module:ChargePurposeModel} chargePurpose The abstraction period to be checked
*
* @returns {Object[]} An array of abstraction periods
* @returns {Date} periods[].startDate
* @returns {Date} periods[].endDate
*/
function _abstractionPeriods (billingPeriod, chargePurpose) {
const billingPeriodStartYear = billingPeriod.startDate.getFullYear()
Expand Down Expand Up @@ -133,56 +126,86 @@ function _abstractionPeriods (billingPeriod, chargePurpose) {
endDate: _subtractOneYear(firstPeriod.endDate)
}

return [previousPeriod, firstPeriod]
const abstractionPeriods = []
if (_isPeriodValid(previousPeriod, billingPeriod)) {
abstractionPeriods.push(previousPeriod)
}

if (_isPeriodValid(firstPeriod, billingPeriod)) {
abstractionPeriods.push(firstPeriod)
}

return abstractionPeriods
}

/**
* Calculates the 'billable days' for each abstraction billing period
* Calculates the 'billable days' for a billable abstraction period
*
* @param {Object[]} abstractionPeriods An array of abstraction billing periods
* @param {Object} abstractionPeriod An abstraction billing period
*
* @returns {Object[]} The array abstraction periods each with a new `billableDays` property
* @returns {Date} periods[].startDate
* @returns {Date} periods[].endDate
* @returns {boolean} periods[].consider
* @returns {number} periods[].billableDays
* @returns {Object} The abstraction period with a new `billableDays` property
Jozzey marked this conversation as resolved.
Show resolved Hide resolved
*/
function _calculateBillableDays (abstractionPeriods) {
let difference
let billableDays
for (const abstractionPeriod of abstractionPeriods) {
difference = abstractionPeriod.endDate.getTime() - abstractionPeriod.startDate.getTime() // difference in msecs
billableDays = Math.ceil(difference / (1000 * 3600 * 24)) + 1 // (1000 msecs * (60 secs * 60 mins) * 24 hrs)
function _calculateBillableDays (abstractionPeriod) {
const DAY_IN_MILLISECONDS = (24 * 60 * 60 * 1000) // (24 hrs * 60 mins * 60 secs * 1000 msecs)
if (abstractionPeriod.billableStartDate) {
const difference = abstractionPeriod.billableEndDate.getTime() - abstractionPeriod.billableStartDate.getTime() // difference in msecs
const billableDays = Math.ceil(difference / DAY_IN_MILLISECONDS) + 1
abstractionPeriod.billableDays = billableDays
}
}

/**
* Adds the `consider` flag to each abstraction billing period as to whether it should be included in billing
* Calculates the 'billable period' for an abstraction billing period
*
* @param {Object} abstractionPeriod An abstraction billing period
* @param {Object} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period
*
* @returns {Object} The abstraction period with new `billableStartDate` & `billableEndDate` properties
Jozzey marked this conversation as resolved.
Show resolved Hide resolved
*/
function _calculateBillablePeriods (abstractionPeriod, billingPeriod) {
Jozzey marked this conversation as resolved.
Show resolved Hide resolved
let billableStartDate
let billableEndDate

if (abstractionPeriod.startDate < billingPeriod.startDate) {
billableStartDate = billingPeriod.startDate
} else {
billableStartDate = abstractionPeriod.startDate
}

if (abstractionPeriod.endDate > billingPeriod.endDate) {
billableEndDate = billingPeriod.endDate
} else {
billableEndDate = abstractionPeriod.endDate
}

if (billableStartDate <= billableEndDate) {
abstractionPeriod.billableStartDate = billableStartDate
abstractionPeriod.billableEndDate = billableEndDate
}
}

/**
* Checks each abstraction billing period to see whether it should be included in billing
*
* The flag is determined by calculating whether the abstraction period intersects with the billing period. For example,
* This is determined by calculating whether the abstraction period intersects with the billing period. For example,
* if the billing period is 2022-04-01 to 2023-03-31 and the abstraction period was 01-Nov to 31-Mar:
*
* - 01-Nov-2022 to 31-Mar-2023 = `true`
* - 01-Nov-2021 to 31-Mar-2022 = `false`
*
* @param {Object} abstractionPeriod Object that has a `startDate` and `endDate` that defines the abstraction period
* @param {Object} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period
* @param {Object[]} abstractionPeriods An array of abstraction billing periods
*
* @returns {Object[]} The array abstraction periods each with a new `consider` property
* @returns {Date} periods[].startDate
* @returns {Date} periods[].endDate
* @returns {Boolean} True if the `abstractionPeriod` intersects the `billingPeriod`
* c
*/
function _flagPeriodsForConsideration (billingPeriod, abstractionPeriods) {
for (const abstractionPeriod of abstractionPeriods) {
if (abstractionPeriod.startDate > billingPeriod.endDate) {
abstractionPeriod.consider = false
} else if (abstractionPeriod.endDate < billingPeriod.startDate) {
abstractionPeriod.consider = false
} else {
abstractionPeriod.consider = true
}
function _isPeriodValid (abstractionPeriod, billingPeriod) {
if (abstractionPeriod.startDate > billingPeriod.endDate) {
return false
} else if (abstractionPeriod.endDate < billingPeriod.startDate) {
return false
} else {
return true
}
}

Expand Down
Loading