Skip to content

Commit

Permalink
Create SROC two-part tariff flagging endpoint for new charge versions (
Browse files Browse the repository at this point in the history
…#1239)

https://eaflood.atlassian.net/browse/WATER-4622
https://eaflood.atlassian.net/browse/WATER-4588

This is a part of the work for two-part tariff supplementary billing. A licence can be added to a two-part tariff supplementary bill run in 5 ways. Editing a return, adding a historic charge version, removing a licence from the annual two-part tariff bill run, recalculating a bill and if a licence is lapsed or revoked.
Out of these 5 ways, 4 of them are in the legacy code base. To keep the new code for the supplementary billing within our system code base, we have decided to create a new endpoint that the legacy code can hit to calculate if the changed licence needs to be added to a supplementary bill run. This PR sets up the endpoint and flags a licence in need of a supplementary bill run when a historic charge version is added.
  • Loading branch information
Beckyrose200 authored Aug 19, 2024
1 parent a8a22c3 commit 5a8d0b7
Show file tree
Hide file tree
Showing 11 changed files with 730 additions and 0 deletions.
8 changes: 8 additions & 0 deletions app/controllers/licences.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* @module LicencesController
*/

const LicenceSupplementaryProcessBillingFlagService = require('../services/licences/supplementary/process-billing-flag.service.js')
const InitiateSessionService = require('../services/return-requirements/initiate-session.service.js')
const ViewLicenceBillsService = require('../services/licences/view-licence-bills.service.js')
const ViewLicenceCommunicationsService = require('../services/licences/view-licence-communications.service.js')
Expand Down Expand Up @@ -91,9 +92,16 @@ async function viewReturns (request, h) {
})
}

async function supplementary (request, h) {
LicenceSupplementaryProcessBillingFlagService.go(request.payload)

return h.response().code(204)
}

module.exports = {
noReturnsRequired,
returnsRequired,
supplementary,
viewBills,
viewCommunications,
viewContacts,
Expand Down
14 changes: 14 additions & 0 deletions app/routes/licence.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ const routes = [
}
}
}
},
{
method: 'POST',
path: '/licences/supplementary',
options: {
handler: LicencesController.supplementary,
app: {
plainOutput: true
},
auth: false,
plugins: {
crumb: false
}
}
}
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict'

/**
* Determines which financial year ends are between the date ranges
* @module DetermineBillingYearsService
*/

const APRIL = 3
const LAST_PRE_SROC_FINANCIAL_YEAR_END = 2022

/**
* Determines the financial years impacted by changes between the start date and end dates, considering only the
* financial year ends that are relevant for SROC supplementary billing.
*
* It determines the financial year ends for the given `startDate` and `endDate`, and returns
* an array of years that are greater than the last pre-SROC financial year end.
*
* @param {Date} startDate - The start date from which to begin calculating financial years.
* @param {Date} endDate - The end date up to which to calculate financial years. If not provided,
* the current date will be used.
*
* @returns {Object[]} - The financial year end that are impacted by the changes between the start and end dates and are
* relevant for SROC.
*/
function go (startDate, endDate) {
const years = []

const startYear = _adjustedFinancialYearEnd(startDate)
// As some changes don't have an end date we need to take this into consideration
const endYear = _adjustedFinancialYearEnd(endDate || new Date())

for (let year = startYear; year <= endYear; year++) {
// SROC supplementary billing started in the financial year 2022/2023. Anything before this year is not considered
// to be SROC
if (year > LAST_PRE_SROC_FINANCIAL_YEAR_END) {
years.push(year)
}
}

return years
}

