From 8956c01a61d396d0a12f355d47665e4d228ac16f Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 26 Feb 2025 13:29:03 +0000 Subject: [PATCH] WIP --- app/controllers/root.controller.js | 19 ++++- .../determine-billing-periods.service.js | 2 +- .../match/fetch-charge-versions.service.js | 19 ++++- .../bill-runs/match/fetch-licences.service.js | 4 +- .../match/match-and-allocate.service.js | 3 +- .../bill-runs/setup/submit-check.service.js | 11 +-- .../start-bill-run-process.service.js | 7 +- .../process-bill-run.service.js | 71 +++++++++++++++++++ 8 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 app/services/bill-runs/tpt-supplementary/process-bill-run.service.js diff --git a/app/controllers/root.controller.js b/app/controllers/root.controller.js index c5b08d64ae..d73a76f2f2 100644 --- a/app/controllers/root.controller.js +++ b/app/controllers/root.controller.js @@ -5,8 +5,23 @@ * @module RootController */ -function index(_request, _h) { - return { status: 'alive' } +const FetchChargeVersionsService = require('../services/bill-runs/match/fetch-charge-versions.service.js') + +const StartBillRunProcessService = require('../services/bill-runs/start-bill-run-process.service.js') + +async function index(_request, h) { + const regionId = '4ccf3c5b-ab4e-48e1-afa8-3b18b5d07fab' + const batchType = 'two_part_supplementary' + const userEmail = 'test@wrsl.gov.uk' + const financialYearEnding = 2024 + // const billingPeriod = { startDate: new Date('2023-04-01'), endDate: new Date('2024-03-31') } + // const chargeVersions = await FetchChargeVersionsService.go(, billingPeriod, false) + + await StartBillRunProcessService.go(regionId, batchType, userEmail, financialYearEnding) + + return h.response().code(204) + + // return { status: 'alive' } } module.exports = { diff --git a/app/services/bill-runs/determine-billing-periods.service.js b/app/services/bill-runs/determine-billing-periods.service.js index 1ebc62768b..969e1969ae 100644 --- a/app/services/bill-runs/determine-billing-periods.service.js +++ b/app/services/bill-runs/determine-billing-periods.service.js @@ -50,7 +50,7 @@ function _billingPeriods(billRunType, financialYear) { const years = { startYear: financialYear.startDate.getFullYear(), endYear: financialYear.endDate.getFullYear() } // Annual and two-part-tariff bill runs will always be a single period - if (['annual', 'two_part_tariff'].includes(billRunType)) { + if (['annual', 'two_part_tariff', 'two_part_supplementary'].includes(billRunType)) { _addBillingPeriod(billingPeriods, years.startYear, years.endYear) return billingPeriods diff --git a/app/services/bill-runs/match/fetch-charge-versions.service.js b/app/services/bill-runs/match/fetch-charge-versions.service.js index b953dabe6b..0167434989 100644 --- a/app/services/bill-runs/match/fetch-charge-versions.service.js +++ b/app/services/bill-runs/match/fetch-charge-versions.service.js @@ -9,6 +9,7 @@ const { ref } = require('objection') const ChargeReferenceModel = require('../../../models/charge-reference.model.js') const ChargeVersionModel = require('../../../models/charge-version.model.js') +const LicenceSupplementaryYears = require('../../../models/licence-supplementary-year.model.js') const Workflow = require('../../../models/workflow.model.js') /** @@ -31,11 +32,11 @@ const Workflow = require('../../../models/workflow.model.js') * @returns {Promise} Contains an array of two-part tariff charge versions with linked licences, charge * references, charge elements and related purpose */ -async function go(regionId, billingPeriod) { - return _fetch(regionId, billingPeriod) +async function go(regionId, billingPeriod, supplementary = false) { + return _fetch(regionId, billingPeriod, supplementary) } -async function _fetch(regionId, billingPeriod) { +async function _fetch(regionId, billingPeriod, supplementary) { const chargeVersions = await ChargeVersionModel.query() .select(['chargeVersions.id', 'chargeVersions.startDate', 'chargeVersions.endDate', 'chargeVersions.status']) .innerJoinRelated('licence') @@ -70,6 +71,18 @@ async function _fetch(regionId, billingPeriod) { // rather than have to remember that quirk we stick with whereJsonPath() which works in all cases. .whereJsonPath('chargeReferences.adjustments', '$.s127', '=', true) ) + .where((builder) => { + if (supplementary) { + builder.whereExists( + LicenceSupplementaryYears.query() + .select(1) + .whereColumn('licenceSupplementaryYears.licenceId', 'chargeVersions.licenceId') + .whereColumn('licenceSupplementaryYears.financialYearEnd', billingPeriod.endDate.getFullYear()) + ) + } else { + builder.whereRaw('1=1') + } + }) .orderBy('chargeVersions.licenceRef', 'asc') .withGraphFetched('changeReason') .modifyGraph('changeReason', (builder) => { diff --git a/app/services/bill-runs/match/fetch-licences.service.js b/app/services/bill-runs/match/fetch-licences.service.js index 8fb21f6903..39b685ba8a 100644 --- a/app/services/bill-runs/match/fetch-licences.service.js +++ b/app/services/bill-runs/match/fetch-licences.service.js @@ -17,8 +17,8 @@ const FetchChargeVersionsService = require('./fetch-charge-versions.service.js') * @returns {Promise} the licences to be matched, each containing an array of charge versions applicable for * two-part tariff */ -async function go(regionId, billingPeriod) { - const chargeVersions = await FetchChargeVersionsService.go(regionId, billingPeriod) +async function go(regionId, billingPeriod, supplementary = false) { + const chargeVersions = await FetchChargeVersionsService.go(regionId, billingPeriod, supplementary) const uniqueLicenceIds = _extractUniqueLicenceIds(chargeVersions) diff --git a/app/services/bill-runs/match/match-and-allocate.service.js b/app/services/bill-runs/match/match-and-allocate.service.js index 8754a9ff2a..cb9b326cef 100644 --- a/app/services/bill-runs/match/match-and-allocate.service.js +++ b/app/services/bill-runs/match/match-and-allocate.service.js @@ -29,7 +29,8 @@ const PrepareReturnLogsService = require('./prepare-return-logs.service.js') * @returns {Promise} - True if there are any licences matched to returns, false otherwise */ async function go(billRun, billingPeriod) { - const licences = await FetchLicencesService.go(billRun.regionId, billingPeriod) + const supplementary = billRun.batchType === 'two_part_supplementary' + const licences = await FetchLicencesService.go(billRun.regionId, billingPeriod, supplementary) if (licences.length > 0) { await _process(licences, billingPeriod, billRun) diff --git a/app/services/bill-runs/setup/submit-check.service.js b/app/services/bill-runs/setup/submit-check.service.js index 3fe6412fdc..d82874e7fb 100644 --- a/app/services/bill-runs/setup/submit-check.service.js +++ b/app/services/bill-runs/setup/submit-check.service.js @@ -48,11 +48,12 @@ async function go(sessionId, auth) { // blocking bill run was found. This is just protection against malicious use, or more likely, someone has left the // page idle and another user has triggered a bill run that now blocks it. if (blockingResults.trigger !== engineTriggers.neither) { - // Temporary code to end the journey if the bill run type is two-part supplementary as processing this bill run type - // is not currently possible - if (session.type !== 'two_part_supplementary') { - await CreateService.go(session, blockingResults, auth.credentials.user) - } + // // Temporary code to end the journey if the bill run type is two-part supplementary as processing this bill run type + // // is not currently possible + // if (session.type !== 'two_part_supplementary') { + // await CreateService.go(session, blockingResults, auth.credentials.user) + // } + await CreateService.go(session, blockingResults, auth.credentials.user) return {} } diff --git a/app/services/bill-runs/start-bill-run-process.service.js b/app/services/bill-runs/start-bill-run-process.service.js index 0b677c8eaa..4c9e46ddfc 100644 --- a/app/services/bill-runs/start-bill-run-process.service.js +++ b/app/services/bill-runs/start-bill-run-process.service.js @@ -11,6 +11,7 @@ const InitiateBillRunService = require('./initiate-bill-run.service.js') const NoBillingPeriodsError = require('../../errors/no-billing-periods.error.js') const SupplementaryProcessBillRunService = require('./supplementary/process-bill-run.service.js') const TwoPartTariffProcessBillRunService = require('./two-part-tariff/process-bill-run.service.js') +const TwoPartTariffSupplementaryProcessBillRunService = require('./tpt-supplementary/process-bill-run.service.js') /** * Manages the creation of a new bill run @@ -19,8 +20,6 @@ const TwoPartTariffProcessBillRunService = require('./two-part-tariff/process-bi * @param {string} batchType - Type of bill run, for example, supplementary * @param {string} userEmail - Email address of the user who initiated the bill run * @param {number} financialYearEnding - The financial year end that will be used for the bill run - * - * @returns {Promise} Object that will be the JSON response returned to the client */ async function go(regionId, batchType, userEmail, financialYearEnding) { const billingPeriods = DetermineBillingPeriodsService.go(batchType, financialYearEnding) @@ -31,6 +30,7 @@ async function go(regionId, batchType, userEmail, financialYearEnding) { const financialYearEndings = _financialYearEndings(billingPeriods) const billRun = await InitiateBillRunService.go(financialYearEndings, regionId, batchType, userEmail) + console.log('🚀 ~ go ~ billRun:', billRun) _processBillRun(billRun, billingPeriods) } @@ -55,6 +55,9 @@ function _processBillRun(billRun, billingPeriods) { case 'two_part_tariff': TwoPartTariffProcessBillRunService.go(billRun, billingPeriods) break + case 'two_part_supplementary': + TwoPartTariffSupplementaryProcessBillRunService.go(billRun, billingPeriods) + break } } diff --git a/app/services/bill-runs/tpt-supplementary/process-bill-run.service.js b/app/services/bill-runs/tpt-supplementary/process-bill-run.service.js new file mode 100644 index 0000000000..4b08f73cfc --- /dev/null +++ b/app/services/bill-runs/tpt-supplementary/process-bill-run.service.js @@ -0,0 +1,71 @@ +'use strict' + +/** + * Process a two-part tariff supplementary bill run for the given billing period + * @module ProcessBillRunService + */ + +const BillRunModel = require('../../../models/bill-run.model.js') +const { calculateAndLogTimeTaken, currentTimeInNanoseconds } = require('../../../lib/general.lib.js') +const HandleErroredBillRunService = require('../handle-errored-bill-run.service.js') +const MatchAndAllocateService = require('../match/match-and-allocate.service.js') + +/** + * Process a two-part tariff supplementary bill run for the given billing period + * + * Matches and allocates licences to returns for a two-part tariff bill run + * + * The results of the matching process are then persisted to the database ready for the results to be reviewed. The bill + * run status is also updated to 'review'. + * + * In the unlikely event of no licences match to returns it will set the status to 'empty'. It will also handle updating + * the bill run if an error occurs during the process. + * + * @param {module:BillRunModel} billRun - The two-part tariff supplementary bill run being processed + * @param {object[]} billingPeriods - An array of billing periods each containing a `startDate` and `endDate`. For 2PT + * this will only ever contain a single period + */ +async function go(billRun, billingPeriods) { + const { id: billRunId } = billRun + // NOTE: billingPeriods come from `DetermineBillingPeriodsService` which always returns an array because it is used by + // all billing types. For two-part tariff we know it will only contain one because 2PT supplementary bill runs are + // only for a single financial year + const billingPeriod = billingPeriods[0] + + try { + const startTime = currentTimeInNanoseconds() + + await _updateStatus(billRunId, 'processing') + + // `populated` will be set to true if `MatchAndAllocateService` processes at least one licence + const populated = await MatchAndAllocateService.go(billRun, billingPeriod) + + await _setBillRunStatus(billRunId, populated) + + calculateAndLogTimeTaken(startTime, 'Process bill run complete', { billRunId, type: 'two_part_supplementary' }) + } catch (error) { + await HandleErroredBillRunService.go(billRunId) + global.GlobalNotifier.omfg('Process bill run failed', { billRun }, error) + } +} + +async function _setBillRunStatus(billRunId, populated) { + // It is highly unlikely no licences were matched to returns. So we default status to 'review' + let status = 'review' + + // Just in case no licences were found to be matched to returns we set the status to 'empty' + if (!populated) { + status = 'empty' + } + + // Update the bill run's status + await _updateStatus(billRunId, status) +} + +async function _updateStatus(billRunId, status) { + await BillRunModel.query().findById(billRunId).patch({ status }) +} + +module.exports = { + go +}