Skip to content

Commit

Permalink
Adding a periods overlap helper (#548)
Browse files Browse the repository at this point in the history
https://eaflood.atlassian.net/browse/WATER-4188

This PR is focused on adding a helper method for the two-part-tariff work. The helper method is used to determine if two dates it has been given overlap or not.
  • Loading branch information
Beckyrose200 authored Nov 27, 2023
1 parent 9e83895 commit 719ec12
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
48 changes: 48 additions & 0 deletions app/lib/general.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,53 @@ function generateUUID () {
return randomUUID({ disableEntropyCache: true })
}

/**
* Tests if one set of periods (represented by a start and end date) overlaps with another
*
* Added as part of two-part tariff and the need to match returns and lines to charge elements. A common complication in
* WRLS is the need to convert an abstract period, for example '1 Nov to 31 Mar' to a concrete period (2023-11-01 to
* 2024-03-31). It gets even more complex when the period crosses over another, for example the start or end of a
* billing period. Then the only way to represent the abstract period in a usable way is as 2 separate periods. Hence
* this service deals with arrays of periods.
*
* > See the comments for `DetermineAbstractionPeriodService` to better understand the complexity of going from
* > abstract to concrete periods
*
* Then there are times we need to test if the periods of one thing overlap with another. In two-part tariff that's the
* abstraction periods of a charge element with those of a return. If _any_ of the periods overlap then the return is
* 'matched' and can be allocated to the charge element.
*
* This method iterates through the `referencePeriods`. It then filters the `checkPeriods` by testing if any of them
* overlap with the `referencePeriod`. If any do `checkPeriods.filter()` will return a non-empty array at which point
* `periodsOverlap()` will return `true`.
*
* Else, having compared all the `checkPeriods` against each `referencePeriod` and finding no overlaps the function will
* return false.
*
* @param {Object[]} referencePeriods Each period is an object containing a `startDate` and `endDate` property
* @param {Object[]} checkPeriods Each period is an object containing a `startDate` and `endDate` property. These
* periods will be checked against the `referencePeriods for any overlaps
*
* @returns {boolean} Returns true if there _any_ check period overlaps with a reference period, else false
*/
function periodsOverlap (referencePeriods, checkPeriods) {
for (const referencePeriod of referencePeriods) {
const overLappingPeriods = checkPeriods.filter((checkPeriod) => {
if (checkPeriod.startDate > referencePeriod.endDate || referencePeriod.startDate > checkPeriod.endDate) {
return false
}

return true
})

if (overLappingPeriods.length) {
return true
}
}

return false
}

/**
* Returns the current date and time as an ISO string
*
Expand All @@ -44,5 +91,6 @@ function timestampForPostgres () {

module.exports = {
generateUUID,
periodsOverlap,
timestampForPostgres
}
125 changes: 125 additions & 0 deletions test/lib/general.lib.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,129 @@ describe('RequestLib', () => {
expect(result).to.equal('2015-10-21T20:31:57.000Z')
})
})

describe('#periodsOverlap', () => {
let referencePeriod
let checkPeriod

describe('when given periods that do not overlap', () => {
beforeEach(() => {
referencePeriod = [{
startDate: new Date('2023-02-01'),
endDate: new Date('2023-02-02')
}]

checkPeriod = [{
startDate: new Date('2023-01-01'),
endDate: new Date('2023-01-31')
}]
})

it('returns false', () => {
const result = GeneralLib.periodsOverlap(referencePeriod, checkPeriod)

expect(result).to.equal(false)
})
})

describe('when a check period overlaps the start of a reference period', () => {
beforeEach(() => {
referencePeriod = [{
startDate: new Date('2023-02-01'),
endDate: new Date('2023-02-28')
}]

checkPeriod = [{
startDate: new Date('2023-01-15'),
endDate: new Date('2023-02-15')
}]
})

it('returns true', () => {
const result = GeneralLib.periodsOverlap(referencePeriod, checkPeriod)

expect(result).to.equal(true)
})
})

describe('when a check period overlaps the end of a reference period', () => {
beforeEach(() => {
referencePeriod = [{
startDate: new Date('2023-01-01'),
endDate: new Date('2023-01-31')
}]

checkPeriod = [{
startDate: new Date('2023-01-15'),
endDate: new Date('2023-02-15')
}]
})

it('returns true', () => {
const result = GeneralLib.periodsOverlap(referencePeriod, checkPeriod)

expect(result).to.equal(true)
})
})

describe('when a reference period is completely inside a check period', () => {
beforeEach(() => {
referencePeriod = [{
startDate: new Date('2023-02-01'),
endDate: new Date('2023-02-15')
}]

checkPeriod = [{
startDate: new Date('2023-01-01'),
endDate: new Date('2023-02-28')
}]
})

it('returns true', () => {
const result = GeneralLib.periodsOverlap(referencePeriod, checkPeriod)

expect(result).to.equal(true)
})
})

describe('when a check period is completely inside a reference period', () => {
beforeEach(() => {
referencePeriod = [{
startDate: new Date('2023-01-01'),
endDate: new Date('2023-02-28')
}]

checkPeriod = [{
startDate: new Date('2023-02-01'),
endDate: new Date('2023-02-15')
}]
})

it('returns true', () => {
const result = GeneralLib.periodsOverlap(referencePeriod, checkPeriod)

expect(result).to.equal(true)
})
})

describe('when the periods are the same', () => {
beforeEach(() => {
referencePeriod = [{
startDate: new Date('2023-02-01'),
endDate: new Date('2023-02-28')
}]

checkPeriod = [{
startDate: new Date('2023-02-01'),
endDate: new Date('2023-02-28')
}]
})

it('returns true', () => {
const result = GeneralLib.periodsOverlap(referencePeriod, checkPeriod)

expect(result).to.equal(true)
})
})
})
})

0 comments on commit 719ec12

Please sign in to comment.