/**
* When flagging a licence for the supplementary bill run, we need to consider which financial years have been
* impacted by the change. We only care about the financial year ends. So if the startDate for a new chargeVersion is
* `2022-05-31`, the financial year end is considered to be `2023` since the financial years run April to March. Same
* goes for if a charge versions endDate is `2023-03-05`, the financial year end is `2023`.
*/
function _adjustedFinancialYearEnd (date) {
let year = date.getFullYear()

if (date.getMonth() >= APRIL) {
year++
}

return year
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict'

/**
* Determines if a licence with a change in charge version should be flagged for supplementary billing
* @module DetermineChargeVersionYearsService
*/

const ChargeVersionModel = require('../../../models/charge-version.model.js')

/**
* Determines if a licence with a change in charge version should be flagged for supplementary billing.
*
* The service is passed the id of a new charge version and determines if it should be flagged for supplementary
* billing. This is worked out based on the charge versions scheme and if any related charge reference has a two-part
* tariff indicator. If they do, then flagForBilling is set to true.
*
* @param {String} chargeVersionId - The UUID for the charge version to fetch
*
* @returns {Object} - An object containing the related licence, charge version start and end date and if the licence
* should be flagged for two-part tariff supplementary billing
*/
async function go (chargeVersionId) {
const { chargeReferences, licence, endDate, startDate, scheme } = await _fetchChargeVersion(chargeVersionId)
const result = {
licence,
startDate,
endDate,
twoPartTariff: false,
flagForBilling: false
}

if (scheme === 'alcs') {
return result
}

result.twoPartTariff = _twoPartTariffIndicators(chargeReferences)

// When we can support non two-part tariff billing flags we can remove this line
result.flagForBilling = result.twoPartTariff

return result
}

async function _fetchChargeVersion (chargeVersionId) {
return ChargeVersionModel.query()
.findById(chargeVersionId)
.select([
'id',
'scheme',
'startDate',
'endDate'])
.withGraphFetched('chargeReferences')
.modifyGraph('chargeReferences', (builder) => {
builder.select([
'id',
'adjustments'
])
})
.withGraphFetched('licence')
.modifyGraph('licence', (builder) => {
builder.select([
'id',
'regionId'
])
})
}

function _twoPartTariffIndicators (chargeReferences) {
return chargeReferences.some((chargeReference) => {
return chargeReference.adjustments?.s127
})
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict'

/**
* Determines from the years provided which ones have an annual or two-part tariff bill run created
* @module DetermineExistingBillRunYearsService
*/

const BillRunModel = require('../../../models/bill-run.model.js')

/**
* Determines from the years provided which ones have an annual or two-part tariff bill run created
*
* This service is responsible for determining the years an annual or two part tariff bill run has been created for.
* This allows those years to be flagged on the licence for supplementary billing.
*
* The service has been passed an array of years that the change on the licence covers. It then verify whether an annual
* or two-part tariff bill run has already been sent for those years. If it has then the year is returned. We do not
* want to flag any years on the licence that hasn't had a bill run already created, as the change on the licence will
* get picked up when the annual/ two-part tariff bill run is created for that year.
*
* @param {String} regionId - The UUID of the region to search for
* @param {Object[]} years - The years that the licence can be flagged for
* @param {Boolean} twoPartTariff - If there are two-part tariff indicators on the licence
*
* @returns {Object[]} - The years that can be flagged for supplementary billing
*/
async function go (regionId, years, twoPartTariff) {
return _supplementaryBillingYears(regionId, years, twoPartTariff)
}

/**
* We need to verify which years annual two-part tariff bill runs have been sent. A year shouldn't be flagged for a
* supplementary bill run if the annual bill run hasn't been sent yet, as any licence changes will be handled in the
* annual run.
*/
async function _supplementaryBillingYears (regionId, years, twoPartTariff) {
const batchType = twoPartTariff ? 'two_part_tariff' : 'annual'

const billRuns = await BillRunModel.query()
.distinct('toFinancialYearEnding')
.where('regionId', regionId)
.where('batchType', batchType)
.whereIn('toFinancialYearEnding', years)

return billRuns.map((billRun) => {
return billRun.toFinancialYearEnding
})
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use strict'

/**
* Orchestrates flagging a licence for supplementary billing
* @module ProcessBillingFlagService
*/

const CreateLicenceSupplementaryYearService = require('./create-licence-supplementary-year.service.js')
const DetermineBillingYearsService = require('./determine-billing-years.service.js')
const DetermineExistingBillRunYearsService = require('./determine-existing-bill-run-years.service.js')
const DetermineChargeVersionYearsService = require('./determine-charge-version-years.service.js')
const { calculateAndLogTimeTaken, currentTimeInNanoseconds } = require('../../../lib/general.lib.js')

/**
* Orchestrates flagging a licence for supplementary billing
*
* This service orchestrates the process of flagging a licence for supplementary billing.
* It retrieves details of the charge version, including the licence information, start and end dates, whether the
* charge version has two-part tariff indicators, and if it should be flagged for supplementary billing.
*
* If the licence qualifies for flagging, the relevant dates are passed to the `DetermineBillingYearsService`, which
* calculates the years affected by the changes to the licence.
*
* If any SROC years are affected, they are passed to the `DetermineExistingBillRunYearsService`. This service checks
* the affected years to see if they have had an annual or two-part tariff bill runs created. We avoid flagging any
* years that haven't had an annual or two-part tariff bill run, as those changes will be captured when the bill run is
* created.
*
* Finally, we call the `CreateLicenceSupplementaryYearService`, which persists our final list of years along with the
* licence ID and whether two-part tariff is true.
*
* @param {Object} payload - The payload from the request
*/
async function go (payload) {
try {
const startTime = currentTimeInNanoseconds()

let result

if (payload.chargeVersionId) {
result = await DetermineChargeVersionYearsService.go(payload.chargeVersionId)
} else {
return
}

const { licence, startDate, endDate, twoPartTariff, flagForBilling } = result

if (!flagForBilling) {
return
}

const years = DetermineBillingYearsService.go(startDate, endDate)

if (!years) {
return
}

const financialYearEnds = await DetermineExistingBillRunYearsService.go(licence.regionId, years, twoPartTariff)

if (financialYearEnds.length === 0) {
return
}

await CreateLicenceSupplementaryYearService.go(licence.id, financialYearEnds, twoPartTariff)

calculateAndLogTimeTaken(startTime, 'Supplementary Billing Flag complete', { licenceId: licence.id })
} catch (error) {
global.GlobalNotifier.omfg('Supplementary Billing Flag failed', payload, error)
}
}

module.exports = {
go
}
19 changes: 19 additions & 0 deletions test/controllers/licences.controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Boom = require('@hapi/boom')

// Things we need to stub
const InitiateSessionService = require('../../app/services/return-requirements/initiate-session.service.js')
const LicenceSupplementaryProcessBillingFlagService = require('../../app/services/licences/supplementary/process-billing-flag.service.js')
const ViewLicenceBillsService = require('../../app/services/licences/view-licence-bills.service.js')
const ViewLicenceCommunicationsService = require('../../app/services/licences/view-licence-communications.service.js')
const ViewLicenceContactDetailsService = require('../../app/services/licences/view-licence-contact-details.service.js')
Expand Down Expand Up @@ -437,6 +438,24 @@ describe('Licences controller', () => {
})
})
})

describe('POST /licences/supplementary', () => {
beforeEach(() => {
options = { method: 'POST', url: '/licences/supplementary' }
})

describe('when the request succeeds', () => {
beforeEach(async () => {
Sinon.stub(LicenceSupplementaryProcessBillingFlagService, 'go').resolves()
})

it('returns a 204 response', async () => {
const response = await server.inject(options)

expect(response.statusCode).to.equal(204)
})
})
})
})

function _viewLicenceBills () {
Expand Down
Loading

0 comments on commit 5a8d0b7

Please sign in to comment.