From 0ebc51e00ef8d4c261d689a4b652bc6e44d81cc1 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 09:03:26 +0100 Subject: [PATCH 001/147] Tidy up Two-part tariff review code and routes https://eaflood.atlassian.net/browse/WATER-4057 > To be updated From 0af33e2212ccdb0637cb115c4d98ca8c73d68c67 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 17:27:33 +0100 Subject: [PATCH 002/147] Move main review page to new `/bill-runs/route` --- .../bill-runs-review.controller.js | 34 +++++++++++++++++++ app/controllers/bill-runs.controller.js | 24 ------------- app/plugins/router.plugin.js | 2 ++ app/routes/bill-runs-review.routes.js | 32 +++++++++++++++++ app/routes/bill-runs.routes.js | 24 ------------- 5 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 app/controllers/bill-runs-review.controller.js create mode 100644 app/routes/bill-runs-review.routes.js diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js new file mode 100644 index 0000000000..ec8f71516d --- /dev/null +++ b/app/controllers/bill-runs-review.controller.js @@ -0,0 +1,34 @@ +'use strict' + +/** + * Controller for /bill-runs/review endpoints + * @module BillRunsReviewController + */ + +const ReviewBillRunService = require('../services/bill-runs/two-part-tariff/review-bill-run.service.js') +const SubmitReviewBillRunService = require('../services/bill-runs/two-part-tariff/submit-review-bill-run.service.js') + +async function review (request, h) { + const { id } = request.params + const { page } = request.query + + const pageData = await ReviewBillRunService.go(id, page, request.yar) + + return h.view('bill-runs/review.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + +async function submitReview (request, h) { + const { id } = request.params + + await SubmitReviewBillRunService.go(id, request.payload, request.yar) + + return h.redirect(`/system/bill-runs/${id}/review`) +} + +module.exports = { + review, + submitReview +} diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 9f62a49676..727d9d8e16 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -17,7 +17,6 @@ const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/ge const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js') const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') -const ReviewBillRunService = require('../services/bill-runs/two-part-tariff/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/two-part-tariff/review-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') const SubmitAmendedAdjustmentFactorService = require('../services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js') @@ -25,7 +24,6 @@ const SubmitAmendedAuthorisedVolumeService = require('../services/bill-runs/two- const SubmitAmendedBillableReturnsService = require('..//services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../services/bill-runs/submit-cancel-bill-run.service.js') const SubmitRemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') -const SubmitReviewBillRunService = require('../services/bill-runs/two-part-tariff/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') const SubmitSendBillRunService = require('../services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../services/bill-runs/view-bill-run.service.js') @@ -132,18 +130,6 @@ async function removeLicence (request, h) { }) } -async function review (request, h) { - const { id } = request.params - const { page } = request.query - - const pageData = await ReviewBillRunService.go(id, page, request.yar) - - return h.view('bill-runs/review.njk', { - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function reviewLicence (request, h) { const { id: billRunId, licenceId } = request.params @@ -246,14 +232,6 @@ async function submitRemoveLicence (request, h) { return h.redirect(`/system/bill-runs/${billRunId}/review`) } -async function submitReview (request, h) { - const { id } = request.params - - await SubmitReviewBillRunService.go(id, request.payload, request.yar) - - return h.redirect(`/system/bill-runs/${id}/review`) -} - async function submitReviewLicence (request, h) { const { id: billRunId, licenceId } = request.params @@ -313,14 +291,12 @@ module.exports = { matchDetails, previewCharge, removeLicence, - review, reviewLicence, send, submitAmendedAdjustmentFactor, submitAmendedAuthorisedVolume, submitAmendedBillableReturns, submitCancel, - submitReview, submitRemoveLicence, submitReviewLicence, submitSend, diff --git a/app/plugins/router.plugin.js b/app/plugins/router.plugin.js index 14cf4e1576..ce4a98cb7f 100644 --- a/app/plugins/router.plugin.js +++ b/app/plugins/router.plugin.js @@ -15,6 +15,7 @@ const AssetRoutes = require('../routes/assets.routes.js') const BillLicences = require('../routes/bill-licences.routes.js') const BillRoutes = require('../routes/bills.routes.js') const BillRunRoutes = require('../routes/bill-runs.routes.js') +const BillRunReviewRoutes = require('../routes/bill-runs-review.routes.js') const BillRunSetupRoutes = require('../routes/bill-runs-setup.routes.js') const BillingAccountRoutes = require('../routes/billing-accounts.routes.js') const CheckRoutes = require('../routes/check.routes.js') @@ -38,6 +39,7 @@ const routes = [ ...BillLicences, ...BillRoutes, ...BillRunRoutes, + ...BillRunReviewRoutes, ...BillRunSetupRoutes, ...BillingAccountRoutes, ...CheckRoutes, diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js new file mode 100644 index 0000000000..f04a04be93 --- /dev/null +++ b/app/routes/bill-runs-review.routes.js @@ -0,0 +1,32 @@ +'use strict' + +const BillRunsReviewController = require('../controllers/bill-runs-review.controller.js') + +const routes = [ + { + method: 'GET', + path: '/bill-runs/review/{id}', + options: { + handler: BillRunsReviewController.review, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/bill-runs/review/{id}', + options: { + handler: BillRunsReviewController.submitReview, + auth: { + access: { + scope: ['billing'] + } + } + } + } +] + +module.exports = routes diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index 598e9f7e9d..0abe35b484 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -78,30 +78,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review', - options: { - handler: BillRunsController.review, - auth: { - access: { - scope: ['billing'] - } - } - } - }, - { - method: 'POST', - path: '/bill-runs/{id}/review', - options: { - handler: BillRunsController.submitReview, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/review/{licenceId}', From ccade8ea739a0a60f64a0c6676447aef34dc1bbd Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 17:28:22 +0100 Subject: [PATCH 003/147] Update link to main review page from `/bill-runs` --- app/presenters/bill-runs/index-bill-runs.presenter.js | 2 +- test/presenters/bill-runs/index-bill-runs.presenter.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/presenters/bill-runs/index-bill-runs.presenter.js b/app/presenters/bill-runs/index-bill-runs.presenter.js index 2f1e503276..1dcd561ed2 100644 --- a/app/presenters/bill-runs/index-bill-runs.presenter.js +++ b/app/presenters/bill-runs/index-bill-runs.presenter.js @@ -68,7 +68,7 @@ function _link (billRunId, status, scheme) { return `/billing/batch/${billRunId}/two-part-tariff-review` } - return `/system/bill-runs/${billRunId}/review` + return `/system/bill-runs/review/${billRunId}` } return `/system/bill-runs/${billRunId}` diff --git a/test/presenters/bill-runs/index-bill-runs.presenter.test.js b/test/presenters/bill-runs/index-bill-runs.presenter.test.js index 0539c003ee..fef530e55c 100644 --- a/test/presenters/bill-runs/index-bill-runs.presenter.test.js +++ b/test/presenters/bill-runs/index-bill-runs.presenter.test.js @@ -142,7 +142,7 @@ describe('Index Bill Runs presenter', () => { it('generates the href needed to link to bill run review', () => { const results = IndexBillRunsPresenter.go(billRuns) - expect(results[0].link).to.equal('/system/bill-runs/31fec553-f2de-40cf-a8d7-a5fb65f5761b/review') + expect(results[0].link).to.equal('/system/bill-runs/review/31fec553-f2de-40cf-a8d7-a5fb65f5761b') expect(results[1].link).to.equal('/system/bill-runs/dfdde4c9-9a0e-440d-b297-7143903c6734') }) }) From 306ba61337e323aac5cbf7bca8565ea6fa1b36f3 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 18:23:10 +0100 Subject: [PATCH 004/147] Move the main review bill run modules into folder --- .../bill-runs-review.controller.js | 6 +- .../review-bill-run.presenter.js | 0 .../fetch-bill-run-licences.service.js | 0 .../review-bill-run.service.js | 4 +- .../submit-review-bill-run.service.js | 0 .../bill-runs-review.controller.test.js | 155 ++++++++++++++++++ test/controllers/bill-runs.controller.test.js | 102 ------------ .../review-bill-run.presenter.test.js | 2 +- .../fetch-bill-run-licences.service.test.js | 2 +- .../review-bill-run.service.test.js | 7 +- .../submit-review-bill-run.service.test.js | 4 +- 11 files changed, 168 insertions(+), 114 deletions(-) rename app/presenters/bill-runs/{two-part-tariff => review}/review-bill-run.presenter.js (100%) rename app/services/bill-runs/{two-part-tariff => review}/fetch-bill-run-licences.service.js (100%) rename app/services/bill-runs/{two-part-tariff => review}/review-bill-run.service.js (95%) rename app/services/bill-runs/{two-part-tariff => review}/submit-review-bill-run.service.js (100%) create mode 100644 test/controllers/bill-runs-review.controller.test.js rename test/presenters/bill-runs/{two-part-tariff => review}/review-bill-run.presenter.test.js (99%) rename test/services/bill-runs/{two-part-tariff => review}/fetch-bill-run-licences.service.test.js (99%) rename test/services/bill-runs/{two-part-tariff => review}/review-bill-run.service.test.js (98%) rename test/services/bill-runs/{two-part-tariff => review}/submit-review-bill-run.service.test.js (93%) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index ec8f71516d..ff887bd7f4 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -5,8 +5,8 @@ * @module BillRunsReviewController */ -const ReviewBillRunService = require('../services/bill-runs/two-part-tariff/review-bill-run.service.js') -const SubmitReviewBillRunService = require('../services/bill-runs/two-part-tariff/submit-review-bill-run.service.js') +const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') +const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') async function review (request, h) { const { id } = request.params @@ -25,7 +25,7 @@ async function submitReview (request, h) { await SubmitReviewBillRunService.go(id, request.payload, request.yar) - return h.redirect(`/system/bill-runs/${id}/review`) + return h.redirect(`/system/bill-runs/review/${id}`) } module.exports = { diff --git a/app/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.js b/app/presenters/bill-runs/review/review-bill-run.presenter.js similarity index 100% rename from app/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.js rename to app/presenters/bill-runs/review/review-bill-run.presenter.js diff --git a/app/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.js b/app/services/bill-runs/review/fetch-bill-run-licences.service.js similarity index 100% rename from app/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.js rename to app/services/bill-runs/review/fetch-bill-run-licences.service.js diff --git a/app/services/bill-runs/two-part-tariff/review-bill-run.service.js b/app/services/bill-runs/review/review-bill-run.service.js similarity index 95% rename from app/services/bill-runs/two-part-tariff/review-bill-run.service.js rename to app/services/bill-runs/review/review-bill-run.service.js index 6129e76173..6c518574e0 100644 --- a/app/services/bill-runs/two-part-tariff/review-bill-run.service.js +++ b/app/services/bill-runs/review/review-bill-run.service.js @@ -7,7 +7,7 @@ const FetchBillRunLicencesService = require('./fetch-bill-run-licences.service.js') const PaginatorPresenter = require('../../../presenters/paginator.presenter.js') -const ReviewBillRunPresenter = require('../../../presenters/bill-runs/two-part-tariff/review-bill-run.presenter.js') +const ReviewBillRunPresenter = require('../../../presenters/bill-runs/review/review-bill-run.presenter.js') /** * Orchestrates fetching and presenting the data needed for the review bill run page @@ -44,7 +44,7 @@ async function go (id, page, yar) { licences.results ) - const pagination = PaginatorPresenter.go(licences.total, selectedPageNumber, `/system/bill-runs/${id}/review`) + const pagination = PaginatorPresenter.go(licences.total, selectedPageNumber, `/system/bill-runs/review/${id}`) const pageTitle = _pageTitle(pagination.numberOfPages, selectedPageNumber) diff --git a/app/services/bill-runs/two-part-tariff/submit-review-bill-run.service.js b/app/services/bill-runs/review/submit-review-bill-run.service.js similarity index 100% rename from app/services/bill-runs/two-part-tariff/submit-review-bill-run.service.js rename to app/services/bill-runs/review/submit-review-bill-run.service.js diff --git a/test/controllers/bill-runs-review.controller.test.js b/test/controllers/bill-runs-review.controller.test.js new file mode 100644 index 0000000000..4aaec29d24 --- /dev/null +++ b/test/controllers/bill-runs-review.controller.test.js @@ -0,0 +1,155 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const { postRequestOptions } = require('../support/general.js') + +// Things we need to stub +const ReviewBillRunService = require('../../app/services/bill-runs/review/review-bill-run.service.js') +const SubmitReviewBillRunService = require('../../app/services/bill-runs/review/submit-review-bill-run.service.js') + +// For running our service +const { init } = require('../../app/server.js') + +describe('Bill Runs Review controller', () => { + let options + let server + + // Create server before each test + beforeEach(async () => { + server = await init() + + // We silence any calls to server.logger.error made in the plugin to try and keep the test output as clean as + // possible + Sinon.stub(server.logger, 'error') + + // We silence sending a notification to our Errbit instance using Airbrake + Sinon.stub(server.app.airbrake, 'notify').resolvesThis() + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('/bill-runs/{id}/review', () => { + describe('GET', () => { + let ReviewBillRunServiceStub + + describe('when a request is valid with no pagination', () => { + beforeEach(() => { + options = _getRequestOptions() + ReviewBillRunServiceStub = Sinon.stub(ReviewBillRunService, 'go').resolves(_reviewBillRunData()) + }) + + it('returns a 200 response', async () => { + const response = await server.inject(options) + const ReviewBillRunServiceArgs = ReviewBillRunServiceStub.args[0] + + expect(response.statusCode).to.equal(200) + expect(ReviewBillRunServiceArgs[0]).to.equal('97db1a27-8308-4aba-b463-8a6af2558b28') + expect(ReviewBillRunServiceArgs[1]).to.equal(undefined) + expect(response.payload).to.contain('two-part tariff') + expect(response.payload).to.contain('Southern (Test replica)') + expect(response.payload).to.contain('Showing all 2 licences') + }) + }) + + describe('when a request is valid with pagination', () => { + beforeEach(() => { + options = _getRequestOptions(null, 'page=2') + ReviewBillRunServiceStub = Sinon.stub(ReviewBillRunService, 'go').resolves(_reviewBillRunData()) + }) + + it('returns a 200 response', async () => { + const response = await server.inject(options) + const ReviewBillRunServiceArgs = ReviewBillRunServiceStub.args[0] + + expect(response.statusCode).to.equal(200) + expect(ReviewBillRunServiceArgs[0]).to.equal('97db1a27-8308-4aba-b463-8a6af2558b28') + expect(ReviewBillRunServiceArgs[1]).to.equal('2') + expect(response.payload).to.contain('two-part tariff') + expect(response.payload).to.contain('Southern (Test replica)') + expect(response.payload).to.contain('Showing all 2 licences') + }) + }) + }) + + describe('POST', () => { + beforeEach(async () => { + options = postRequestOptions('/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28') + }) + + describe('when a request is valid', () => { + beforeEach(() => { + Sinon.stub(SubmitReviewBillRunService, 'go').resolves() + }) + + it('redirects to the review licences page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal( + '/system/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28' + ) + }) + }) + }) + }) +}) + +function _getRequestOptions (path, query = null) { + const root = '/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28' + const rootPath = path ? `${root}/${path}` : root + const url = query ? `${rootPath}?${query}` : rootPath + + return { + method: 'GET', + url, + auth: { + strategy: 'session', + credentials: { scope: ['billing'] } + } + } +} + +function _reviewBillRunData () { + return { + region: 'Southern (Test replica)', + status: 'review', + dateCreated: '6 November 2023', + financialYear: '2021 to 2022', + billRunType: 'two-part tariff', + numberOfLicencesDisplayed: 2, + numberOfLicencesToReview: 1, + totalNumberOfLicences: 2, + preparedLicences: [ + { + licenceId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', + licenceRef: '1/11/11/*1/1111', + licenceHolder: 'Big Farm Ltd', + status: 'review', + issue: 'Multiple Issues' + }, + { + licenceId: '9442527a-64f3-471a-a3e4-fa0683a3d505', + licenceRef: '2/22/22/*2/2222', + licenceHolder: 'Small Farm Ltd', + status: 'ready', + issue: 'Multiple Issues' + } + ], + filter: { + issues: undefined, + licenceHolder: undefined, + licenceStatus: undefined, + openFilter: false + } + } +} diff --git a/test/controllers/bill-runs.controller.test.js b/test/controllers/bill-runs.controller.test.js index 83d0b38394..4d687e16b9 100644 --- a/test/controllers/bill-runs.controller.test.js +++ b/test/controllers/bill-runs.controller.test.js @@ -23,7 +23,6 @@ const GenerateBillRunService = require('../../app/services/bill-runs/two-part-ta const IndexBillRunsService = require('../../app/services/bill-runs/index-bill-runs.service.js') const MatchDetailsService = require('../../app/services/bill-runs/two-part-tariff/match-details.service.js') const RemoveBillRunLicenceService = require('../../app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') -const ReviewBillRunService = require('../../app/services/bill-runs/two-part-tariff/review-bill-run.service.js') const ReviewLicenceService = require('../../app/services/bill-runs/two-part-tariff/review-licence.service.js') const SendBillRunService = require('../../app/services/bill-runs/send-bill-run.service.js') const SubmitAmendedAdjustmentFactorService = require('../../app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js') @@ -31,7 +30,6 @@ const SubmitAmendedAuthorisedVolumeService = require('../../app/services/bill-ru const SubmitAmendedBillableReturnsService = require('../../app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../../app/services/bill-runs/submit-cancel-bill-run.service.js') const SubmitRemoveBillRunLicenceService = require('../../app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') -const SubmitReviewBillRunService = require('../../app/services/bill-runs/two-part-tariff/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../../app/services/bill-runs/two-part-tariff/submit-review-licence.service.js') const SubmitSendBillRunService = require('../../app/services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../../app/services/bill-runs/view-bill-run.service.js') @@ -289,71 +287,6 @@ describe('Bill Runs controller', () => { }) }) - describe('/bill-runs/{id}/review', () => { - describe('GET', () => { - let ReviewBillRunServiceStub - - describe('when a request is valid with no pagination', () => { - beforeEach(() => { - options = _getRequestOptions('review') - ReviewBillRunServiceStub = Sinon.stub(ReviewBillRunService, 'go').resolves(_reviewBillRunData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - const ReviewBillRunServiceArgs = ReviewBillRunServiceStub.args[0] - - expect(response.statusCode).to.equal(200) - expect(ReviewBillRunServiceArgs[0]).to.equal('97db1a27-8308-4aba-b463-8a6af2558b28') - expect(ReviewBillRunServiceArgs[1]).to.equal(undefined) - expect(response.payload).to.contain('two-part tariff') - expect(response.payload).to.contain('Southern (Test replica)') - expect(response.payload).to.contain('Showing all 2 licences') - }) - }) - - describe('when a request is valid with pagination', () => { - beforeEach(() => { - options = _getRequestOptions('review?page=2') - ReviewBillRunServiceStub = Sinon.stub(ReviewBillRunService, 'go').resolves(_reviewBillRunData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - const ReviewBillRunServiceArgs = ReviewBillRunServiceStub.args[0] - - expect(response.statusCode).to.equal(200) - expect(ReviewBillRunServiceArgs[0]).to.equal('97db1a27-8308-4aba-b463-8a6af2558b28') - expect(ReviewBillRunServiceArgs[1]).to.equal('2') - expect(response.payload).to.contain('two-part tariff') - expect(response.payload).to.contain('Southern (Test replica)') - expect(response.payload).to.contain('Showing all 2 licences') - }) - }) - }) - - describe('POST', () => { - beforeEach(async () => { - options = _postRequestOptions('review') - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(SubmitReviewBillRunService, 'go').resolves() - }) - - it('redirects to the review licences page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review' - ) - }) - }) - }) - }) - describe('/bill-runs/{id}/review/{licenceId}', () => { describe('GET', () => { beforeEach(async () => { @@ -1014,41 +947,6 @@ function _multiGroupBillRun () { } } -function _reviewBillRunData () { - return { - region: 'Southern (Test replica)', - status: 'review', - dateCreated: '6 November 2023', - financialYear: '2021 to 2022', - billRunType: 'two-part tariff', - numberOfLicencesDisplayed: 2, - numberOfLicencesToReview: 1, - totalNumberOfLicences: 2, - preparedLicences: [ - { - licenceId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - licenceRef: '1/11/11/*1/1111', - licenceHolder: 'Big Farm Ltd', - status: 'review', - issue: 'Multiple Issues' - }, - { - licenceId: '9442527a-64f3-471a-a3e4-fa0683a3d505', - licenceRef: '2/22/22/*2/2222', - licenceHolder: 'Small Farm Ltd', - status: 'ready', - issue: 'Multiple Issues' - } - ], - filter: { - issues: undefined, - licenceHolder: undefined, - licenceStatus: undefined, - openFilter: false - } - } -} - function _singleGroupBillRun () { return { billsCount: '1 Annual bill', diff --git a/test/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.test.js b/test/presenters/bill-runs/review/review-bill-run.presenter.test.js similarity index 99% rename from test/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.test.js rename to test/presenters/bill-runs/review/review-bill-run.presenter.test.js index 6e6cb34053..5112850f21 100644 --- a/test/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.test.js +++ b/test/presenters/bill-runs/review/review-bill-run.presenter.test.js @@ -8,7 +8,7 @@ const { beforeEach, describe, it } = exports.lab = Lab.script() const { expect } = Code // Thing under test -const ReviewBillRunPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.js') +const ReviewBillRunPresenter = require('../../../../app/presenters/bill-runs/review/review-bill-run.presenter.js') describe('Review Bill Run presenter', () => { describe('when there is data to be presented for review', () => { diff --git a/test/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.test.js b/test/services/bill-runs/review/fetch-bill-run-licences.service.test.js similarity index 99% rename from test/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.test.js rename to test/services/bill-runs/review/fetch-bill-run-licences.service.test.js index 60ae9ba9bc..5f15250f09 100644 --- a/test/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.test.js +++ b/test/services/bill-runs/review/fetch-bill-run-licences.service.test.js @@ -15,7 +15,7 @@ const RegionHelper = require('../../../support/helpers/region.helper.js') const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') // Thing under test -const FetchBillRunLicencesService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.js') +const FetchBillRunLicencesService = require('../../../../app/services/bill-runs/review/fetch-bill-run-licences.service.js') describe('Fetch Bill Run Licences service', () => { let filterIssues diff --git a/test/services/bill-runs/two-part-tariff/review-bill-run.service.test.js b/test/services/bill-runs/review/review-bill-run.service.test.js similarity index 98% rename from test/services/bill-runs/two-part-tariff/review-bill-run.service.test.js rename to test/services/bill-runs/review/review-bill-run.service.test.js index bf9cc73f20..79eb6db7ea 100644 --- a/test/services/bill-runs/two-part-tariff/review-bill-run.service.test.js +++ b/test/services/bill-runs/review/review-bill-run.service.test.js @@ -12,11 +12,12 @@ const { expect } = Code const DatabaseConfig = require('../../../../config/database.config.js') // Things we need to stub -const FetchBillRunLicencesService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-bill-run-licences.service.js') -const ReviewBillRunPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/review-bill-run.presenter.js') +const FetchBillRunLicencesService = require('../../../../app/services/bill-runs/review/fetch-bill-run-licences.service.js') +// TODO: Stop stubbing the presenter +const ReviewBillRunPresenter = require('../../../../app/presenters/bill-runs/review/review-bill-run.presenter.js') // Thing under test -const ReviewBillRunService = require('../../../../app/services/bill-runs/two-part-tariff/review-bill-run.service.js') +const ReviewBillRunService = require('../../../../app/services/bill-runs/review/review-bill-run.service.js') describe('Review Bill Run Service', () => { const billRunId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' diff --git a/test/services/bill-runs/two-part-tariff/submit-review-bill-run.service.test.js b/test/services/bill-runs/review/submit-review-bill-run.service.test.js similarity index 93% rename from test/services/bill-runs/two-part-tariff/submit-review-bill-run.service.test.js rename to test/services/bill-runs/review/submit-review-bill-run.service.test.js index bfa64cd4ea..a3db99dad9 100644 --- a/test/services/bill-runs/two-part-tariff/submit-review-bill-run.service.test.js +++ b/test/services/bill-runs/review/submit-review-bill-run.service.test.js @@ -9,9 +9,9 @@ const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() const { expect } = Code // Thing under test -const SubmitReviewBillRunService = require('../../../../app/services/bill-runs/two-part-tariff/submit-review-bill-run.service.js') +const SubmitReviewBillRunService = require('../../../../app/services/bill-runs/review/submit-review-bill-run.service.js') -describe('Submit Review Bill Run Service', () => { +describe.only('Submit Review Bill Run Service', () => { const billRunId = '27dad88a-6b3c-438b-a25f-f1483e7e12a0' let yarStub From b9e9075f5bb6cfce57ffbd9cf42c56f77e902374 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 18:35:58 +0100 Subject: [PATCH 005/147] Move the main review page into review folder --- app/views/bill-runs/{ => review}/review.njk | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/views/bill-runs/{ => review}/review.njk (100%) diff --git a/app/views/bill-runs/review.njk b/app/views/bill-runs/review/review.njk similarity index 100% rename from app/views/bill-runs/review.njk rename to app/views/bill-runs/review/review.njk From 7a6aff8e1a421f5b10303392363cb4dd2f9befc6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 18:36:57 +0100 Subject: [PATCH 006/147] Update cancel links to use new route --- app/controllers/bill-runs-review.controller.js | 2 +- app/presenters/bill-runs/cancel-bill-run.presenter.js | 2 +- app/views/bill-runs/review/review.njk | 2 +- test/presenters/bill-runs/cancel-bill-run.presenter.test.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index ff887bd7f4..8ad238b0f4 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -14,7 +14,7 @@ async function review (request, h) { const pageData = await ReviewBillRunService.go(id, page, request.yar) - return h.view('bill-runs/review.njk', { + return h.view('bill-runs/review/review.njk', { activeNavBar: 'bill-runs', ...pageData }) diff --git a/app/presenters/bill-runs/cancel-bill-run.presenter.js b/app/presenters/bill-runs/cancel-bill-run.presenter.js index e5c8c28397..35eed3da99 100644 --- a/app/presenters/bill-runs/cancel-bill-run.presenter.js +++ b/app/presenters/bill-runs/cancel-bill-run.presenter.js @@ -52,7 +52,7 @@ function _backLink (id, scheme, status) { return `/billing/batch/${id}/two-part-tariff-review` } - return `/system/bill-runs/${id}/review` + return `/system/bill-runs/review/${id}` } return `/system/bill-runs/${id}` diff --git a/app/views/bill-runs/review/review.njk b/app/views/bill-runs/review/review.njk index ab6ce74944..a4d95b999c 100644 --- a/app/views/bill-runs/review/review.njk +++ b/app/views/bill-runs/review/review.njk @@ -120,7 +120,7 @@ {{ govukButton({ classes: "govuk-button--secondary govuk-!-margin-bottom-0", text: "Cancel bill run", - href: "cancel", + href: "/system/bill-runs/" + billRunId + "/cancel", preventDoubleClick: true }) }} diff --git a/test/presenters/bill-runs/cancel-bill-run.presenter.test.js b/test/presenters/bill-runs/cancel-bill-run.presenter.test.js index a481617b22..e8be48ee00 100644 --- a/test/presenters/bill-runs/cancel-bill-run.presenter.test.js +++ b/test/presenters/bill-runs/cancel-bill-run.presenter.test.js @@ -44,7 +44,7 @@ describe('Cancel Bill Run presenter', () => { it('returns a link to the SROC review page', () => { const result = CancelBillRunPresenter.go(billRun) - expect(result.backLink).to.equal('/system/bill-runs/420e948f-1992-437e-8a47-74c0066cb017/review') + expect(result.backLink).to.equal('/system/bill-runs/review/420e948f-1992-437e-8a47-74c0066cb017') }) }) From 961979a5a406d92bea378a3360f68fd8667309f7 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 22 Oct 2024 18:42:30 +0100 Subject: [PATCH 007/147] Fix main review filter buttons POST action --- app/views/bill-runs/review/review.njk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/bill-runs/review/review.njk b/app/views/bill-runs/review/review.njk index a4d95b999c..a8a3e1c93a 100644 --- a/app/views/bill-runs/review/review.njk +++ b/app/views/bill-runs/review/review.njk @@ -130,7 +130,7 @@ {% set filtersForm %}

Filter by

-
+ {# Filter by licence holder or licence number #} From d646c7eea942d81e6b1e46a6cbc1b38da7a4abcf Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 24 Oct 2024 17:11:13 +0100 Subject: [PATCH 008/147] Move review licence page to `'/bill-runs/review` This just updates the controllers and routes --- .../bill-runs-review.controller.js | 25 ++++++++++++++++++- app/controllers/bill-runs.controller.js | 24 ------------------ app/routes/bill-runs-review.routes.js | 24 ++++++++++++++++++ app/routes/bill-runs.routes.js | 24 ------------------ 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 8ad238b0f4..35b71fcb1a 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -6,7 +6,9 @@ */ const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') +const ReviewLicenceService = require('../services/bill-runs/two-part-tariff/review-licence.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') +const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') async function review (request, h) { const { id } = request.params @@ -20,6 +22,17 @@ async function review (request, h) { }) } +async function reviewLicence (request, h) { + const { reviewLicenceId } = request.params + + const pageData = await ReviewLicenceService.go(reviewLicenceId, request.yar) + + return h.view('bill-runs/review/review-licence.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function submitReview (request, h) { const { id } = request.params @@ -28,7 +41,17 @@ async function submitReview (request, h) { return h.redirect(`/system/bill-runs/review/${id}`) } +async function submitReviewLicence (request, h) { + const { id: billRunId, licenceId } = request.params + + await SubmitReviewLicenceService.go(billRunId, licenceId, request.payload, request.yar) + + return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}`) +} + module.exports = { review, - submitReview + reviewLicence, + submitReview, + submitReviewLicence } diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 727d9d8e16..0e953fac9a 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -17,14 +17,12 @@ const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/ge const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js') const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') -const ReviewLicenceService = require('../services/bill-runs/two-part-tariff/review-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') const SubmitAmendedAdjustmentFactorService = require('../services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js') const SubmitAmendedAuthorisedVolumeService = require('../services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js') const SubmitAmendedBillableReturnsService = require('..//services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../services/bill-runs/submit-cancel-bill-run.service.js') const SubmitRemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') -const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') const SubmitSendBillRunService = require('../services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../services/bill-runs/view-bill-run.service.js') @@ -130,18 +128,6 @@ async function removeLicence (request, h) { }) } -async function reviewLicence (request, h) { - const { id: billRunId, licenceId } = request.params - - const pageData = await ReviewLicenceService.go(billRunId, licenceId, request.yar) - - return h.view('bill-runs/review-licence.njk', { - pageTitle: `Licence ${pageData.licence.licenceRef}`, - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function send (request, h) { const { id } = request.params @@ -232,14 +218,6 @@ async function submitRemoveLicence (request, h) { return h.redirect(`/system/bill-runs/${billRunId}/review`) } -async function submitReviewLicence (request, h) { - const { id: billRunId, licenceId } = request.params - - await SubmitReviewLicenceService.go(billRunId, licenceId, request.payload, request.yar) - - return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}`) -} - async function submitSend (request, h) { const { id } = request.params @@ -291,14 +269,12 @@ module.exports = { matchDetails, previewCharge, removeLicence, - reviewLicence, send, submitAmendedAdjustmentFactor, submitAmendedAuthorisedVolume, submitAmendedBillableReturns, submitCancel, submitRemoveLicence, - submitReviewLicence, submitSend, twoPartTariff, view diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index f04a04be93..39d2cd5186 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -26,6 +26,30 @@ const routes = [ } } } + }, + { + method: 'GET', + path: '/bill-runs/review/licence/{reviewLicenceId}', + options: { + handler: BillRunsReviewController.reviewLicence, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/bill-runs/review/licence/{reviewLicenceId}', + options: { + handler: BillRunsReviewController.submitReviewLicence, + auth: { + access: { + scope: ['billing'] + } + } + } } ] diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index 0abe35b484..71db72b96d 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -78,30 +78,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}', - options: { - handler: BillRunsController.reviewLicence, - auth: { - access: { - scope: ['billing'] - } - } - } - }, - { - method: 'POST', - path: '/bill-runs/{id}/review/{licenceId}', - options: { - handler: BillRunsController.submitReviewLicence, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}', From 9f89759fa3e4d6742a55b07076ff9f02d85660ee Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 24 Oct 2024 17:12:32 +0100 Subject: [PATCH 009/147] Add review_licences.id to query This means we can use it to directly find the match instead of bill run and licence ID. --- .../bill-runs/review/fetch-bill-run-licences.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/fetch-bill-run-licences.service.js b/app/services/bill-runs/review/fetch-bill-run-licences.service.js index d3269580fe..049f35bcf8 100644 --- a/app/services/bill-runs/review/fetch-bill-run-licences.service.js +++ b/app/services/bill-runs/review/fetch-bill-run-licences.service.js @@ -90,7 +90,7 @@ async function _fetchBillRunLicences ( id, filterIssues, filterLicenceHolderNumber, filterLicenceStatus, filterProgress, page = 1 ) { const reviewLicenceQuery = ReviewLicenceModel.query() - .select('licenceId', 'licenceRef', 'licenceHolder', 'issues', 'progress', 'status') + .select('id', 'licenceId', 'licenceRef', 'licenceHolder', 'issues', 'progress', 'status') .where('billRunId', id) .orderBy([ { column: 'status', order: 'desc' }, From 5a84c59a1d36e0af2cc1c60432da267bfef85e3d Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 24 Oct 2024 17:15:02 +0100 Subject: [PATCH 010/147] Use the review licence ID for the link --- app/presenters/bill-runs/review/review-bill-run.presenter.js | 2 +- app/views/bill-runs/review/review.njk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/presenters/bill-runs/review/review-bill-run.presenter.js b/app/presenters/bill-runs/review/review-bill-run.presenter.js index ef5b0b1bdc..811da853dd 100644 --- a/app/presenters/bill-runs/review/review-bill-run.presenter.js +++ b/app/presenters/bill-runs/review/review-bill-run.presenter.js @@ -73,7 +73,7 @@ function _prepareLicences (licences) { for (const licence of licences) { preparedLicences.push({ - id: licence.licenceId, + id: licence.id, licenceRef: licence.licenceRef, licenceHolder: licence.licenceHolder, issue: _getIssueOnLicence(licence.issues), diff --git a/app/views/bill-runs/review/review.njk b/app/views/bill-runs/review/review.njk index a8a3e1c93a..8023ab5ea9 100644 --- a/app/views/bill-runs/review/review.njk +++ b/app/views/bill-runs/review/review.njk @@ -322,7 +322,7 @@ {% endset %} {% set action %} - {{ licence.licenceRef }}View licence matching for licence {{ licence.licenceRef }} + {{ licence.licenceRef }}View licence matching for licence {{ licence.licenceRef }} {% endset %} {% set tableRow = [ From a22a8081a9c0b5f85996d97cc4db43852661152c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 24 Oct 2024 17:15:47 +0100 Subject: [PATCH 011/147] Oops! Remove a .only() --- .../bill-runs/review/submit-review-bill-run.service.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/services/bill-runs/review/submit-review-bill-run.service.test.js b/test/services/bill-runs/review/submit-review-bill-run.service.test.js index a3db99dad9..cba8b58a65 100644 --- a/test/services/bill-runs/review/submit-review-bill-run.service.test.js +++ b/test/services/bill-runs/review/submit-review-bill-run.service.test.js @@ -11,7 +11,7 @@ const { expect } = Code // Thing under test const SubmitReviewBillRunService = require('../../../../app/services/bill-runs/review/submit-review-bill-run.service.js') -describe.only('Submit Review Bill Run Service', () => { +describe('Submit Review Bill Run Service', () => { const billRunId = '27dad88a-6b3c-438b-a25f-f1483e7e12a0' let yarStub From 7fcb1d2f9f275d9e5482d998b61de4775d6df137 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 28 Oct 2024 08:36:54 +0000 Subject: [PATCH 012/147] Move and replace review licence presenter --- .../review/review-licence.presenter.js | 269 ++++++++++++++++ .../review-licence.presenter.js | 292 ------------------ 2 files changed, 269 insertions(+), 292 deletions(-) create mode 100644 app/presenters/bill-runs/review/review-licence.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js new file mode 100644 index 0000000000..668e35bdeb --- /dev/null +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -0,0 +1,269 @@ +'use strict' + +/** + * Formats the review licence data ready for presenting in the review licence page + * @module ReviewLicencePresenter + */ + +const Big = require('big.js') + +const { formatAbstractionPeriod, formatLongDate } = require('../../base.presenter.js') +const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') + +/** + * Formats the review licence data ready for presenting in the review licence page + * + * @param {module:ReviewLicenceModel} reviewLicence - instance of the `ReviewLicenceModel` returned from + * `FetchReviewLicenceService` + * + * @returns {object} page date needed for the review licence page + */ +function go (reviewLicence) { + const { + billRun, + licenceHolder, + licenceId, + licenceRef, + progress, + reviewChargeVersions, + reviewReturns, + status + } = reviewLicence + const { matchedReturns, unmatchedReturns } = _formatReviewReturns(reviewReturns) + + return { + billRunId: billRun.id, + chargeVersions: _chargeVersions(reviewChargeVersions, billRun.toFinancialYearEnding), + elementsInReview: _elementsInReview(reviewChargeVersions), + licence: { + licenceId, + licenceRef, + status, + licenceHolder, + progress + }, + matchedReturns, + pageTitle: `Licence ${licenceRef}`, + region: billRun.region.displayName, + unmatchedReturns + } +} + +function _billingAccountDetails (billingAccount) { + return { + billingAccountId: billingAccount.id, + accountNumber: billingAccount.accountNumber, + accountName: billingAccount.$accountName(), + contactName: billingAccount.$contactName(), + addressLines: billingAccount.$addressLines() + } +} + +function _chargeElements (reviewChargeElements, chargePeriod) { + const numberOfElements = reviewChargeElements.length + + return reviewChargeElements.map((reviewChargeElement, index) => { + const { amendedAllocated, chargeElement, id, issues, reviewReturns, status } = reviewChargeElement + + return { + billableReturns: `${amendedAllocated} ML / ${chargeElement.authorisedAnnualQuantity} ML`, + chargePeriods: _chargeElementChargePeriod(chargeElement, chargePeriod), + returnVolumes: _chargeElementReturnVolumes(reviewReturns), + description: chargeElement.description, + elementNumber: `Element ${index + 1} of ${numberOfElements}`, + status, + id, + issues: issues.length > 0 ? issues.split(', ') : [''], + purpose: chargeElement.purpose.description + } + }) +} + +function _chargeElementChargePeriod (chargeElement, chargePeriod) { + const { + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + } = chargeElement + + const abstractionPeriods = DetermineAbstractionPeriodService.go( + chargePeriod, + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + ) + + return abstractionPeriods.map((abstractionPeriod) => { + const { endDate, startDate } = abstractionPeriod + + return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` + }) +} + +function _chargeElementReturnVolumes (reviewReturns) { + return reviewReturns.map((reviewReturn) => { + const { quantity, returnReference, returnStatus } = reviewReturn + + if (returnStatus === 'due') { + return `overdue (${returnReference})` + } + + return `${quantity} ML (${returnReference})` + }) +} + +function _chargeReferences (reviewChargeReferences, chargePeriod) { + return reviewChargeReferences.map((reviewChargeReference) => { + const { amendedAuthorisedVolume, chargeReference, reviewChargeElements, id } = reviewChargeReference + const totalAllocated = _totalAllocated(reviewChargeElements) + + return { + billableReturnsWarning: totalAllocated > amendedAuthorisedVolume, + chargeCategory: `Charge reference ${chargeReference.chargeCategory.reference}`, + chargeDescription: chargeReference.chargeCategory.shortDescription, + id, + chargeElements: _chargeElements(reviewChargeElements, chargePeriod), + chargeReferenceLinkTitle: _chargeReferenceLinkTitle(reviewChargeReference), + totalBillableReturns: `${totalAllocated} ML / ${amendedAuthorisedVolume} ML` + } + }) +} + +function _chargeReferenceLinkTitle (reviewChargeReference) { + const { aggregate, chargeAdjustment } = reviewChargeReference + + if (aggregate !== 1 || chargeAdjustment !== 1) { + return 'Change details' + } + + return 'View details' +} + +function _chargeVersionDescription (reviewChargeReferences) { + const referenceCount = reviewChargeReferences.length + const elementCount = reviewChargeReferences.reduce((total, reviewChargeReference) => { + return total + reviewChargeReference.reviewChargeElements.length + }, 0) + + const referenceText = referenceCount > 1 ? 'references' : 'reference' + const elementText = elementCount > 1 ? 'elements' : 'element' + + return `${referenceCount} charge ${referenceText} with ${elementCount} two-part tariff charge ${elementText}` +} + +function _chargeVersions (reviewChargeVersions, toFinancialYearEnding) { + return reviewChargeVersions.map((reviewChargeVersion) => { + const { chargePeriodStartDate, chargePeriodEndDate, chargeVersion, reviewChargeReferences } = reviewChargeVersion + const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } + + return { + billingAccountDetails: _billingAccountDetails(chargeVersion.billingAccount), + chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, + chargeReferences: _chargeReferences(reviewChargeReferences, chargePeriod), + description: _chargeVersionDescription(reviewChargeReferences), + financialPeriod: _financialYear(toFinancialYearEnding) + } + }) +} + +function _elementsInReview (reviewChargeVersions) { + // If the licence we are reviewing is linked to at least one charge element (via charge version -> charge reference -> + // charge element) that has a status of 'review' then the licence is said to have a status of 'REVIEW' + return reviewChargeVersions.some((reviewChargeVersion) => { + const { reviewChargeReferences } = reviewChargeVersion + + return reviewChargeReferences.some((reviewChargeReference) => { + const { reviewChargeElements } = reviewChargeReference + + return reviewChargeElements.some((reviewChargeElement) => { + return reviewChargeElement.status === 'review' + }) + }) + }) +} + +function _financialYear (financialYearEnding) { + const startYear = financialYearEnding - 1 + const endYear = financialYearEnding + + return `${startYear} to ${endYear}` +} + +function _formatReviewReturns (reviewReturns) { + const matchedReturns = [] + const unmatchedReturns = [] + + reviewReturns.forEach((reviewReturn) => { + const { description, endDate, issues, purposes, returnLog, returnId, returnReference, startDate } = reviewReturn + const { periodStartDay, periodStartMonth, periodEndDay, periodEndMonth } = returnLog + + const formattedReviewReturn = { + abstractionPeriod: formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth), + description, + issues: issues.length > 0 ? issues.split(', ') : [''], + purpose: purposes[0].tertiary.description, + reference: returnReference, + returnId, + returnLink: _returnLink(reviewReturn), + returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, + returnStatus: _returnStatus(reviewReturn), + returnTotal: _returnTotal(reviewReturn) + } + + if (reviewReturn.reviewChargeElements.length > 0) { + matchedReturns.push(formattedReviewReturn) + } else { + unmatchedReturns.push(formattedReviewReturn) + } + }) + + return { matchedReturns, unmatchedReturns } +} + +function _returnLink (reviewReturn) { + const { returnId, returnStatus } = reviewReturn + + if (['due', 'received'].includes(returnStatus)) { + return `/return/internal?returnId=${returnId}` + } + + return `/returns/return?id=${returnId}` +} + +function _returnStatus (reviewReturn) { + const { returnStatus, underQuery } = reviewReturn + + if (returnStatus === 'due') { + return 'overdue' + } + + if (underQuery) { + return 'query' + } + + return reviewReturn.returnStatus +} + +function _returnTotal (reviewReturn) { + const { allocated, quantity, returnStatus } = reviewReturn + + if (['due', 'received'].includes(returnStatus)) { + return '/' + } + + return `${allocated} ML / ${quantity} ML` +} + +function _totalAllocated (reviewChargeElements) { + return reviewChargeElements.reduce((total, reviewChargeElement) => { + const { amendedAllocated } = reviewChargeElement + + return Big(total).plus(amendedAllocated).toNumber() + }, 0) +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js b/app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js deleted file mode 100644 index c2cce71743..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js +++ /dev/null @@ -1,292 +0,0 @@ -'use strict' - -/** - * Formats the review licence data ready for presenting in the review licence page - * @module ReviewLicencePresenter - */ - -const Big = require('big.js') - -const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') -const { formatAbstractionPeriod, formatLongDate } = require('../../base.presenter.js') - -/** - * Formats the review licence data ready for presenting in the review licence page - * - * @param {module:BillRunModel} billRun - the data from the bill run - * @param {module:ReviewLicenceModel} licence - the data from review licence - * - * @returns {object} the prepared bill run and licence data to be passed to the review licence page - */ -function go (billRun, licence) { - return { - billRunId: billRun.id, - region: billRun.region.displayName, - licence: { - licenceId: licence[0].licenceId, - licenceRef: licence[0].licenceRef, - status: licence[0].status, - licenceHolder: licence[0].licenceHolder, - progress: licence[0].progress - }, - elementsInReview: licence[0].hasReviewStatus, - matchedReturns: _matchedReturns(licence[0].reviewReturns), - unmatchedReturns: _unmatchedReturns(licence[0].reviewReturns), - chargeData: _prepareChargeData(licence, billRun) - } -} - -function _billingAccountDetails (billingAccount) { - return { - billingAccountId: billingAccount.id, - accountNumber: billingAccount.accountNumber, - accountName: billingAccount.$accountName(), - contactName: billingAccount.$contactName(), - addressLines: billingAccount.$addressLines() - } -} - -function _chargeElementCount (reviewChargeVersion) { - const { reviewChargeReferences } = reviewChargeVersion - - const chargeElementCount = reviewChargeReferences.reduce((total, reviewChargeReference) => { - return total + reviewChargeReference.reviewChargeElements.length - }, 0) - - return chargeElementCount -} - -function _chargeElementDetails (reviewChargeReference, chargePeriod) { - const { reviewChargeElements } = reviewChargeReference - - const chargeElements = reviewChargeElements.map((reviewChargeElement, index) => { - return { - reviewChargeElementId: reviewChargeElement.id, - elementNumber: `Element ${index + 1} of ${reviewChargeElements.length}`, - elementStatus: reviewChargeElement.status, - elementDescription: reviewChargeElement.chargeElement.description, - dates: _prepareChargeElementDates(reviewChargeElement.chargeElement, chargePeriod), - purpose: reviewChargeElement.chargeElement.purpose.description, - issues: reviewChargeElement.issues.length > 0 ? reviewChargeElement.issues.split(', ') : [''], - billableReturns: `${reviewChargeElement.amendedAllocated} ML / ${reviewChargeElement.chargeElement.authorisedAnnualQuantity} ML`, - returnVolume: _prepareReturnVolume(reviewChargeElement) - } - }) - - return chargeElements -} - -function _chargeReferenceDetails (reviewChargeVersion, chargePeriod) { - const chargeReference = [] - - const { reviewChargeReferences } = reviewChargeVersion - - reviewChargeReferences.forEach((reviewChargeReference) => { - const totalBillableReturns = _totalBillableReturns(reviewChargeReference) - - chargeReference.push({ - id: reviewChargeReference.id, - chargeCategory: `Charge reference ${reviewChargeReference.chargeReference.chargeCategory.reference}`, - chargeDescription: reviewChargeReference.chargeReference.chargeCategory.shortDescription, - totalBillableReturns: `${totalBillableReturns} ML / ${reviewChargeReference.amendedAuthorisedVolume} ML`, - billableReturnsWarning: totalBillableReturns > reviewChargeReference.amendedAuthorisedVolume, - chargeReferenceLink: _chargeReferenceLink(reviewChargeReference), - chargeElements: _chargeElementDetails(reviewChargeReference, chargePeriod) - }) - }) - - return chargeReference -} - -function _chargeReferenceLink (reviewChargeReference) { - const { chargeAdjustment, aggregate } = reviewChargeReference - - if (chargeAdjustment !== 1 || aggregate !== 1) { - return { linkName: 'Change details' } - } - - return { linkName: 'View details' } -} - -function _financialYear (financialYearEnding) { - const startYear = financialYearEnding - 1 - const endYear = financialYearEnding - - return `${startYear} to ${endYear}` -} - -function _matchedReturns (returnLogs) { - const matchedReturns = [] - - returnLogs.forEach((returnLog) => { - if (returnLog.reviewChargeElements.length > 0) { - matchedReturns.push( - { - returnId: returnLog.returnId, - reference: returnLog.returnReference, - dates: _prepareDate(returnLog.startDate, returnLog.endDate), - returnStatus: _returnStatus(returnLog), - description: returnLog.description, - purpose: returnLog.purposes[0].tertiary.description, - returnTotal: _returnTotal(returnLog), - issues: returnLog.issues.length > 0 ? returnLog.issues.split(', ') : [''], - returnLink: _returnLink(returnLog), - absPeriod: _prepareAbsPeriod(returnLog.returnLog) - } - ) - } - }) - - return matchedReturns -} - -function _prepareAbsPeriod (returnLog) { - const { periodStartDay, periodStartMonth, periodEndDay, periodEndMonth } = returnLog - - return formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth) -} - -function _prepareChargeData (licence, billRun) { - const chargeData = [] - - licence[0].reviewChargeVersions.forEach((reviewChargeVersion) => { - const chargePeriod = { - startDate: reviewChargeVersion.chargePeriodStartDate, - endDate: reviewChargeVersion.chargePeriodEndDate - } - - chargeData.push({ - financialYear: _financialYear(billRun.toFinancialYearEnding), - chargePeriodDate: _prepareDate( - reviewChargeVersion.chargePeriodStartDate, - reviewChargeVersion.chargePeriodEndDate - ), - chargeElementCount: _chargeElementCount(reviewChargeVersion), - billingAccountDetails: _billingAccountDetails(reviewChargeVersion.billingAccountDetails), - chargeReferences: _chargeReferenceDetails(reviewChargeVersion, chargePeriod) - }) - }) - - return chargeData -} - -function _prepareChargeElementDates (chargeElement, chargePeriod) { - const { - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - } = chargeElement - - const abstractionPeriods = DetermineAbstractionPeriodService.go( - chargePeriod, - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - ) - - const dates = [] - - // NOTE: There can be more than 1 abstraction period for an element, hence why we loop through them - abstractionPeriods.forEach((abstractionPeriod) => { - dates.push(_prepareDate(abstractionPeriod.startDate, abstractionPeriod.endDate)) - }) - - return dates -} - -function _prepareDate (startDate, endDate) { - const preparedStartDate = formatLongDate(startDate) - const preparedEndDate = formatLongDate(endDate) - - return `${preparedStartDate} to ${preparedEndDate}` -} - -function _prepareReturnVolume (reviewChargeElement) { - const { reviewReturns } = reviewChargeElement - const returnVolumes = [] - - if (reviewReturns) { - reviewReturns.forEach((reviewReturn) => { - if (reviewReturn.returnStatus === 'due') { - returnVolumes.push(`overdue (${reviewReturn.returnReference})`) - } else { - returnVolumes.push(`${reviewReturn.quantity} ML (${reviewReturn.returnReference})`) - } - }) - } - - return returnVolumes -} - -function _returnLink (returnLog) { - if (['due', 'received'].includes(returnLog.returnStatus)) { - return `/return/internal?returnId=${returnLog.returnId}` - } - - return `/returns/return?id=${returnLog.returnId}` -} - -function _returnStatus (returnLog) { - if (returnLog.returnStatus === 'due') { - return 'overdue' - } - - if (returnLog.underQuery) { - return 'query' - } - - return returnLog.returnStatus -} - -function _returnTotal (returnLog) { - const { returnStatus, allocated, quantity } = returnLog - - if (['due', 'received'].includes(returnStatus)) { - return '/' - } - - return `${allocated} ML / ${quantity} ML` -} - -function _totalBillableReturns (reviewChargeReference) { - let totalBillableReturns = 0 - - reviewChargeReference.reviewChargeElements.forEach((reviewChargeElement) => { - totalBillableReturns = Big(totalBillableReturns).plus(reviewChargeElement.amendedAllocated).toNumber() - }) - - return totalBillableReturns -} - -function _unmatchedReturns (returnLogs) { - const unmatchedReturns = [] - - returnLogs.forEach((returnLog) => { - // If the reviewChargeElement length is less than 1 it means the return did not match to a charge element and - // therefore belongs in the unmatchedReturns section - if (returnLog.reviewChargeElements.length < 1) { - unmatchedReturns.push( - { - returnId: returnLog.returnId, - reference: returnLog.returnReference, - dates: _prepareDate(returnLog.startDate, returnLog.endDate), - returnStatus: _returnStatus(returnLog), - description: returnLog.description, - purpose: returnLog.purposes[0].tertiary.description, - returnTotal: `${returnLog.allocated} / ${returnLog.quantity} ML`, - issues: returnLog.issues.length > 0 ? returnLog.issues.split(', ') : [''], - returnLink: _returnLink(returnLog), - absPeriod: _prepareAbsPeriod(returnLog.returnLog) - } - ) - } - }) - - return unmatchedReturns -} - -module.exports = { - go -} From 7cd5607ccdb33981188e84dd87a6bb6ae4079974 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 28 Oct 2024 08:37:20 +0000 Subject: [PATCH 013/147] Move and replace fetch review licence service --- .../review/fetch-review-licence.service.js | 173 ++++++++++++++++++ .../fetch-review-licence-results.service.js | 148 --------------- 2 files changed, 173 insertions(+), 148 deletions(-) create mode 100644 app/services/bill-runs/review/fetch-review-licence.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js diff --git a/app/services/bill-runs/review/fetch-review-licence.service.js b/app/services/bill-runs/review/fetch-review-licence.service.js new file mode 100644 index 0000000000..64fe32fd80 --- /dev/null +++ b/app/services/bill-runs/review/fetch-review-licence.service.js @@ -0,0 +1,173 @@ +'use strict' + +/** + * Fetches the individual review licence data for a two-part tariff bill run + * @module FetchReviewLicenceService + */ + +const { ref } = require('objection') + +const ReviewLicenceModel = require('../../../models/review-licence.model.js') + +async function go (reviewLicenceId) { + return _fetch(reviewLicenceId) +} + +async function _fetch (reviewLicenceId) { + return ReviewLicenceModel.query() + .findById(reviewLicenceId) + .select([ + 'id', + 'billRunId', + 'licenceId', + 'licenceRef', + 'licenceHolder', + 'status', + 'progress' + ]) + .withGraphFetched('billRun') + .modifyGraph('billRun', (builder) => { + builder + .select([ + 'id', + 'toFinancialYearEnding' + ]) + .withGraphFetched('region') + .modifyGraph('region', (builder) => { + builder.select([ + 'displayName' + ]) + }) + }) + .withGraphFetched('reviewReturns') + .modifyGraph('reviewReturns', (builder) => { + builder + .select([ + 'id', + 'allocated', + 'description', + 'endDate', + 'issues', + 'quantity', + 'purposes', + 'returnId', + 'returnReference', + 'returnStatus', + 'startDate', + 'underQuery' + ]) + .orderBy('reviewReturns.startDate', 'asc') + .withGraphFetched('returnLog') + .modifyGraph('returnLog', (builder) => { + builder + .select([ + ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), + ref('metadata:nald.periodStartMonth').castInt().as('periodStartMonth'), + ref('metadata:nald.periodEndDay').castInt().as('periodEndDay'), + ref('metadata:nald.periodEndMonth').castInt().as('periodEndMonth') + ]) + }) + .withGraphFetched('reviewChargeElements') + .modifyGraph('reviewReturns', (builder) => { + builder + .select([ + 'id' + ]) + .orderBy('startDate', 'asc') + }) + }) + .withGraphFetched('reviewChargeVersions') + .modifyGraph('reviewChargeVersions', (builder) => { + builder + .select([ + 'id', + 'chargePeriodEndDate', + 'chargePeriodStartDate' + ]) + .orderBy('chargePeriodStartDate', 'asc') + .withGraphFetched('reviewChargeReferences') + .modifyGraph('reviewChargeReferences', (builder) => { + builder + .select([ + 'id', + 'aggregate', + 'amendedAuthorisedVolume', + 'chargeAdjustment' + ]) + .withGraphFetched('chargeReference') + .modifyGraph('chargeReference', (builder) => { + builder + .select([ + 'id' + ]) + .withGraphFetched('chargeCategory') + .modifyGraph('chargeCategory', (builder) => { + builder + .select([ + 'id', + 'reference', + 'shortDescription' + ]) + }) + }) + .withGraphFetched('reviewChargeElements') + .modifyGraph('reviewChargeElements', (builder) => { + builder + .select([ + 'reviewChargeElements.id', + 'reviewChargeElements.amendedAllocated', + 'reviewChargeElements.issues', + 'reviewChargeElements.status' + ]) + .join('chargeElements', 'reviewChargeElements.chargeElementId', 'chargeElements.id') + .orderBy('chargeElements.authorisedAnnualQuantity', 'desc') + .withGraphFetched('chargeElement') + .modifyGraph('chargeElement', (builder) => { + builder + .select([ + 'id', + 'description', + 'abstractionPeriodStartDay', + 'abstractionPeriodStartMonth', + 'abstractionPeriodEndDay', + 'abstractionPeriodEndMonth', + 'authorisedAnnualQuantity' + ]) + .withGraphFetched('purpose') + .modifyGraph('purpose', (builder) => { + builder + .select([ + 'id', + 'description' + ]) + }) + }) + .withGraphFetched('reviewReturns') + .modifyGraph('reviewReturns', (builder) => { + builder + .select([ + 'reviewReturns.id', + 'reviewReturns.quantity', + 'reviewReturns.returnReference', + 'reviewReturns.returnStatus' + ]) + }) + }) + }) + .withGraphFetched('chargeVersion') + .modifyGraph('chargeVersion', (builder) => { + builder + .select([ + 'id' + ]) + .withGraphFetched('billingAccount') + .modifyGraph('billingAccount', (builder) => { + builder.modify('contactDetails') + }) + }) + }) +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js b/app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js deleted file mode 100644 index f348a3d5f4..0000000000 --- a/app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js +++ /dev/null @@ -1,148 +0,0 @@ -'use strict' - -/** - * Fetches the individual review licence data for a two-part tariff bill run - * @module FetchReviewLicenceResultsService - */ - -const { ref } = require('objection') - -const BillingAccountModel = require('../../../models/billing-account.model.js') -const BillRunModel = require('../../../models/bill-run.model.js') -const ReviewLicenceModel = require('../../../models/review-licence.model.js') - -/** - * Fetches the bill run and an individual licences review data for a two-part tariff bill run - * - * @param {module:BillRunModel} billRunId - UUID of the bill run - * @param {module:LicenceModel} licenceId - UUID of the individual licence to review - * - * @returns {Promise} Contains an array of bill run data and review licence data - */ -async function go (billRunId, licenceId) { - const billRun = await _fetchBillRun(billRunId) - const licence = await _fetchReviewLicence(licenceId, billRunId) - - await _fetchBillingAccountDetails(licence[0].reviewChargeVersions) - - return { billRun, licence } -} - -async function _fetchBillingAccount (billingAccountId) { - return BillingAccountModel.query().findById(billingAccountId).modify('contactDetails') -} - -async function _fetchBillingAccountDetails (reviewChargeVersions) { - for (const reviewChargeVersion of reviewChargeVersions) { - reviewChargeVersion.billingAccountDetails = await _fetchBillingAccount( - reviewChargeVersion.chargeVersion.billingAccountId - ) - } -} - -async function _fetchBillRun (billRunId) { - return BillRunModel.query() - .findById(billRunId) - .select( - 'id', - 'fromFinancialYearEnding', - 'toFinancialYearEnding') - .withGraphFetched('region') - .modifyGraph('region', (builder) => { - builder.select('displayName') - }) -} - -async function _fetchReviewLicence (licenceId, billRunId) { - return ReviewLicenceModel.query() - .select( - 'id', - 'billRunId', - 'licenceId', - 'licenceRef', - 'licenceHolder', - 'issues', - 'status', - 'progress', - ReviewLicenceModel.raw(` - EXISTS (SELECT 1 - FROM review_charge_elements rce - INNER JOIN review_charge_references rcr ON rce.review_charge_reference_id = rcr.id - INNER JOIN review_charge_versions rcv ON rcr.review_charge_version_id = rcv.id - WHERE rce.status = 'review' - AND rcv.review_licence_id = review_licences.id) AS has_review_status - `) - ) - .where('licenceId', licenceId) - .where('billRunId', billRunId) - .withGraphFetched('reviewReturns.reviewChargeElements') - .modifyGraph('reviewReturns', (builder) => { - builder.orderBy('reviewReturns.startDate', 'asc') - }) - .withGraphFetched('reviewReturns.returnLog') - .modifyGraph('reviewReturns.returnLog', (builder) => { - builder.select([ - ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), - ref('metadata:nald.periodStartMonth').castInt().as('periodStartMonth'), - ref('metadata:nald.periodEndDay').castInt().as('periodEndDay'), - ref('metadata:nald.periodEndMonth').castInt().as('periodEndMonth')]) - }) - .withGraphFetched('reviewChargeVersions') - .modifyGraph('reviewChargeVersions', (builder) => { - builder - .join('chargeVersions', 'reviewChargeVersions.chargeVersionId', 'chargeVersions.id') - .orderBy('chargeVersions.startDate', 'asc') - }) - .withGraphFetched('reviewChargeVersions.chargeVersion') - .modifyGraph('reviewChargeVersions.chargeVersion', (builder) => { - builder.select([ - 'billingAccountId' - ]) - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences') - .modifyGraph('reviewChargeVersions.reviewChargeReferences', (builder) => { - builder - .join('chargeReferences', 'reviewChargeReferences.chargeReferenceId', 'chargeReferences.id') - .join('chargeCategories', 'chargeReferences.chargeCategoryId', 'chargeCategories.id') - .orderBy('chargeCategories.subsistenceCharge', 'desc') - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences.chargeReference') - .modifyGraph('reviewChargeVersions.reviewChargeReferences.chargeReference', (builder) => { - builder.select([ - 'chargeCategoryId' - ]) - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences.chargeReference.chargeCategory') - .modifyGraph('reviewChargeVersions.reviewChargeReferences.chargeReference.chargeCategory', (builder) => { - builder.select([ - 'reference', - 'shortDescription' - ]) - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences.reviewChargeElements') - .modifyGraph('reviewChargeVersions.reviewChargeReferences.reviewChargeElements', (builder) => { - builder - .join('chargeElements', 'reviewChargeElements.chargeElementId', 'chargeElements.id') - .orderBy('chargeElements.authorisedAnnualQuantity', 'desc') - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences.reviewChargeElements.chargeElement') - .modifyGraph('reviewChargeVersions.reviewChargeReferences.reviewChargeElements.chargeElement', (builder) => { - builder.select([ - 'description', - 'abstractionPeriodStartDay', - 'abstractionPeriodStartMonth', - 'abstractionPeriodEndDay', - 'abstractionPeriodEndMonth', - 'authorisedAnnualQuantity' - ]) - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences.reviewChargeElements.chargeElement.purpose') - .modifyGraph('reviewChargeVersions.reviewChargeReferences.reviewChargeElements.chargeElement.purpose', (builder) => { - builder.select(['description']) - }) - .withGraphFetched('reviewChargeVersions.reviewChargeReferences.reviewChargeElements.reviewReturns') -} - -module.exports = { - go -} From a9ff4f9250720803ac2a18e6e1dffaa35e1dff74 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 28 Oct 2024 08:37:50 +0000 Subject: [PATCH 014/147] Move and update review licence view --- .../bill-runs/{ => review}/review-licence.njk | 468 +++++++----------- 1 file changed, 190 insertions(+), 278 deletions(-) rename app/views/bill-runs/{ => review}/review-licence.njk (51%) diff --git a/app/views/bill-runs/review-licence.njk b/app/views/bill-runs/review/review-licence.njk similarity index 51% rename from app/views/bill-runs/review-licence.njk rename to app/views/bill-runs/review/review-licence.njk index 3b058a61a9..6833191fc3 100644 --- a/app/views/bill-runs/review-licence.njk +++ b/app/views/bill-runs/review/review-licence.njk @@ -9,13 +9,100 @@ {% from "govuk/components/inset-text/macro.njk" import govukInsetText %} {% from "govuk/components/warning-text/macro.njk" import govukWarningText %} +{# Helper for generating both the matched and unmatched returns tables #} +{% macro returnsTable(matchType, returns) %} + {% set caption %} + {% if matchType == 'matched' %} + Matched returns + {% else %} + Unmatched returns + {% endif %} + {% endset %} + + {% set tableRows = [] %} + {% for return in returns %} + {% set returnIndex = loop.index0 %} + + {% set action %} + {{ return.reference }} +
{{return.returnPeriod}}
+
{{return.abstractionPeriod}}
+ {% endset %} + + {% set returnSummary %} +
+ {{ return.purpose }} +
+ {{ return.description }} + {% endset %} + + {% set tag %} + {{ statusTag(return.returnStatus) }} + {% endset %} + + {% set issues = '' %} + {% for issue in return.issues %} + {% set issues = issues + '
' + issue + '
' %} + {% endfor %} + + {% set tableRow = [ + { + html: action, + classes: 'govuk-body-s', + attributes: { 'data-test': matchType + '-return-action-' + matchedReturnIndex } + }, + { + html: returnSummary, + classes: 'govuk-body-s', + attributes: { 'data-test': matchType + '-return-summary-' + matchedReturnIndex } + }, + { + html: tag, + classes: 'govuk-body-s', + attributes: { 'data-test': matchType + '-return-status-' + matchedReturnIndex } + }, + { + html: "
" + return.returnTotal + "
" + issues, + classes: "govuk-body-s govuk-!-text-align-right", + attributes: { 'data-test': matchType + '-return-total-' + matchedReturnIndex} + }] + %} + + {% set tableRows = (tableRows.push(tableRow), tableRows) %} + {% endfor %} + + {# Table displaying details of the returns #} + {{ govukTable({ + caption: caption, + captionClasses: "govuk-table__caption--m", + attributes: { 'data-test': matchType + '-returns' }, + firstCellIsHeader: false, + head: [ + { + text: 'Return reference and periods' + }, + { + text: 'Purpose and description' + }, + { + text: 'Status' + }, + { + text: 'Return totals Allocated/Total', + format: 'numeric', + classes: 'width-one-tenth' + } + ], + rows: tableRows + }) }} +{% endmacro %} {% block breadcrumbs %} {# Back link #} {{ govukBackLink({ text: 'Go back to review licences', - href: '/system/bill-runs/' + billRunId + '/review' + href: '/system/bill-runs/review/' + billRunId }) }} {% endblock %} @@ -44,54 +131,27 @@ {# Licence nav bars #} {# Licence in review text #} @@ -101,64 +161,65 @@ }) }} {% endif %} - {# Change status #} - {% if licence.status === 'ready' %} - {% set statusButtonText = 'Put licence into review' %} - {% set statusButtonValue = 'review' %} - {% set statusButtonClass = "govuk-button--secondary" %} - {% else %} - {% set statusButtonText = 'Confirm licence is ready' %} - {% set statusButtonValue = 'ready' %} - {% set statusButtonClass = "govuk-button--primary" %} - {% endif %} - - {# Mark progress #} - {% if licence.progress %} - {% set progressButtonText = 'Remove progress mark' %} - {% set progressButtonValue = 'unmark' %} - {% else %} - {% set progressButtonText = 'Mark progress' %} - {% set progressButtonValue = 'mark' %} - {% endif %} -
- {{ govukButton({ - text: statusButtonText, - classes: statusButtonClass, - name: "licence-status", - value: statusButtonValue, - preventDoubleClick: true - }) }} + {# Change status button #} + {% if licence.status === 'ready' %} + {% set statusButtonText = 'Put licence into review' %} + {% set statusButtonValue = 'review' %} + {% set statusButtonClass = "govuk-button--secondary" %} + {% else %} + {% set statusButtonText = 'Confirm licence is ready' %} + {% set statusButtonValue = 'ready' %} + {% set statusButtonClass = "govuk-button--primary" %} + {% endif %} + + {{ govukButton({ + text: statusButtonText, + classes: statusButtonClass, + name: "licence-status", + value: statusButtonValue, + preventDoubleClick: true + }) }} - {{ govukButton({ - text: progressButtonText, - classes: "govuk-button--secondary", - name: "mark-progress", - value: progressButtonValue, - preventDoubleClick: true - }) }} + {# Mark progress button #} + {% if licence.progress %} + {% set progressButtonText = 'Remove progress mark' %} + {% set progressButtonValue = 'unmark' %} + {% else %} + {% set progressButtonText = 'Mark progress' %} + {% set progressButtonValue = 'mark' %} + {% endif %} + + {{ govukButton({ + text: progressButtonText, + classes: "govuk-button--secondary", + name: "mark-progress", + value: progressButtonValue, + preventDoubleClick: true + }) }} - {{ govukButton({ - text: 'Remove from bill run', - classes: "govuk-button--secondary", - href: "../remove/" + licence.licenceId, - preventDoubleClick: true - }) }} + {# Remove from bill run button #} + {{ govukButton({ + text: 'Remove from bill run', + classes: "govuk-button--secondary", + href: "../remove/" + licence.licenceId, + preventDoubleClick: true + }) }}
- {# Charge Periods #} + {# Charge Periods (bookmarks) #}

Charge periods

@@ -174,187 +235,35 @@
- {# Matched Returns #} - {% if matchedReturns.length > 0 %} - {% set tableRows = [] %} - {% for return in matchedReturns %} - {% set matchedReturnIndex = loop.index0 %} - - {% set action %} - {{ return.reference }} -
{{return.dates}}
-
{{return.absPeriod}}
- {% endset %} - - {% set returnSummary %} -
- {{ return.purpose }} -
- {{ return.description }} - {% endset %} - - {% set tag %} - {{ statusTag(return.returnStatus) }} - {% endset %} - - {% set issues = '' %} - {% for issue in return.issues %} - {% set issues = issues + '
' + issue + '
' %} - {% endfor %} - - {% set tableRow = [ - { - html: action, - classes: 'govuk-body-s', - attributes: { 'data-test': 'matched-return-action-' + matchedReturnIndex } - }, - { - html: returnSummary, - classes: 'govuk-body-s', - attributes: { 'data-test': 'matched-return-summary-' + matchedReturnIndex } - }, - { - html: tag, - classes: 'govuk-body-s', - attributes: { 'data-test': 'matched-return-status-' + matchedReturnIndex } - }, - { - html: "
" + return.returnTotal + "
" + issues, - classes: "govuk-body-s govuk-!-text-align-right", - attributes: { 'data-test': 'matched-return-total-' + matchedReturnIndex} - }] - %} - - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endfor %} - - {# Table displaying details of the matched returns #} - {{ govukTable({ - caption: "Matched returns", - captionClasses: "govuk-table__caption--m", - attributes: { 'data-test': 'matched-returns' }, - firstCellIsHeader: false, - head: [ - { - text: 'Return reference and periods' - }, - { - text: 'Purpose and description' - }, - { - text: 'Status' - }, - { - text: 'Return totals Allocated/Total', - format: 'numeric', - classes: 'width-one-tenth' - } - ], - rows: tableRows - }) }} - {% endif %} - - {# Unmatched Returns #} - {% if unmatchedReturns.length > 0 %} - {% set tableRows = [] %} - {% for return in unmatchedReturns %} - {% set unmatchedReturnIndex = loop.index0 %} - - {% set action %} - {{ return.reference }} -
{{return.dates}}
-
{{return.absPeriod}}
- {% endset %} - - {% set returnSummary %} -
- {{ return.purpose }} -
- {{ return.description }} - {% endset %} - - {% set tag %} - {{ statusTag(return.returnStatus) }} - {% endset %} - - {% set issues = '' %} - {% for issue in return.issues %} - {% set issues = issues + '
' + issue + '
' %} - {% endfor %} - - {% set tableRow = [ - { - html: action, - classes: 'govuk-body-s', - attributes: { 'data-test': 'unmatched-return-action-' + unmatchedReturnIndex } - }, - { - html: returnSummary, - classes: 'govuk-body-s', - attributes: { 'data-test': 'unmatched-return-summary-' + unmatchedReturnIndex } - }, - { - html: tag, - classes: 'govuk-body-s', - attributes: { 'data-test': 'unmatched-return-status-' + unmatchedReturnIndex } - }, - { - html: "
" + return.returnTotal + "
" + issues, - classes: "govuk-body-s govuk-!-text-align-right", - attributes: { 'data-test': 'unmatched-return-total-' + unmatchedReturnIndex } - } - ] - %} - - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endfor %} - - {# Table displaying details of the unmatched returns #} - {{ govukTable({ - caption: "Unmatched returns", - captionClasses: "govuk-table__caption--m", - attributes: { 'data-test': 'unmatched-returns' }, - firstCellIsHeader: false, - head: [ - { - text: 'Return reference and periods' - }, - { - text: 'Purpose and description' - }, - { - text: 'Status' - }, - { - text: 'Return totals', - format: 'numeric' - } - ], - rows: tableRows - }) }} - {% endif %} - - {# No Returns #} {% if matchedReturns == 0 and unmatchedReturns == 0 %} -

No two-part tariff returns

+ {# No Returns #} +

No two-part tariff returns

+ {% else %} + {# Matched Returns #} + {% if matchedReturns.length > 0 %} + {{ returnsTable('matched', matchedReturns) }} + {% endif %} + + {# Unmatched Returns #} + {% if unmatchedReturns.length > 0 %} + {{ returnsTable('unmatched', matchedReturns) }} + {% endif %} {% endif %}
- {# Loop through Charge Versions #} + {# Charge Periods (proper) #}
- {% for chargeVersion in chargeData %} - {% set chargeVersionIndex = loop.index0 %} -
Financial year {{chargeVersion.financialYear}}
+ {% for chargeVersion in chargeVersions %} + {% set chargeVersionIndex = loop.index0 %} + +
Financial year {{chargeVersion.financialPeriod}}
-

Charge periods {{chargeVersion.chargePeriodDate}}

+

Charge periods {{chargeVersion.chargePeriod}}

- {% set chargeReferenceText = "charge references " if chargeVersion.chargeReferences.length > 1 else "charge reference " %} - {% set chargeElementText = "charge elements " if chargeVersion.chargeElementCount > 1 else "charge element " %} - -
{{chargeVersion.chargeReferences.length}} {{chargeReferenceText}} with {{chargeVersion.chargeElementCount}} two-part tariff {{chargeElementText}}
+
{{ chargeVersion.description }}
{# Billing account details #} {% set billingAccountLink = '/billing-accounts/' + chargeVersion.billingAccountDetails.billingAccountId %} @@ -389,16 +298,19 @@
-

{{chargeReference.chargeCategory}}
{{chargeReference.chargeDescription}}

+

+ {{chargeReference.chargeCategory}} +
{{chargeReference.chargeDescription}}
+

- {% if chargeReference.billableReturnsWarning %} - {{ govukWarningText({ - text: "The total billable return volume exceeds the total authorised volume", - iconFallbackText: "Warning" - }) }} - {% endif %} + {% if chargeReference.billableReturnsWarning %} + {{ govukWarningText({ + text: "The total billable return volume exceeds the total authorised volume", + iconFallbackText: "Warning" + }) }} + {% endif %} {% set rows = [] %} {% set row = { @@ -412,8 +324,8 @@ actions: { items: [ { - href: licence.licenceId + '/charge-reference-details/' + chargeReference.id, - text: chargeReference.chargeReferenceLink.linkName, + href: '/system/bill-runs/review/charge-reference/' + chargeReference.id, + text: chargeReference.chargeReferenceLinkTitle, attributes: { 'data-test': 'charge-version-' + chargeVersionIndex + '-charge-reference-link-' + chargeReferenceIndex } } ] @@ -439,12 +351,12 @@
{{chargeElement.elementNumber}} - {{ statusTag(chargeElement.elementStatus) }} + {{ statusTag(chargeElement.status) }} -

{{chargeElement.elementDescription}} +

{{chargeElement.description}}
- {% for chargeElementDate in chargeElement.dates %} -
{{ chargeElementDate }}
+ {% for chargePeriod in chargeElement.chargePeriods %} +
{{ chargePeriod }}
{% endfor %}
{{ chargeElement.purpose }} @@ -456,7 +368,7 @@ {% endfor %} {% set returnVolumes = '' %} - {% for returnVolume in chargeElement.returnVolume %} + {% for returnVolume in chargeElement.returnVolumes %} {% set returnVolumes = returnVolumes + '
' + returnVolume + '
' %} {% endfor %} @@ -479,7 +391,7 @@ actions: { items: [ { - href: licence.licenceId + '/match-details/' + chargeElement.reviewChargeElementId, + href: '/system/bill-runs/review/charge-element/' + chargeElement.id, html: '
View match details
' } ]} From c57ea032c448f51f7c8bf8c6836e3fcca9e1f1fb Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 28 Oct 2024 08:39:11 +0000 Subject: [PATCH 015/147] Update Review licence service to use new modules --- .../two-part-tariff/review-licence.service.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/app/services/bill-runs/two-part-tariff/review-licence.service.js b/app/services/bill-runs/two-part-tariff/review-licence.service.js index c03412dc6e..6c1aa1837a 100644 --- a/app/services/bill-runs/two-part-tariff/review-licence.service.js +++ b/app/services/bill-runs/two-part-tariff/review-licence.service.js @@ -1,28 +1,27 @@ 'use strict' /** - * Orchestrates fetching and presenting the data needed for the licence review page in a two-part tariff bill run + * Orchestrates fetching and presenting the data needed for the two-part tariff review licence page * @module ReviewLicenceService */ -const FetchReviewLicenceResultsService = require('./fetch-review-licence-results.service.js') -const ReviewLicencePresenter = require('../../../presenters/bill-runs/two-part-tariff/review-licence.presenter.js') +const FetchReviewLicenceService = require('../review/fetch-review-licence.service.js') +const ReviewLicencePresenter = require('../../../presenters/bill-runs/review/review-licence.presenter.js') /** - * Orchestrates fetching and presenting the data needed for the licence review page in a two-part tariff bill run + * Orchestrates fetching and presenting the data needed for the two-part tariff review licence page * - * @param {module:BillRunModel} billRunId - The UUID for the bill run - * @param {module:LicenceModel} licenceId - The UUID of the licence that is being reviewed + * @param {string} reviewLicenceId - The UUID of the licence that is being reviewed * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller * * @returns {Promise} the 'pageData' needed for the review licence page. It contains the licence, bill run, * matched and unmatched returns and the licence charge data */ -async function go (billRunId, licenceId, yar) { - const { billRun, licence } = await FetchReviewLicenceResultsService.go(billRunId, licenceId) +async function go (reviewLicenceId, yar) { + const reviewLicence = await FetchReviewLicenceService.go(reviewLicenceId) const [bannerMessage] = yar.flash('banner') - const pageData = ReviewLicencePresenter.go(billRun, licence) + const pageData = ReviewLicencePresenter.go(reviewLicence) return { bannerMessage, From 459df4295e64532bf6ce2b27ea8f3e0407e35848 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 28 Oct 2024 08:39:51 +0000 Subject: [PATCH 016/147] Move Review chg ref page to '/bill-runs/review' --- app/controllers/bill-runs-review.controller.js | 14 ++++++++++++++ app/controllers/bill-runs.controller.js | 14 -------------- app/routes/bill-runs-review.routes.js | 12 ++++++++++++ app/routes/bill-runs.routes.js | 12 ------------ 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 35b71fcb1a..1adb2e890a 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -5,6 +5,7 @@ * @module BillRunsReviewController */ +const ReviewChargeReferenceService = require('../services/bill-runs/two-part-tariff/charge-reference-details.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/two-part-tariff/review-licence.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') @@ -22,6 +23,18 @@ async function review (request, h) { }) } +async function reviewChargeReference (request, h) { + const { reviewChargeReferenceId } = request.params + + const pageData = await ReviewChargeReferenceService.go(reviewChargeReferenceId, request.yar) + + return h.view('bill-runs/charge-reference-details.njk', { + pageTitle: 'Charge reference details', + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function reviewLicence (request, h) { const { reviewLicenceId } = request.params @@ -51,6 +64,7 @@ async function submitReviewLicence (request, h) { module.exports = { review, + reviewChargeReference, reviewLicence, submitReview, submitReviewLicence diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 0e953fac9a..1cb701f2fb 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -12,7 +12,6 @@ const AmendAuthorisedVolumeService = require('../services/bill-runs/two-part-tar const AmendBillableReturnsService = require('../services/bill-runs/two-part-tariff/amend-billable-returns.service.js') const CalculateChargeService = require('../services/bill-runs/two-part-tariff/calculate-charge.service.js') const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js') -const ChargeReferenceDetailsService = require('../services/bill-runs/two-part-tariff/charge-reference-details.service.js') const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/generate-bill-run.service.js') const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js') @@ -74,18 +73,6 @@ async function cancel (request, h) { }) } -async function chargeReferenceDetails (request, h) { - const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params - - const pageData = await ChargeReferenceDetailsService.go(billRunId, licenceId, reviewChargeReferenceId, request.yar) - - return h.view('bill-runs/charge-reference-details.njk', { - pageTitle: 'Charge reference details', - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function index (request, h) { const { page } = request.query @@ -264,7 +251,6 @@ module.exports = { amendAuthorisedVolume, amendBillableReturns, cancel, - chargeReferenceDetails, index, matchDetails, previewCharge, diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 39d2cd5186..8f40b937be 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -27,6 +27,18 @@ const routes = [ } } }, + { + method: 'GET', + path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}', + options: { + handler: BillRunsReviewController.reviewChargeReference, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/bill-runs/review/licence/{reviewLicenceId}', diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index 71db72b96d..3fc3328282 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -78,18 +78,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}', - options: { - handler: BillRunsController.chargeReferenceDetails, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-authorised-volume', From 67d9efd226ffd5f123333d7e0ac6acb66116555c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 28 Oct 2024 09:29:11 +0000 Subject: [PATCH 017/147] Move Review licence service into review folder --- app/controllers/bill-runs-review.controller.js | 2 +- .../{two-part-tariff => review}/review-licence.service.js | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename app/services/bill-runs/{two-part-tariff => review}/review-licence.service.js (100%) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 1adb2e890a..4776b18306 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -7,7 +7,7 @@ const ReviewChargeReferenceService = require('../services/bill-runs/two-part-tariff/charge-reference-details.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') -const ReviewLicenceService = require('../services/bill-runs/two-part-tariff/review-licence.service.js') +const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') diff --git a/app/services/bill-runs/two-part-tariff/review-licence.service.js b/app/services/bill-runs/review/review-licence.service.js similarity index 100% rename from app/services/bill-runs/two-part-tariff/review-licence.service.js rename to app/services/bill-runs/review/review-licence.service.js From 5ab585ef61eee6fc9761c7c6844b888ef4120555 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 12:22:19 +0000 Subject: [PATCH 018/147] Move, rename and refactor review chg ref presenter --- .../review-charge-reference.presenter.js | 124 +++++++++++++++++ .../charge-reference-details.presenter.js | 126 ------------------ 2 files changed, 124 insertions(+), 126 deletions(-) create mode 100644 app/presenters/bill-runs/review/review-charge-reference.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.js diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js new file mode 100644 index 0000000000..48770f44a4 --- /dev/null +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -0,0 +1,124 @@ +'use strict' + +/** + * Formats the review charge reference data ready for presenting in the review charge reference page + * @module ReviewChargeReferencePresenter + */ + +const Big = require('big.js') + +const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js') + +/** + * Formats the review charge reference data ready for presenting in the review charge reference page + * + * @param {module:ReviewChargeReferenceModel} reviewChargeReference - instance of the `ReviewChargeReferenceModel` + * returned from `FetchReviewChargeReferenceService` + * + * @returns {object} page date needed for the review charge reference page + */ +function go (reviewChargeReference) { + const { + amendedAuthorisedVolume, + chargeReference, + reviewChargeElements, + reviewChargeVersion, + id: reviewChargeReferenceId + } = reviewChargeReference + + return { + additionalCharges: _additionalCharges(chargeReference), + adjustments: _adjustments(reviewChargeReference), + amendedAuthorisedVolume, + canAmend: _canAmend(reviewChargeReference), + chargeCategory: chargeReference.chargeCategory.reference, + chargeDescription: chargeReference.chargeCategory.shortDescription, + chargePeriod: _chargePeriod(reviewChargeVersion), + financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), + reviewChargeReferenceId, + reviewLicenceId: reviewChargeVersion.reviewLicence.id, + totalBillableReturns: _totalAllocated(reviewChargeElements) + } +} + +function _additionalCharges (chargeReference) { + const { supportedSourceName, waterCompanyCharge } = chargeReference + + const additionalCharges = [] + + if (supportedSourceName) { + additionalCharges.push(`Supported source ${supportedSourceName}`) + } + + if (waterCompanyCharge) { + additionalCharges.push('Public Water Supply') + } + + return additionalCharges.join(', ') +} + +function _adjustments (reviewChargeReference) { + const { + abatementAgreement, + aggregate, + amendedAggregate, + amendedChargeAdjustment, + canalAndRiverTrustAgreement, + chargeAdjustment, + twoPartTariffAgreement, + winterDiscount + } = reviewChargeReference + + const adjustments = [] + + if (aggregate !== 1) { + adjustments.push(`Aggregate factor (${amendedAggregate})`) + } + + if (chargeAdjustment !== 1) { + adjustments.push(`Charge adjustment (${amendedChargeAdjustment})`) + } + + if (abatementAgreement !== 1) { + adjustments.push(`Abatement agreement (${abatementAgreement})`) + } + + if (winterDiscount) { + adjustments.push('Winter discount') + } + + if (twoPartTariffAgreement) { + adjustments.push('Two part tariff agreement') + } + + if (canalAndRiverTrustAgreement) { + adjustments.push('Canal and River trust agreement') + } + + return adjustments +} + +function _canAmend (reviewChargeReference) { + const { aggregate, chargeAdjustment } = reviewChargeReference + + return (aggregate !== 1 || chargeAdjustment !== 1) +} + +function _chargePeriod (reviewChargeVersion) { + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion + const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } + + return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` +} + +function _totalAllocated (reviewChargeElements) { + return reviewChargeElements.reduce((total, reviewChargeElement) => { + const { amendedAllocated } = reviewChargeElement + + return Big(total).plus(amendedAllocated).toNumber() + }, 0) +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.js b/app/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.js deleted file mode 100644 index 6c1ce00ff5..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.js +++ /dev/null @@ -1,126 +0,0 @@ -'use strict' - -/** - * Formats the review charge reference data ready for presenting in the charge reference details page - * @module ChargeReferenceDetailsPresenter - */ - -const Big = require('big.js') - -const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') - -/** - * Prepares and processes review charge reference data for presentation - * - * @param {module:BillRunModel} billRun - the data from the bill run - * @param {module:ReviewChargeReference} reviewChargeReference - the data from the review charge reference - * @param {string} licenceId - the UUID of the licence the charge reference is linked to - * - * @returns {object} the prepared bill run and charge reference data to be passed to the charge reference details page - */ -function go (billRun, reviewChargeReference, licenceId) { - const { hasAggregateOrChargeFactor, adjustments } = _adjustments(reviewChargeReference) - - return { - billRunId: billRun.id, - financialYear: formatFinancialYear(billRun.toFinancialYearEnding), - chargePeriod: _prepareDate( - reviewChargeReference.reviewChargeVersion.chargePeriodStartDate, - reviewChargeReference.reviewChargeVersion.chargePeriodEndDate - ), - chargeReference: { - id: reviewChargeReference.id, - reference: reviewChargeReference.chargeReference.chargeCategory.reference, - description: reviewChargeReference.chargeReference.chargeCategory.shortDescription, - totalBillableReturns: _totalBillableReturns(reviewChargeReference.reviewChargeElements), - authorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - adjustments, - additionalCharges: _additionalCharges(reviewChargeReference.chargeReference) - }, - licenceId, - hasAggregateOrChargeFactor - } -} - -function _additionalCharges (chargeReference) { - const { supportedSourceName, waterCompanyCharge } = chargeReference - - const charges = [] - - if (supportedSourceName) { - charges.push(`Supported source ${supportedSourceName}`) - } - - if (waterCompanyCharge) { - charges.push('Public Water Supply') - } - - return charges.join(', ') -} - -function _adjustments (reviewChargeReference) { - const { - aggregate, - amendedAggregate, - chargeAdjustment, - amendedChargeAdjustment, - abatementAgreement, - winterDiscount, - twoPartTariffAgreement, - canalAndRiverTrustAgreement - } = reviewChargeReference - - const adjustments = [] - let hasAggregateOrChargeFactor = false - - if (amendedAggregate !== 1) { - adjustments.push(`Aggregate factor (${amendedAggregate})`) - hasAggregateOrChargeFactor = true - } - - if (amendedChargeAdjustment !== 1) { - adjustments.push(`Charge adjustment (${amendedChargeAdjustment})`) - hasAggregateOrChargeFactor = true - } - - if (abatementAgreement !== 1) { - adjustments.push(`Abatement agreement (${abatementAgreement})`) - } - - if (winterDiscount) { - adjustments.push('Winter discount') - } - - if (twoPartTariffAgreement) { - adjustments.push('Two part tariff agreement') - } - - if (canalAndRiverTrustAgreement) { - adjustments.push('Canal and River trust agreement') - } - - if (aggregate !== amendedAggregate || chargeAdjustment !== amendedChargeAdjustment) { - hasAggregateOrChargeFactor = true - } - - return { adjustments, hasAggregateOrChargeFactor } -} - -function _prepareDate (startDate, endDate) { - const preparedStartDate = formatLongDate(startDate) - const preparedEndDate = formatLongDate(endDate) - - return `${preparedStartDate} to ${preparedEndDate}` -} - -function _totalBillableReturns (reviewChargeElements) { - return reviewChargeElements.reduce((total, reviewChargeElement) => { - total = Big(total).plus(reviewChargeElement.amendedAllocated).toNumber() - - return total - }, 0) -} - -module.exports = { - go -} From 0938c8d855c84eacd19e21f0b93421ed6a87318a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:13:20 +0000 Subject: [PATCH 019/147] Move and refactor Fetch review chg ref service --- .../fetch-review-charge-reference.service.js | 95 +++++++++++++++++++ .../fetch-review-charge-reference.service.js | 72 -------------- 2 files changed, 95 insertions(+), 72 deletions(-) create mode 100644 app/services/bill-runs/review/fetch-review-charge-reference.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js diff --git a/app/services/bill-runs/review/fetch-review-charge-reference.service.js b/app/services/bill-runs/review/fetch-review-charge-reference.service.js new file mode 100644 index 0000000000..5788743697 --- /dev/null +++ b/app/services/bill-runs/review/fetch-review-charge-reference.service.js @@ -0,0 +1,95 @@ +'use strict' + +/** + * Fetches the selected review charge reference instance and related data for the 2PT review charge reference page + * @module FetchReviewChargeReferenceService + */ + +const { ref } = require('objection') + +const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') + +/** + * Fetches the selected review charge reference instance and related data for the 2PT review charge reference page + * + * @param {string} reviewChargeReferenceId - the UUID of the selected review charge reference + * + * @returns {module:ReviewChargeReferenceModel} the matching `ReviewChargeReferenceModel` instance and related data + * needed for the two-part tariff review charge reference page + */ +async function go (reviewChargeReferenceId) { + return _fetch(reviewChargeReferenceId) +} + +async function _fetch (reviewChargeReferenceId) { + return ReviewChargeReferenceModel.query() + .findById(reviewChargeReferenceId) + .select([ + 'id', + 'abatementAgreement', + 'aggregate', + 'amendedAggregate', + 'amendedAuthorisedVolume', + 'amendedChargeAdjustment', + 'canalAndRiverTrustAgreement', + 'chargeAdjustment', + 'twoPartTariffAgreement', + 'winterDiscount' + ]) + .withGraphFetched('reviewChargeVersion') + .modifyGraph('reviewChargeVersion', (builder) => { + builder + .select([ + 'id', + 'chargePeriodStartDate', + 'chargePeriodEndDate' + ]) + .withGraphFetched('reviewLicence') + .modifyGraph('reviewLicence', (builder) => { + builder + .select([ + 'id' + ]) + .withGraphFetched('billRun') + .modifyGraph('billRun', (builder) => { + builder + .select([ + 'id', + 'toFinancialYearEnding' + ]) + }) + }) + }) + .withGraphFetched('reviewChargeElements') + .modifyGraph('reviewChargeElements', (builder) => { + builder + .select([ + 'id', + 'amendedAllocated' + ]) + }) + .withGraphFetched('chargeReference') + .modifyGraph('chargeReference', (builder) => { + builder + .select([ + 'id', + 'volume', + 'chargeCategoryId', + ref('chargeReferences.additionalCharges:supportedSource.name').castText().as('supportedSourceName'), + ref('chargeReferences.additionalCharges:isSupplyPublicWater').castText().as('waterCompanyCharge') + ]) + .withGraphFetched('chargeCategory') + .modifyGraph('chargeCategory', (builder) => { + builder + .select([ + 'id', + 'reference', + 'shortDescription' + ]) + }) + }) +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js b/app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js deleted file mode 100644 index 5c938cd9ca..0000000000 --- a/app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict' - -/** - * Fetches the individual charge reference details during the review stage of a two-part tariff bill run - * @module FetchReviewChargeReferenceService - */ - -const { ref } = require('objection') - -const BillRunModel = require('../../../models/bill-run.model.js') -const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') - -/** - * Fetches the charge reference details for an individual licence - * - * @param {string} billRunId - UUID of the bill run - * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being viewed - * - * @returns {Promise} An object containing the bill run and review charge reference instances - */ -async function go (billRunId, reviewChargeReferenceId) { - const billRun = await _fetchBillRun(billRunId) - const reviewChargeReference = await _fetchReviewChargeReference(reviewChargeReferenceId) - - return { billRun, reviewChargeReference } -} - -async function _fetchBillRun (billRunId) { - return BillRunModel.query() - .findById(billRunId) - .select( - 'id', - 'toFinancialYearEnding') -} - -async function _fetchReviewChargeReference (reviewChargeReferenceId) { - return ReviewChargeReferenceModel.query() - .findById(reviewChargeReferenceId) - .withGraphFetched('chargeReference') - .modifyGraph('chargeReference', (builder) => { - builder.select([ - 'volume', - 'chargeCategoryId', - ref('chargeReferences.additionalCharges:supportedSource.name').castText().as('supportedSourceName'), - ref('chargeReferences.additionalCharges:isSupplyPublicWater').castText().as('waterCompanyCharge') - ]) - }) - .withGraphFetched('chargeReference.chargeCategory') - .modifyGraph('chargeReference.chargeCategory', (builder) => { - builder.select([ - 'reference', - 'shortDescription' - ]) - }) - .withGraphFetched('reviewChargeVersion') - .modifyGraph('reviewChargeVersion', (builder) => { - builder.select([ - 'chargePeriodStartDate', - 'chargePeriodEndDate' - ]) - }) - .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder.select([ - 'amendedAllocated' - ]) - }) -} - -module.exports = { - go -} From e7e77a3d5d42092523dfb7b29b6d184826c3b6a7 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:14:43 +0000 Subject: [PATCH 020/147] Move and refactor review chg ref view --- .../review/review-charge-reference.njk | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 app/views/bill-runs/review/review-charge-reference.njk diff --git a/app/views/bill-runs/review/review-charge-reference.njk b/app/views/bill-runs/review/review-charge-reference.njk new file mode 100644 index 0000000000..afb00c0b42 --- /dev/null +++ b/app/views/bill-runs/review/review-charge-reference.njk @@ -0,0 +1,157 @@ +{% extends 'layout.njk' %} +{% from "govuk/components/back-link/macro.njk" import govukBackLink %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %} +{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %} + +{% block breadcrumbs %} + {# Back link #} + {{ govukBackLink({ + text: 'Go back to licence', + href: '/system/bill-runs/review/licence/' + reviewLicenceId + }) }} +{% endblock %} + +{% block content %} + +{# Adjustment factor ammended banner #} +{% if bannerMessage %} + {{ govukNotificationBanner({ + titleText: 'Adjustment updated', + text: bannerMessage + }) }} +{% endif %} + +{# Charge preview banner #} +{% if chargeMessage %} + {{ govukNotificationBanner({ + titleText: 'Information', + text: chargeMessage + }) }} +{% endif %} + +{# Title area #} +
+
+

+ Charge reference {{chargeCategory}}{{chargeDescription}} +

+ Financial Year {{financialPeriod}} +

+ Charge period {{chargePeriod}} +

+
+
+ +{# Return numbers ML #} +
+
+
+

+ {{totalBillableReturns}} ML +
+ Total billable returns +
+

+
+
+

+ / +

+
+
+

+ {{amendedAuthorisedVolume}} ML +
+ Authorised volume +
+

+
+
+
+ +{# Buttons #} +
+
+ {% if canAmend %} + + {{ govukButton({ + text: "Change the authorised volume", + classes: "govuk-button--secondary", + preventDoubleClick: true, + href: "/system/bill-runs/charge-reference/" + reviewChargeReferenceId + "/authorised" + }) }} + + {% endif %} + + + {{ govukButton({ + text: "Preview the charge", + classes: "govuk-button--secondary", + preventDoubleClick: true, + href: "/system/bill-runs/charge-reference/" + reviewChargeReferenceId + "/preview" + }) }} + +
+
+ +{# Reference details #} +{% if additionalCharges or adjustments.length > 0 %} +
+
+

Reference details

+ + {% set adjustmentsValue %} + {% for adjustment in adjustments %} + {% set adjustmentsIndex = loop.index0 %} +
{{adjustment}}
+ {% endfor %} + {% endset %} + + {% if canAmend %} + {% set showLink = { + items: [{ + href: "/system/bill-runs/charge-reference/" + reviewChargeReferenceId + "/factors", + text: "Change factors" + }] + } + %} + {% endif %} + + {% set tableRows = [] %} + {% if additionalCharges %} + {% set tableRow = { + key: { + text: "Additional charges" + }, + value: { + html: '
' + additionalCharges + '
' + } + } + %} + + {% set tableRows = (tableRows.push(tableRow), tableRows) %} + {% endif %} + + {% if adjustments %} + {% set tableRow = { + key: { + text: "Adjustments" + }, + value: { + html: adjustmentsValue + }, + actions: showLink + } + %} + + {% set tableRows = (tableRows.push(tableRow), tableRows) %} + {% endif %} + + {{ govukSummaryList({ + rows: tableRows + }) }} +

+
+{% endif %} +{% endblock %} From d0ad2797cf71a07ca30cfdebd91ff5d68dc308ba Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:20:26 +0000 Subject: [PATCH 021/147] Move, rename and refactor Review chg ref service --- .../review/review-charge-reference.service.js | 38 ++++++++++++++++ .../charge-reference-details.service.js | 43 ------------------- 2 files changed, 38 insertions(+), 43 deletions(-) create mode 100644 app/services/bill-runs/review/review-charge-reference.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/charge-reference-details.service.js diff --git a/app/services/bill-runs/review/review-charge-reference.service.js b/app/services/bill-runs/review/review-charge-reference.service.js new file mode 100644 index 0000000000..7bf3846d31 --- /dev/null +++ b/app/services/bill-runs/review/review-charge-reference.service.js @@ -0,0 +1,38 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data needed for the review charge reference page + * @module ReviewChargeReferenceService + */ + +const FetchReviewChargeReferenceService = require('../review/fetch-review-charge-reference.service.js') +const ReviewChargeReferencePresenter = require('../../../presenters/bill-runs/review/review-charge-reference.presenter.js') + +/** + * Orchestrates fetching and presenting the data needed for the review charge reference page + * + * @param {string} reviewChargeReferenceId - The UUID of the charge reference being reviewed + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * + * @returns {Promise} the 'pageData' needed for the review charge reference page. It contains details of the + * bill run, charge reference and the charge adjustments + */ +async function go (reviewChargeReferenceId, yar) { + const reviewChargeReference = await FetchReviewChargeReferenceService.go(reviewChargeReferenceId) + + const [bannerMessage] = yar.flash('banner') + const [chargeMessage] = yar.flash('charge') + + const pageData = ReviewChargeReferencePresenter.go(reviewChargeReference) + + return { + pageTitle: 'Charge reference details', + bannerMessage, + chargeMessage, + ...pageData + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/charge-reference-details.service.js b/app/services/bill-runs/two-part-tariff/charge-reference-details.service.js deleted file mode 100644 index f57976fe18..0000000000 --- a/app/services/bill-runs/two-part-tariff/charge-reference-details.service.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict' - -/** - * Orchestrates fetching and presenting the data needed for the charge reference details page in a two-part tariff bill - * run - * @module ChargeReferenceDetailsService - */ - -const ChargeReferenceDetailsPresenter = require('../../../presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.js') -const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') - -/** - * Orchestrates fetching and presenting the data needed for the charge reference details page in a two-part tariff bill - * run - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeReferenceId - The UUID of the charge reference being reviewed - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - * - * @returns {Promise} the 'pageData' needed for the review charge reference page. It contains details of the - * bill run, charge reference and the charge adjustments - */ -async function go (billRunId, licenceId, reviewChargeReferenceId, yar) { - const { - billRun, - reviewChargeReference - } = await FetchReviewChargeReferenceService.go(billRunId, reviewChargeReferenceId) - - const [bannerMessage] = yar.flash('banner') - const [chargeMessage] = yar.flash('charge') - const pageData = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - return { - bannerMessage, - chargeMessage, - ...pageData - } -} - -module.exports = { - go -} From eb699e90ba6cc443709fda1a25a950d5a22ab3f0 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:20:52 +0000 Subject: [PATCH 022/147] Update Bill Runs Review controller with changes --- app/controllers/bill-runs-review.controller.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 4776b18306..e64ee816da 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -5,7 +5,7 @@ * @module BillRunsReviewController */ -const ReviewChargeReferenceService = require('../services/bill-runs/two-part-tariff/charge-reference-details.service.js') +const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') @@ -28,8 +28,7 @@ async function reviewChargeReference (request, h) { const pageData = await ReviewChargeReferenceService.go(reviewChargeReferenceId, request.yar) - return h.view('bill-runs/charge-reference-details.njk', { - pageTitle: 'Charge reference details', + return h.view('bill-runs/review/review-charge-reference.njk', { activeNavBar: 'bill-runs', ...pageData }) From 9753eb7952fb631d171e736cd3f0dbd71240e14a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:21:48 +0000 Subject: [PATCH 023/147] Housekeeping - add missing JSDoc comments --- .../bill-runs/review/fetch-review-licence.service.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/fetch-review-licence.service.js b/app/services/bill-runs/review/fetch-review-licence.service.js index 64fe32fd80..4dd3c8aa8a 100644 --- a/app/services/bill-runs/review/fetch-review-licence.service.js +++ b/app/services/bill-runs/review/fetch-review-licence.service.js @@ -1,7 +1,7 @@ 'use strict' /** - * Fetches the individual review licence data for a two-part tariff bill run + * Fetches the selected review licence instance and related data for the two-part tariff review licence page * @module FetchReviewLicenceService */ @@ -9,6 +9,14 @@ const { ref } = require('objection') const ReviewLicenceModel = require('../../../models/review-licence.model.js') +/** + * Fetches the selected review licence instance and associated data for the two-part tariff review licence page + * + * @param {string} reviewLicenceId - the UUID of the selected review licence + * + * @returns {module:ReviewLicenceModel} the matching `ReviewLicenceModel` instance and related data needed for the + * two-part tariff review licence page + */ async function go (reviewLicenceId) { return _fetch(reviewLicenceId) } From 7c97b15205ccae07f66efc7a0b4369f84c01d0d8 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:22:13 +0000 Subject: [PATCH 024/147] Housekeeping - update reference to module --- app/services/bill-runs/review/review-licence.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/review-licence.service.js b/app/services/bill-runs/review/review-licence.service.js index 6c1aa1837a..71e32ce152 100644 --- a/app/services/bill-runs/review/review-licence.service.js +++ b/app/services/bill-runs/review/review-licence.service.js @@ -5,7 +5,7 @@ * @module ReviewLicenceService */ -const FetchReviewLicenceService = require('../review/fetch-review-licence.service.js') +const FetchReviewLicenceService = require('./fetch-review-licence.service.js') const ReviewLicencePresenter = require('../../../presenters/bill-runs/review/review-licence.presenter.js') /** From bf81f8ee433c03f1aa2db73724c5d2ca450e5594 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 13:22:45 +0000 Subject: [PATCH 025/147] Housekeeping - refactor to use existing lib method --- .../bill-runs/review/review-licence.presenter.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index 668e35bdeb..4477f0a338 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -7,7 +7,7 @@ const Big = require('big.js') -const { formatAbstractionPeriod, formatLongDate } = require('../../base.presenter.js') +const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') /** @@ -163,7 +163,7 @@ function _chargeVersions (reviewChargeVersions, toFinancialYearEnding) { chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, chargeReferences: _chargeReferences(reviewChargeReferences, chargePeriod), description: _chargeVersionDescription(reviewChargeReferences), - financialPeriod: _financialYear(toFinancialYearEnding) + financialPeriod: formatFinancialYear(toFinancialYearEnding) } }) } @@ -184,13 +184,6 @@ function _elementsInReview (reviewChargeVersions) { }) } -function _financialYear (financialYearEnding) { - const startYear = financialYearEnding - 1 - const endYear = financialYearEnding - - return `${startYear} to ${endYear}` -} - function _formatReviewReturns (reviewReturns) { const matchedReturns = [] const unmatchedReturns = [] From b1f4b71c3190d7e1b0ec65d2cabffe394b6ab467 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:45:46 +0000 Subject: [PATCH 026/147] Move chg ref factors page to /bill-runs/review --- app/routes/bill-runs-review.routes.js | 24 ++++++++++++++++++++++++ app/routes/bill-runs.routes.js | 24 ------------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 8f40b937be..2625538b20 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -39,6 +39,30 @@ const routes = [ } } }, + { + method: 'GET', + path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}/factors', + options: { + handler: BillRunsReviewController.factors, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}/factors', + options: { + handler: BillRunsReviewController.submitFactors, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/bill-runs/review/licence/{reviewLicenceId}', diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index 3fc3328282..1ea06b52b6 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -102,30 +102,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-adjustment-factor', - options: { - handler: BillRunsController.amendAdjustmentFactor, - auth: { - access: { - scope: ['billing'] - } - } - } - }, - { - method: 'POST', - path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-adjustment-factor', - options: { - handler: BillRunsController.submitAmendedAdjustmentFactor, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}', From 614f17672e947df7dbf986ed8722bd02096fed4c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:46:50 +0000 Subject: [PATCH 027/147] Move, rename and refactor chg ref factors presenter --- .../bill-runs/review/factors.presenter.js | 95 +++++++++++++++++++ .../amend-adjustment-factor.presenter.js | 79 --------------- 2 files changed, 95 insertions(+), 79 deletions(-) create mode 100644 app/presenters/bill-runs/review/factors.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js new file mode 100644 index 0000000000..b025966308 --- /dev/null +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -0,0 +1,95 @@ +'use strict' + +/** + * Formats the review charge reference data ready for presenting in the review charge reference factors page + * @module AmendAdjustmentFactorPresenter + */ + +const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') + +/** + * Formats the review charge reference data ready for presenting in the review charge reference factors page + * + * @param {module:ReviewChargeReference} reviewChargeReference - instance of the `ReviewChargeReferenceModel` + * returned from `FetchReviewChargeReferenceService` + * + * @returns {object} page date needed for the review charge reference factors page + */ +function go (reviewChargeReference) { + const { + amendedAggregate, + amendedChargeAdjustment, + chargeReference, + reviewChargeVersion, + id: reviewChargeReferenceId + } = reviewChargeReference + + const additionalCharges = _additionalCharges(chargeReference) + const adjustments = _adjustments(reviewChargeReference) + + return { + amendedAggregate, + amendedChargeAdjustment, + otherAdjustments: [...additionalCharges, ...adjustments], + chargeDescription: chargeReference.chargeCategory.shortDescription, + chargePeriod: _chargePeriod(reviewChargeVersion), + financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), + reviewChargeReferenceId + } +} + +function _additionalCharges (chargeReference) { + const { supportedSourceName, waterCompanyCharge } = chargeReference + + const additionalCharges = [] + + if (supportedSourceName) { + additionalCharges.push(`Supported source ${supportedSourceName}`) + } + + if (waterCompanyCharge) { + additionalCharges.push('Public Water Supply') + } + + return additionalCharges +} + +function _adjustments (reviewChargeReference) { + const { + abatementAgreement, + canalAndRiverTrustAgreement, + twoPartTariffAgreement, + winterDiscount + } = reviewChargeReference + + const adjustments = [] + + if (abatementAgreement !== 1) { + adjustments.push(`Abatement agreement (${abatementAgreement})`) + } + + if (winterDiscount) { + adjustments.push('Winter discount') + } + + if (twoPartTariffAgreement) { + adjustments.push('Two part tariff agreement') + } + + if (canalAndRiverTrustAgreement) { + adjustments.push('Canal and River trust agreement') + } + + return adjustments +} + +function _chargePeriod (reviewChargeVersion) { + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion + const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } + + return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js b/app/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js deleted file mode 100644 index 8ba3294158..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict' - -/** - * Formats the two part tariff review data ready for presenting in the amend adjustment factor page - * @module AmendAdjustmentFactorPresenter - */ - -const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') - -/** - * Prepares and processes bill run and review charge reference data for presenting - * - * @param {module:BillRunModel} billRun - the data from the bill run - * @param {module:ReviewChargeReference} reviewChargeReference - the data from the review charge reference - * @param {string} licenceId - the UUID of the licence being reviewed - * - * @returns {object} the prepared bill run and charge reference data to be passed to the amend adjustment factor page - */ -function go (billRun, reviewChargeReference, licenceId) { - return { - billRunId: billRun.id, - licenceId, - financialYear: formatFinancialYear(billRun.toFinancialYearEnding), - chargePeriod: _prepareDate( - reviewChargeReference.reviewChargeVersion.chargePeriodStartDate, - reviewChargeReference.reviewChargeVersion.chargePeriodEndDate - ), - chargeReference: { - id: reviewChargeReference.id, - description: reviewChargeReference.chargeReference.chargeCategory.shortDescription, - aggregateFactor: reviewChargeReference.amendedAggregate === 0 ? '0' : reviewChargeReference.amendedAggregate, - chargeAdjustment: reviewChargeReference.amendedChargeAdjustment === 0 ? '0' : reviewChargeReference.amendedChargeAdjustment, - otherAdjustments: _otherAdjustments(reviewChargeReference) - } - } -} - -function _otherAdjustments (reviewChargeReference) { - const { supportedSourceName, waterCompanyCharge } = reviewChargeReference.chargeReference - - const adjustments = [] - - if (supportedSourceName) { - adjustments.push(`Supported source ${supportedSourceName}`) - } - - if (waterCompanyCharge) { - adjustments.push('Public Water Supply') - } - - if (reviewChargeReference.abatementAgreement !== 1) { - adjustments.push(`Abatement agreement (${reviewChargeReference.abatementAgreement})`) - } - - if (reviewChargeReference.winterDiscount) { - adjustments.push('Winter discount') - } - - if (reviewChargeReference.twoPartTariffAgreement) { - adjustments.push('Two part tariff agreement') - } - - if (reviewChargeReference.canalAndRiverTrustAgreement) { - adjustments.push('Canal and River trust agreement') - } - - return adjustments -} - -function _prepareDate (startDate, endDate) { - const preparedStartDate = formatLongDate(startDate) - const preparedEndDate = formatLongDate(endDate) - - return `${preparedStartDate} to ${preparedEndDate}` -} - -module.exports = { - go -} From b465d56b2217d84fc773a551123933a1456a398b Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:47:28 +0000 Subject: [PATCH 028/147] Move, rename & refactor chg ref factors service --- .../bill-runs/review/factors.service.js | 31 +++++++++++++++++ .../amend-adjustment-factor.service.js | 33 ------------------- 2 files changed, 31 insertions(+), 33 deletions(-) create mode 100644 app/services/bill-runs/review/factors.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js diff --git a/app/services/bill-runs/review/factors.service.js b/app/services/bill-runs/review/factors.service.js new file mode 100644 index 0000000000..6ff2d33a77 --- /dev/null +++ b/app/services/bill-runs/review/factors.service.js @@ -0,0 +1,31 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data needed for the review charge reference factors page + * @module FactorsService + */ + +const FactorsPresenter = require('../../../presenters/bill-runs/review/factors.presenter.js') +const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') + +/** + * Orchestrates fetching and presenting the data needed for the review charge reference factors page + * + * @param {string} reviewChargeReferenceId - The UUID of the review charge reference whose factors are being amended + * + * @returns {Promise} the 'pageData' needed for the review charge reference factors page + */ +async function go (reviewChargeReferenceId) { + const reviewChargeReference = await FetchReviewChargeReferenceService.go(reviewChargeReferenceId) + + const pageData = FactorsPresenter.go(reviewChargeReference) + + return { + pageTitle: 'Set the adjustment factors', + ...pageData + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js b/app/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js deleted file mode 100644 index c2ebd95a71..0000000000 --- a/app/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict' - -/** - * Orchestrates fetching and presenting the data needed for the amend adjustment factor page - * @module AmendAdjustmentFactorService - */ - -const AmendAdjustmentFactorPresenter = require('../../../presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js') -const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') - -/** - * Orchestrates fetching and presenting the data needed for the amend adjustment factor page - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being viewed - * - * @returns {Promise} the 'pageData' needed to view the amend adjustment factor page - */ -async function go (billRunId, licenceId, reviewChargeReferenceId) { - const { - billRun, - reviewChargeReference - } = await FetchReviewChargeReferenceService.go(billRunId, reviewChargeReferenceId) - - const pageData = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - return pageData -} - -module.exports = { - go -} From 31130194c708484b5cb4fac02d12c6665e5ff28c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:48:08 +0000 Subject: [PATCH 029/147] Move, rename, and refactor chg ref factors view --- app/views/bill-runs/review/factors.njk | 92 ++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 app/views/bill-runs/review/factors.njk diff --git a/app/views/bill-runs/review/factors.njk b/app/views/bill-runs/review/factors.njk new file mode 100644 index 0000000000..7d7a210462 --- /dev/null +++ b/app/views/bill-runs/review/factors.njk @@ -0,0 +1,92 @@ +{% extends 'layout.njk' %} +{% from "govuk/components/back-link/macro.njk" import govukBackLink %} +{% from "govuk/components/inset-text/macro.njk" import govukInsetText %} +{% from "govuk/components/input/macro.njk" import govukInput %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from 'govuk/components/error-summary/macro.njk' import govukErrorSummary %} + +{% block breadcrumbs %} + {# Back link #} + {{ govukBackLink({ + text: 'Go back to charge reference', + href: '/system/bill-runs/review/charge-reference/' + reviewChargeReferenceId + }) }} +{% endblock %} + +{% block content %} +
+
+ + {% set errorList %} +
{{error.aggregateFactorElement.text}}
+
{{error.chargeAdjustmentElement.text}}
+ {% endset %} + + {% if error %} + {{ govukErrorSummary({ + titleText: 'There is a problem', + errorList: error.errorList + }) }} + {% endif %} + + {# Title #} +

+ {{chargeDescription}} + {{pageTitle}} +

+ Financial Year {{financialPeriod}} +

+ Charge period {{chargePeriod}} +

+ + {# Inset section #} + {% if otherAdjustments.length > 0 %} + {% set insertText %} +

Other adjustments apply:

+ {% for otherAdjustment in otherAdjustments %} +
{{otherAdjustment}}
+ {% endfor %} + {% endset %} + + {{ govukInsetText({ + html: insertText + }) }} + {% endif %} + + {# Input fields #} +
+ + + {{ govukInput({ + label: { + text: "Aggregate factor", + classes: "govuk-label" + }, + id: "amended-aggregate", + name: "amendedAggregate", + classes: "govuk-input--width-10", + value: amendedAggregate, + errorMessage: { + text: error.amendedAggregate.message + } if error.amendedAggregate + }) }} + + {{ govukInput({ + label: { + text: "Charge adjustment", + classes: "govuk-label" + }, + id: "amended-charge-adjustment", + name: "amendedChargeAdjustment", + classes: "govuk-input--width-10", + value: amendedChargeAdjustment, + errorMessage: { + text: error.amendedChargeAdjustment.message + } if error.amendedChargeAdjustment + }) }} + + {{ govukButton({ text: 'Confirm', preventDoubleClick: true }) }} +
+
+
+{% endblock %} From af9c23b8ddb55e995d97c5b28e276d6db8a26e79 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:48:51 +0000 Subject: [PATCH 030/147] Move, rename and refactor chg ref factors validator --- .../bill-runs/review/factors.validator.js | 81 +++++++++++++++++ .../adjustment-factor.validator.js | 89 ------------------- 2 files changed, 81 insertions(+), 89 deletions(-) create mode 100644 app/validators/bill-runs/review/factors.validator.js delete mode 100644 app/validators/bill-runs/two-part-tariff/adjustment-factor.validator.js diff --git a/app/validators/bill-runs/review/factors.validator.js b/app/validators/bill-runs/review/factors.validator.js new file mode 100644 index 0000000000..40429e3bac --- /dev/null +++ b/app/validators/bill-runs/review/factors.validator.js @@ -0,0 +1,81 @@ +'use strict' + +/** + * Validates data submitted for the review charge reference factors page + * @module FactorsValidator + */ + +const Joi = require('joi') + +/** + * Validates data submitted for the review charge reference factors page + * + * @param {object} payload - The payload from the request to be validated + * + * @returns {object} The result from calling Joi's schema.validate(). If any errors are found the `error:` property will + * also exist detailing what the issue is. + */ +function go (payload) { + const schema = Joi.object({ + amendedAggregate: Joi + .number() + .min(0) + .required() + .custom(_maxDecimals, 'Max decimals') + .messages({ + 'number.base': 'The aggregate factor must be a number', + 'number.unsafe': 'The aggregate factor must be a number', + 'number.min': 'The aggregate factor must be greater than 0', + 'any.required': 'Enter an aggregate factor', + 'any.invalid': 'The aggregate factor must not have more than 15 decimal places' + }), + amendedChargeAdjustment: Joi + .number() + .min(0) + .required() + .custom(_maxDecimals, 'Max decimals') + .messages({ + 'number.base': 'The charge factor must be a number', + 'number.unsafe': 'The charge factor must be a number', + 'number.min': 'The charge factor must be greater than 0', + 'any.required': 'Enter a charge factor', + 'any.invalid': 'The charge factor must not have more than 15 decimal places' + }) + }) + + return schema.validate(payload, { abortEarly: false }) +} + +/** + * Custom JOI validator to check a value does not have more than 15 decimal places + * + * We are limited to 15 decimals by the Rules Service that will eventually be called to calculate the charge. Due to + * limitations in Joi validation for decimals, achieving validation for numbers with more than 15 decimal places + * requires a custom approach. + * + * See {@link https://github.com/hapijs/joi/blob/master/API.md#anycustommethod-description | Joi custom validation}. + * + * @param {number} value - the value to be validated + * @param {object} helpers - a Joi object containing a numbers of helpers + * + * @returns {number|object} if valid the original value else a Joi 'any.invalid' error. Knowing we return this means + * you can assign what error message to use when a number has too many decimals. + */ +function _maxDecimals (value, helpers) { + // Guard clause to ensure we don't try and interact with a null or undefined value + if (!value) { + return value + } + + const parts = value.toString().split('.') + + if (parts.length === 1 || parts[1].length <= 15) { + return value + } + + return helpers.error('any.invalid') +} + +module.exports = { + go +} diff --git a/app/validators/bill-runs/two-part-tariff/adjustment-factor.validator.js b/app/validators/bill-runs/two-part-tariff/adjustment-factor.validator.js deleted file mode 100644 index 0b390c436c..0000000000 --- a/app/validators/bill-runs/two-part-tariff/adjustment-factor.validator.js +++ /dev/null @@ -1,89 +0,0 @@ -'use strict' - -/** - * Validates data submitted for the `/bill-runs/{billRunId}/review/{licenceId}/charge-reference-details/ - * {reviewChargeReferenceId}/amend-adjustment-factor` page - * @module AdjustmentFactorValidator - */ - -const Joi = require('joi') - -/** - * Validates data submitted for the `/bill-runs/{billRunId}/review/{licenceId}/charge-reference-details/ - * {reviewChargeReferenceId}/amend-adjustment-factor` page - * - * When editing the aggregate factor or the charge adjustment on the charge reference, the user input boxes are - * pre-populated with the current value for both. The user must overwrite this value with there own value to amend the - * adjustments. - * The validation happening here is to ensure that the adjustments have been entered. Both have a - * minimum value of 0 and they both get validated to either 2 or 15 decimal places. - * - * @param {object} payload - The payload from the request to be validated - * @param {number} maxNumberOfDecimals - The maximum number of decimal places the factor can be validated to - * @param {string} validationType - The type of factor being validated, this is to add to the validation messages - * - * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If - * any errors are found the `error:` property will also exist detailing what the issues were - */ -function go (payload, maxNumberOfDecimals, validationType) { - return _validate(payload, maxNumberOfDecimals, validationType) -} - -/** - * Due to limitations in Joi validation for decimals, achieving validation for numbers with fewer than 2 or 15 decimal - * places requires a custom approach. First, convert the number into a string. Then split the string into an array using - * the decimal point (`.`) as the delimiter. This results in either one item in the array (if no decimal is present) or - * two items (if a decimal is present). The first item represents the part before the decimal, while the second item - * represents the part after. By assessing if the length of the second string is less than 3 or 16, we can validate if - * there the correct number of decimals. - * - * @private - */ -function _customValidation (quantity, helpers, maxNumberOfDecimals, validationType) { - const quantityParts = quantity.toString().split('.') - - if (quantityParts.length === 1 || quantityParts[1].length <= maxNumberOfDecimals) { - return quantity - } - - return helpers.message({ - custom: `The ${validationType} factor must not have more than ${maxNumberOfDecimals} decimal places` - }) -} - -function _validate (quantity, maxNumberOfDecimals, validationType) { - const schema = Joi.object({ - quantity: Joi - .number() - .min(0) - .required() - .messages({ - 'number.base': `The ${validationType} factor must be a number`, - 'number.unsafe': `The ${validationType} factor must be a number`, - 'number.min': `The ${validationType} factor must be greater than 0`, - 'any.required': `Enter a ${validationType} factor` - }) - }) - - const validation = schema.validate({ quantity }, { abortEarly: false }) - - // The first check we are doing is validating that a number has been inputted. If it is a number then we can move onto - // checking if there are a valid number of decimal places - if (!validation.error) { - return _validateDecimals(quantity, maxNumberOfDecimals, validationType) - } - - return validation -} - -function _validateDecimals (quantity, maxNumberOfDecimals, validationType) { - const decimalSchema = Joi.number().custom((value, helpers) => { - return _customValidation(value, helpers, maxNumberOfDecimals, validationType) - }) - - return decimalSchema.validate(quantity) -} - -module.exports = { - go -} From 257497d2dae63f6aa2d3b5fbd31202a63f1dcb25 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:49:20 +0000 Subject: [PATCH 031/147] Move, rename & refactor chg ref factors submit --- .../review/submit-factors.service.js | 88 ++++++++++++++++++ ...ubmit-amended-adjustment-factor.service.js | 91 ------------------- 2 files changed, 88 insertions(+), 91 deletions(-) create mode 100644 app/services/bill-runs/review/submit-factors.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js diff --git a/app/services/bill-runs/review/submit-factors.service.js b/app/services/bill-runs/review/submit-factors.service.js new file mode 100644 index 0000000000..5467046156 --- /dev/null +++ b/app/services/bill-runs/review/submit-factors.service.js @@ -0,0 +1,88 @@ +'use strict' + +/** + * Handles user submission for the review charge reference factors page + * @module SubmitAmendedAdjustmentFactorService + */ + +const FactorsPresenter = require('../../../presenters/bill-runs/review/factors.presenter.js') +const FactorsValidator = require('../../../validators/bill-runs/review/factors.validator.js') +const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') +const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') + +/** + * Handles user submission for the review charge reference factors page + * + * It first validates the payload of the submitted request. + * + * If there is no validation error it will save the selected value to the review charge reference then return an empty + * object. This will indicate to the controller that the submission was successful triggering it to redirect back to the + * review charge reference page. + * + * If there is a validation error it is combined with the output of the presenter to generate the page data needed to + * re-render the view with an error message. + * + * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being updated + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * @param {object} payload - The submitted form data + * + * @returns {Promise} An empty object if there are no errors else the page data for the type page including the + * validation error details + */ +async function go (reviewChargeReferenceId, yar, payload) { + const validationResult = _validate(payload) + + if (!validationResult) { + await _save(reviewChargeReferenceId, payload) + yar.flash('banner', 'The adjustment factors for this licence have been updated') + + return {} + } + + const reviewChargeReference = await FetchReviewChargeReferenceService.go(reviewChargeReferenceId) + const pageData = FactorsPresenter.go(reviewChargeReference) + + return { + activeNavBar: 'search', + error: validationResult, + pageTitle: 'Set the adjustment factors', + ...pageData, + amendedAggregate: payload.amendedAggregate, + amendedChargeAdjustment: payload.amendedChargeAdjustment + } +} + +async function _save (reviewChargeReferenceId, payload) { + return ReviewChargeReferenceModel.query() + .findById(reviewChargeReferenceId) + .patch(payload) +} + +function _validate (payload) { + const validation = FactorsValidator.go(payload) + + if (!validation.error) { + return null + } + + const result = { + errorList: [] + } + + validation.error.details.forEach((detail) => { + const href = detail.context.key === 'amendedAggregate' ? '#amended-aggregate' : '#amended-charge-adjustment' + + result.errorList.push({ + href, + text: detail.message + }) + + result[detail.context.key] = { message: detail.message } + }) + + return result +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js b/app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js deleted file mode 100644 index 2ace5e35a9..0000000000 --- a/app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict' - -/** - * Orchestrates validating and patching the data for the amend adjustment factors page - * @module SubmitAmendedAdjustmentFactorService -*/ - -const AdjustmentFactorValidator = require('../../../validators/bill-runs/two-part-tariff/adjustment-factor.validator.js') -const AmendAdjustmentFactorPresenter = require('../../../presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js') -const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') -const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') - -/** - * Orchestrates validating the data for the amend adjustment factor page and patching the db value - - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being updated - * @param {object} payload - The submitted form data - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - * - * @returns {Promise} The updated value for the adjustment factor - */ -async function go (billRunId, licenceId, reviewChargeReferenceId, payload, yar) { - const validationResult = _validate(payload) - - if (!validationResult) { - await _persistAmendedAdjustmentFactor(reviewChargeReferenceId, payload) - yar.flash('banner', 'The adjustment factors for this licence have been updated') - - return { error: null } - } - - const pageData = await _getPageData(billRunId, reviewChargeReferenceId, licenceId) - - return { - activeNavBar: 'search', - pageTitle: 'Set the adjustment factors', - error: validationResult, - inputtedAggregateValue: payload.amendedAggregateFactor, - inputtedChargeValue: payload.amendedChargeAdjustment, - ...pageData - } -} - -async function _getPageData (billRunId, reviewChargeReferenceId, licenceId) { - const { - billRun, - reviewChargeReference - } = await FetchReviewChargeReferenceService.go(billRunId, reviewChargeReferenceId) - - return AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) -} - -async function _persistAmendedAdjustmentFactor (reviewChargeReferenceId, payload) { - await ReviewChargeReferenceModel.query() - .findById(reviewChargeReferenceId) - .patch({ amendedAggregate: payload.amendedAggregateFactor }) - - await ReviewChargeReferenceModel.query() - .findById(reviewChargeReferenceId) - .patch({ amendedChargeAdjustment: payload.amendedChargeAdjustment }) -} - -function _validate (payload) { - const maxDecimalsForAggregateValue = 15 - const maxDecimalsForChargeAdjustmentValue = 15 - - const aggregateValidation = AdjustmentFactorValidator.go( - payload.amendedAggregateFactor, - maxDecimalsForAggregateValue, - 'aggregate') - - const chargeValidation = AdjustmentFactorValidator.go( - payload.amendedChargeAdjustment, - maxDecimalsForChargeAdjustmentValue, - 'charge') - - if (!aggregateValidation.error && !chargeValidation.error) { - return null - } - - return { - aggregateFactorElement: aggregateValidation.error ? { text: aggregateValidation.error.details[0].message } : null, - chargeAdjustmentElement: chargeValidation.error ? { text: chargeValidation.error.details[0].message } : null - } -} - -module.exports = { - go -} From c90ba101b22e6bd739fd2738d19de6f57afa719a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:50:24 +0000 Subject: [PATCH 032/147] Update chg ref factors controllers --- .../bill-runs-review.controller.js | 26 +++++++++++++++ app/controllers/bill-runs.controller.js | 33 ------------------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index e64ee816da..077e847679 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -5,12 +5,25 @@ * @module BillRunsReviewController */ +const FactorsService = require('../services/bill-runs/review/factors.service.js') const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') +const SubmitFactorsService = require('../services/bill-runs/review/submit-factors.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') +async function factors (request, h) { + const { reviewChargeReferenceId } = request.params + + const pageData = await FactorsService.go(reviewChargeReferenceId) + + return h.view('bill-runs/review/factors.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function review (request, h) { const { id } = request.params const { page } = request.query @@ -45,6 +58,17 @@ async function reviewLicence (request, h) { }) } +async function submitFactors (request, h) { + const { reviewChargeReferenceId } = request.params + const pageData = await SubmitFactorsService.go(reviewChargeReferenceId, request.yar, request.payload) + + if (pageData.error) { + return h.view('bill-runs/review/factors.njk', pageData) + } + + return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) +} + async function submitReview (request, h) { const { id } = request.params @@ -62,9 +86,11 @@ async function submitReviewLicence (request, h) { } module.exports = { + factors, review, reviewChargeReference, reviewLicence, + submitFactors, submitReview, submitReviewLicence } diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 1cb701f2fb..1ff9d6e9d0 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -7,7 +7,6 @@ const Boom = require('@hapi/boom') -const AmendAdjustmentFactorService = require('../services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js') const AmendAuthorisedVolumeService = require('../services/bill-runs/two-part-tariff/amend-authorised-volume.service.js') const AmendBillableReturnsService = require('../services/bill-runs/two-part-tariff/amend-billable-returns.service.js') const CalculateChargeService = require('../services/bill-runs/two-part-tariff/calculate-charge.service.js') @@ -17,7 +16,6 @@ const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.serv const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js') const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') -const SubmitAmendedAdjustmentFactorService = require('../services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js') const SubmitAmendedAuthorisedVolumeService = require('../services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js') const SubmitAmendedBillableReturnsService = require('..//services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../services/bill-runs/submit-cancel-bill-run.service.js') @@ -25,18 +23,6 @@ const SubmitRemoveBillRunLicenceService = require('../services/bill-runs/two-par const SubmitSendBillRunService = require('../services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../services/bill-runs/view-bill-run.service.js') -async function amendAdjustmentFactor (request, h) { - const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params - - const pageData = await AmendAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReferenceId) - - return h.view('bill-runs/amend-adjustment-factor.njk', { - pageTitle: 'Set the adjustment factors', - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function amendAuthorisedVolume (request, h) { const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params @@ -127,23 +113,6 @@ async function send (request, h) { }) } -async function submitAmendedAdjustmentFactor (request, h) { - const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params - const pageData = await SubmitAmendedAdjustmentFactorService.go( - billRunId, - licenceId, - reviewChargeReferenceId, - request.payload, - request.yar - ) - - if (pageData.error) { - return h.view('bill-runs/amend-adjustment-factor.njk', pageData) - } - - return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}/charge-reference-details/${reviewChargeReferenceId}`) -} - async function submitAmendedAuthorisedVolume (request, h) { const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params const pageData = await SubmitAmendedAuthorisedVolumeService.go( @@ -247,7 +216,6 @@ async function view (request, h) { } module.exports = { - amendAdjustmentFactor, amendAuthorisedVolume, amendBillableReturns, cancel, @@ -256,7 +224,6 @@ module.exports = { previewCharge, removeLicence, send, - submitAmendedAdjustmentFactor, submitAmendedAuthorisedVolume, submitAmendedBillableReturns, submitCancel, From c8cf931fb15a2bea621aefb22a62e1540dd29415 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 29 Oct 2024 23:50:47 +0000 Subject: [PATCH 033/147] Housekeeping - fix indenting in view --- .../bill-runs/review/review-charge-reference.njk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/bill-runs/review/review-charge-reference.njk b/app/views/bill-runs/review/review-charge-reference.njk index afb00c0b42..0189b907c3 100644 --- a/app/views/bill-runs/review/review-charge-reference.njk +++ b/app/views/bill-runs/review/review-charge-reference.njk @@ -33,9 +33,9 @@ {# Title area #}
-

- Charge reference {{chargeCategory}}{{chargeDescription}} -

+

+ Charge reference {{chargeCategory}}{{chargeDescription}} +

Financial Year {{financialPeriod}}

Charge period {{chargePeriod}} @@ -79,7 +79,7 @@ text: "Change the authorised volume", classes: "govuk-button--secondary", preventDoubleClick: true, - href: "/system/bill-runs/charge-reference/" + reviewChargeReferenceId + "/authorised" + href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/authorised" }) }} {% endif %} @@ -89,7 +89,7 @@ text: "Preview the charge", classes: "govuk-button--secondary", preventDoubleClick: true, - href: "/system/bill-runs/charge-reference/" + reviewChargeReferenceId + "/preview" + href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/preview" }) }}

@@ -111,7 +111,7 @@ {% if canAmend %} {% set showLink = { items: [{ - href: "/system/bill-runs/charge-reference/" + reviewChargeReferenceId + "/factors", + href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/factors", text: "Change factors" }] } From b666d8ea4e2d9b0e021f15d141497beb890e769a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 09:14:05 +0000 Subject: [PATCH 034/147] Housekeeping - remove redundant view code --- app/views/bill-runs/review/factors.njk | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/views/bill-runs/review/factors.njk b/app/views/bill-runs/review/factors.njk index 7d7a210462..77df19c1d5 100644 --- a/app/views/bill-runs/review/factors.njk +++ b/app/views/bill-runs/review/factors.njk @@ -16,12 +16,6 @@ {% block content %}
- - {% set errorList %} -
{{error.aggregateFactorElement.text}}
-
{{error.chargeAdjustmentElement.text}}
- {% endset %} - {% if error %} {{ govukErrorSummary({ titleText: 'There is a problem', From 28907ed760d35eac59c968aa76cee617b4322203 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 09:19:48 +0000 Subject: [PATCH 035/147] Housekeeping - remove redundant views Overlooked doing this when creating the views that replaced them --- .../bill-runs/amend-adjustment-factor.njk | 105 ------------ .../bill-runs/charge-reference-details.njk | 156 ------------------ 2 files changed, 261 deletions(-) delete mode 100644 app/views/bill-runs/amend-adjustment-factor.njk delete mode 100644 app/views/bill-runs/charge-reference-details.njk diff --git a/app/views/bill-runs/amend-adjustment-factor.njk b/app/views/bill-runs/amend-adjustment-factor.njk deleted file mode 100644 index 761af487f9..0000000000 --- a/app/views/bill-runs/amend-adjustment-factor.njk +++ /dev/null @@ -1,105 +0,0 @@ -{% extends 'layout.njk' %} -{% from "govuk/components/back-link/macro.njk" import govukBackLink %} -{% from "govuk/components/inset-text/macro.njk" import govukInsetText %} -{% from "govuk/components/input/macro.njk" import govukInput %} -{% from "govuk/components/button/macro.njk" import govukButton %} -{% from 'govuk/components/error-summary/macro.njk' import govukErrorSummary %} - - -{% block breadcrumbs %} - {# Back link #} - {{ govukBackLink({ - text: 'Go back to licence', - href: '/system/bill-runs/' + billRunId + '/review/' + licenceId + '/charge-reference-details/' + chargeReference.id - }) }} -{% endblock %} - -{% block content %} -
-
- - {% set errorMessage %} -
{{error.aggregateFactorElement.text}}
-
{{error.chargeAdjustmentElement.text}}
- {% endset %} - - {% if error %} - {{ govukErrorSummary({ - titleText: 'There is a problem', - errorList: [ - { - html: errorMessage, - href: '#adjustment-factor-error' - } - ] - }) }} - {% endif %} - - {{chargeReference.description}} -

Set the adjustment factors

- - {% set insertText %} -

- Financial year - {{financialYear}} -

- -

- Charge period - {{chargePeriod}} -

-

Other adjustments apply:

- - {% for adjustment in chargeReference.otherAdjustments %} -
{{adjustment}}
- {% endfor %} - {% endset %} - - {{ govukInsetText({ - html: insertText - }) }} - - {% if inputtedAggregateValue %} - {% set aggregateValue = inputtedAggregateValue %} - {% else %} - {% set aggregateValue = chargeReference.aggregateFactor %} - {% endif %} - - {% if inputtedChargeValue %} - {% set chargeValue = inputtedChargeValue %} - {% else %} - {% set chargeValue = chargeReference.chargeAdjustment %} - {% endif %} - -
- - - {{ govukInput({ - label: { - text: "Aggregate factor", - classes: "govuk-label" - }, - id: "amended-aggregate-factor", - name: "amendedAggregateFactor", - classes: "govuk-input--width-10", - value: aggregateValue, - errorMessage: error.aggregateFactorElement - }) }} - - {{ govukInput({ - label: { - text: "Charge adjustment", - classes: "govuk-label" - }, - id: "amended-charge-adjustment", - name: "amendedChargeAdjustment", - classes: "govuk-input govuk-input--width-10", - value: chargeValue, - errorMessage: error.chargeAdjustmentElement - }) }} - - {{ govukButton({ text: 'Confirm', preventDoubleClick: true }) }} -
-
-
-{% endblock %} diff --git a/app/views/bill-runs/charge-reference-details.njk b/app/views/bill-runs/charge-reference-details.njk deleted file mode 100644 index 12e88c71c5..0000000000 --- a/app/views/bill-runs/charge-reference-details.njk +++ /dev/null @@ -1,156 +0,0 @@ -{% extends 'layout.njk' %} -{% from "govuk/components/back-link/macro.njk" import govukBackLink %} -{% from "govuk/components/button/macro.njk" import govukButton %} -{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %} -{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %} - -{% block breadcrumbs %} - {# Back link #} - {{ govukBackLink({ - text: 'Go back to licence', - href: '/system/bill-runs/' + billRunId + '/review/' + licenceId - }) }} -{% endblock %} - -{% block content %} - - {# Adjustment factor ammended banner #} - {% if bannerMessage %} - {{ govukNotificationBanner({ - titleText: 'Adjustment updated', - text: bannerMessage - }) }} - {% endif %} - - {# Charge preview banner #} - {% if chargeMessage %} - {{ govukNotificationBanner({ - titleText: 'Information', - text: chargeMessage - }) }} - {% endif %} - -
-
-

- Charge reference {{chargeReference.reference}}{{chargeReference.description}} -

- Financial Year {{financialYear}} -

- Charge period {{chargePeriod}} -

-
-
- -
-
-
-

- {{chargeReference.totalBillableReturns}} ML -
- Total billable returns -
-

-
-
-

- / -

-
-
-

- {{chargeReference.authorisedVolume}} ML -
- Authorised volume -
-

-
-
-
- -
-
- {% if hasAggregateOrChargeFactor %} - - {{ govukButton({ - text: "Change the authorised volume", - classes: "govuk-button--secondary", - preventDoubleClick: true, - href: chargeReference.id + '/amend-authorised-volume' - }) }} - - {% endif %} - - - {{ govukButton({ - text: "Preview the charge", - classes: "govuk-button--secondary", - preventDoubleClick: true, - href: "../preview-charge/" + chargeReference.id - }) }} - -
-
- -{% if chargeReference.additionalCharges or chargeReference.adjustments.length > 0 %} -
-
-

- Reference details -

- - {% set adjustmentsValue %} - {% for adjustment in chargeReference.adjustments %} - {% set adjustmentsIndex = loop.index0 %} -
{{adjustment}}
- {% endfor %} - {% endset %} - - {% if hasAggregateOrChargeFactor %} - {% set showLink = { - items: [ - { - href: chargeReference.id + "/amend-adjustment-factor", - text: "Change factors" - } - ] - }%} - {% endif %} - - {% set tableRows = [] %} - {% if chargeReference.additionalCharges %} - {% set tableRow = { - key: { - text: "Additional charges" - }, - value: { - html: '
' + chargeReference.additionalCharges + '
' - } - } - %} - - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endif %} - - {% if chargeReference.adjustments %} - {% set tableRow = { - key: { - text: "Adjustments" - }, - value: { - html: adjustmentsValue - }, - actions: showLink - } - %} - - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endif %} - - {{ govukSummaryList({ - rows: tableRows - }) }} -

-
-{% endif %} -{% endblock %} From d338f73e2d1683533ca5de45b7ec61daecb14cc0 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 09:26:00 +0000 Subject: [PATCH 036/147] Housekeeping - Missed rename in comments --- app/presenters/bill-runs/review/factors.presenter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js index b025966308..fe67db2f28 100644 --- a/app/presenters/bill-runs/review/factors.presenter.js +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -2,7 +2,7 @@ /** * Formats the review charge reference data ready for presenting in the review charge reference factors page - * @module AmendAdjustmentFactorPresenter + * @module FactorsPresenter */ const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') From 0e27aec20ed429dd2d36ff7ae10092c8b0b1c09b Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 09:29:05 +0000 Subject: [PATCH 037/147] Housekeeping - property ordering --- app/presenters/bill-runs/review/factors.presenter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js index fe67db2f28..19e794c452 100644 --- a/app/presenters/bill-runs/review/factors.presenter.js +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -30,10 +30,10 @@ function go (reviewChargeReference) { return { amendedAggregate, amendedChargeAdjustment, - otherAdjustments: [...additionalCharges, ...adjustments], chargeDescription: chargeReference.chargeCategory.shortDescription, chargePeriod: _chargePeriod(reviewChargeVersion), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), + otherAdjustments: [...additionalCharges, ...adjustments], reviewChargeReferenceId } } From 5d2bc283531d3c069f34d254de11e498938bafb9 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 09:31:26 +0000 Subject: [PATCH 038/147] Housekeeping - Rename function to match property --- .../bill-runs/review/review-charge-reference.presenter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js index 48770f44a4..887ce90126 100644 --- a/app/presenters/bill-runs/review/review-charge-reference.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -37,7 +37,7 @@ function go (reviewChargeReference) { financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, reviewLicenceId: reviewChargeVersion.reviewLicence.id, - totalBillableReturns: _totalAllocated(reviewChargeElements) + totalBillableReturns: _totalBillableReturns(reviewChargeElements) } } @@ -111,7 +111,7 @@ function _chargePeriod (reviewChargeVersion) { return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` } -function _totalAllocated (reviewChargeElements) { +function _totalBillableReturns (reviewChargeElements) { return reviewChargeElements.reduce((total, reviewChargeElement) => { const { amendedAllocated } = reviewChargeElement From 2e15ff5c303d6c5e0c6bca2075242e7249509e7d Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 12:44:45 +0000 Subject: [PATCH 039/147] Housekeeping - Missed rename in comments --- app/services/bill-runs/review/submit-factors.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/submit-factors.service.js b/app/services/bill-runs/review/submit-factors.service.js index 5467046156..8ece309ba2 100644 --- a/app/services/bill-runs/review/submit-factors.service.js +++ b/app/services/bill-runs/review/submit-factors.service.js @@ -2,7 +2,7 @@ /** * Handles user submission for the review charge reference factors page - * @module SubmitAmendedAdjustmentFactorService + * @module SubmitFactorsService */ const FactorsPresenter = require('../../../presenters/bill-runs/review/factors.presenter.js') From 251c062a37c40436cce938019cac7a0707382a89 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 12:46:46 +0000 Subject: [PATCH 040/147] Housekeeping - correct typo in comments --- app/services/bill-runs/review/submit-factors.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/submit-factors.service.js b/app/services/bill-runs/review/submit-factors.service.js index 8ece309ba2..2788aeffb6 100644 --- a/app/services/bill-runs/review/submit-factors.service.js +++ b/app/services/bill-runs/review/submit-factors.service.js @@ -26,7 +26,7 @@ const ReviewChargeReferenceModel = require('../../../models/review-charge-refere * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller * @param {object} payload - The submitted form data * - * @returns {Promise} An empty object if there are no errors else the page data for the type page including the + * @returns {Promise} An empty object if there are no errors else the page data for the page including the * validation error details */ async function go (reviewChargeReferenceId, yar, payload) { From 0668781a5ea3a31c99e4ec1bbc7ce544a9e0c5a7 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:12:36 +0000 Subject: [PATCH 041/147] Move, rename & refactor chg ref authorised presenter --- .../bill-runs/review/authorised.presenter.js | 56 ++++++++++++++++++ .../amend-authorised-volume.presenter.js | 58 ------------------- 2 files changed, 56 insertions(+), 58 deletions(-) create mode 100644 app/presenters/bill-runs/review/authorised.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js diff --git a/app/presenters/bill-runs/review/authorised.presenter.js b/app/presenters/bill-runs/review/authorised.presenter.js new file mode 100644 index 0000000000..afe3164364 --- /dev/null +++ b/app/presenters/bill-runs/review/authorised.presenter.js @@ -0,0 +1,56 @@ +'use strict' + +/** + * Formats the review charge reference data ready for presenting in the review charge reference authorised page + * @module AuthorisedPresenter + */ + +const Big = require('big.js') + +const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') + +/** + * Formats the review charge reference data ready for presenting in the review charge reference authorised page + * + * @param {module:ReviewChargeReference} reviewChargeReference - instance of the `ReviewChargeReferenceModel` + * returned from `FetchReviewChargeReferenceService` + * + * @returns {object} page date needed for the review charge reference factors page + */ +function go (reviewChargeReference) { + const { + amendedAuthorisedVolume, + chargeReference, + reviewChargeElements, + reviewChargeVersion, + id: reviewChargeReferenceId + } = reviewChargeReference + + return { + amendedAuthorisedVolume, + chargeDescription: chargeReference.chargeCategory.shortDescription, + chargePeriod: _chargePeriod(reviewChargeVersion), + financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), + reviewChargeReferenceId, + totalBillableReturns: _totalBillableReturns(reviewChargeElements) + } +} + +function _chargePeriod (reviewChargeVersion) { + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion + const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } + + return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` +} + +function _totalBillableReturns (reviewChargeElements) { + return reviewChargeElements.reduce((total, reviewChargeElement) => { + const { amendedAllocated } = reviewChargeElement + + return Big(total).plus(amendedAllocated).toNumber() + }, 0) +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js b/app/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js deleted file mode 100644 index 9cb18051f6..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict' - -/** - * Formats the two part tariff review data ready for presenting in the amend authorised volume page - * @module AmendAuthorisedVolumePresenter - */ - -const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') - -/** - * Prepares and processes bill run and review charge reference data for presenting - * - * @param {module:BillRunModel} billRun - the data from the bill run - * @param {module:ReviewChargeReference} reviewChargeReference - the data from the review charge reference - * @param {string} licenceId - the UUID of the licence being reviewed - * - * @returns {object} the prepared bill run and charge reference data to be passed to the amend authorised volume page - */ -function go (billRun, reviewChargeReference, licenceId) { - return { - billRunId: billRun.id, - licenceId, - financialYear: formatFinancialYear(billRun.toFinancialYearEnding), - chargePeriod: _prepareDate( - reviewChargeReference.reviewChargeVersion.chargePeriodStartDate, - reviewChargeReference.reviewChargeVersion.chargePeriodEndDate - ), - chargeReference: { - id: reviewChargeReference.id, - description: reviewChargeReference.chargeReference.chargeCategory.shortDescription, - authorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - totalBillableReturns: _totalBillableReturns(reviewChargeReference.reviewChargeElements) - }, - chargeCategory: { - minVolume: reviewChargeReference.chargeReference.chargeCategory.minVolume, - maxVolume: reviewChargeReference.chargeReference.chargeCategory.maxVolume - } - } -} - -function _prepareDate (startDate, endDate) { - const preparedStartDate = formatLongDate(startDate) - const preparedEndDate = formatLongDate(endDate) - - return `${preparedStartDate} to ${preparedEndDate}` -} - -function _totalBillableReturns (reviewChargeElements) { - return reviewChargeElements.reduce((total, reviewChargeElement) => { - total += reviewChargeElement.amendedAllocated - - return total - }, 0) -} - -module.exports = { - go -} From 6efdb1c3c48c5761e87f053030776862537e5443 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:13:22 +0000 Subject: [PATCH 042/147] Move, rename & refactor chg ref authorised service --- .../bill-runs/review/authorised.service.js | 32 +++++++++++++++++++ .../amend-authorised-volume.service.js | 30 ----------------- 2 files changed, 32 insertions(+), 30 deletions(-) create mode 100644 app/services/bill-runs/review/authorised.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/amend-authorised-volume.service.js diff --git a/app/services/bill-runs/review/authorised.service.js b/app/services/bill-runs/review/authorised.service.js new file mode 100644 index 0000000000..c762837a17 --- /dev/null +++ b/app/services/bill-runs/review/authorised.service.js @@ -0,0 +1,32 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data needed for the review charge reference authorised page + * @module AuthorisedService + */ + +const AuthorisedPresenter = require('../../../presenters/bill-runs/review/authorised.presenter.js') +const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') + +/** + * Orchestrates fetching and presenting the data needed for the review charge reference authorised page + * + * @param {string} reviewChargeReferenceId - The UUID of the review charge reference whose authorised volume is being + * amended + * + * @returns {Promise} the 'pageData' needed to view the amend authorised volume page + */ +async function go (reviewChargeReferenceId) { + const reviewChargeReference = await FetchReviewChargeReferenceService.go(reviewChargeReferenceId) + + const pageData = AuthorisedPresenter.go(reviewChargeReference) + + return { + pageTitle: 'Set the authorised volume', + ...pageData + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/amend-authorised-volume.service.js b/app/services/bill-runs/two-part-tariff/amend-authorised-volume.service.js deleted file mode 100644 index cf4f14d484..0000000000 --- a/app/services/bill-runs/two-part-tariff/amend-authorised-volume.service.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict' - -/** - * Orchestrates fetching and presenting the data needed for the amend authorised volume page - * @module AmendAuthorisedVolumeService - */ - -const AmendAuthorisedVolumePresenter = require('../../../presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js') -const FetchAuthorisedVolumeService = require('./fetch-authorised-volume.service.js') - -/** - * Orchestrates fetching and presenting the data needed for the amend authorised volume page - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being viewed - * - * @returns {Promise} the 'pageData' needed to view the amend authorised volume page - */ -async function go (billRunId, licenceId, reviewChargeReferenceId) { - const { billRun, reviewChargeReference } = await FetchAuthorisedVolumeService.go(billRunId, reviewChargeReferenceId) - - const pageData = AmendAuthorisedVolumePresenter.go(billRun, reviewChargeReference, licenceId) - - return pageData -} - -module.exports = { - go -} From eeb832be7801a8c24a411b5fcb8b50bdf0c74544 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:14:05 +0000 Subject: [PATCH 043/147] Move, rename & refactor chg ref authorised view --- .../authorised.njk} | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) rename app/views/bill-runs/{amend-authorised-volume.njk => review/authorised.njk} (52%) diff --git a/app/views/bill-runs/amend-authorised-volume.njk b/app/views/bill-runs/review/authorised.njk similarity index 52% rename from app/views/bill-runs/amend-authorised-volume.njk rename to app/views/bill-runs/review/authorised.njk index f394ec601c..c3ce376ca0 100644 --- a/app/views/bill-runs/amend-authorised-volume.njk +++ b/app/views/bill-runs/review/authorised.njk @@ -8,40 +8,41 @@ {% block breadcrumbs %} {# Back link #} {{ govukBackLink({ - text: 'Go back to licence', - href: '/system/bill-runs/' + billRunId + '/review/' + licenceId + '/charge-reference-details/' + chargeReference.id + text: 'Go back to charge reference', + href: '/system/bill-runs/review/charge-reference/' + reviewChargeReferenceId }) }} {% endblock %} {% block content %} - {% if error %} - {{ govukErrorSummary({ - titleText: 'There is a problem', - errorList: [ - { - text: error.authorisedVolume, - href: '#authorised-volume-error' - } - ] - }) }} - {% endif %} -
- {{chargeReference.description}} -

Set the authorised volume

+ {% if error %} + {{ govukErrorSummary({ + titleText: 'There is a problem', + errorList: [ + { + text: error.text, + href: '#amended-authorised-volume' + } + ] + }) }} + {% endif %} + + {# Title #} +

+ {{chargeDescription}} + {{pageTitle}} +

+ Financial Year {{financialPeriod}} +

+ Charge period {{chargePeriod}} +

{% set insertText %}

- Financial year - {{financialYear}} + Total billable returns + {{totalBillableReturns}} ML

-

- Charge period - {{chargePeriod}} -

-

Total billable returns

-

{{chargeReference.totalBillableReturns}}

{% endset %} {{ govukInsetText({ @@ -57,18 +58,18 @@ text: "Authorised volume", classes: "govuk-label" }, - id: "authorised-volume", - name: "authorisedVolume", + id: "amended-authorised-volume", + name: "amendedAuthorisedVolume", classes: "govuk-input--width-10", - value: chargeReference.authorisedVolume, - errorMessage: error.authorisedVolume, + value: amendedAuthorisedVolume, suffix: { text: "ML" - } + }, + errorMessage: error }) }} {# Hidden input for authorised volume #} - + {{ govukButton({ text: 'Confirm', preventDoubleClick: true }) }} From 46f081153c0adc5474d089d7896de618ab08f274 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:14:44 +0000 Subject: [PATCH 044/147] Move, rename & refactor chg ref authorised validator --- .../bill-runs/review/authorised.validator.js | 78 +++++++++++++++++ .../authorised-volume.validator.js | 85 ------------------- 2 files changed, 78 insertions(+), 85 deletions(-) create mode 100644 app/validators/bill-runs/review/authorised.validator.js delete mode 100644 app/validators/bill-runs/two-part-tariff/authorised-volume.validator.js diff --git a/app/validators/bill-runs/review/authorised.validator.js b/app/validators/bill-runs/review/authorised.validator.js new file mode 100644 index 0000000000..d47994a724 --- /dev/null +++ b/app/validators/bill-runs/review/authorised.validator.js @@ -0,0 +1,78 @@ +'use strict' + +/** + * Validates data submitted for the review charge reference authorised page + * @module FactorsValidator + */ + +const Joi = require('joi') + +/** + * Validates data submitted for the review charge reference authorised page + * + * When editing the authorised volume on the charge reference, the user input box is pre-populated with the current + * value. The user must overwrite this value with there own value to amend the authorised volume. + * The validation happening here is to ensure that the volume has been entered, it has a maximum 6 decimal places and + * is more than the totalBillableReturns. + * + * @param {object} payload - The payload from the request to be validated + * + * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If + * any errors are found the `error:` property will also exist detailing what the issues were + */ +function go (payload) { + const { amendedAuthorisedVolume, totalBillableReturns } = payload + + return _validate(amendedAuthorisedVolume, Number(totalBillableReturns)) +} + +function _validate (amendedAuthorisedVolume, totalBillableReturns) { + const schema = Joi + .number() + .min(totalBillableReturns) + .required() + .custom(_maxDecimals, 'Max decimals') + .messages({ + 'number.base': 'The authorised volume must be a number', + 'number.unsafe': 'The authorised volume must be a number or fewer than 17 digits long', + 'number.min': `The authorised volume must be greater than ${totalBillableReturns}`, + 'any.required': 'Enter an authorised volume', + 'any.invalid': 'The authorised volume must not have more than 6 decimal places' + }) + + return schema.validate(amendedAuthorisedVolume, { abortEarly: false }) +} + +/** + * Custom JOI validator to check a value does not have more than 6 decimal places + * + * We are limited to 6 decimals by the Rules Service that will eventually be called to calculate the charge. Due to + * limitations in Joi validation for decimals, achieving validation for numbers with more than 6 decimal places + * requires a custom approach. + * + * See {@link https://github.com/hapijs/joi/blob/master/API.md#anycustommethod-description | Joi custom validation}. + * + * @param {number} value - the value to be validated + * @param {object} helpers - a Joi object containing a numbers of helpers + * + * @returns {number|object} if valid the original value else a Joi 'any.invalid' error. Knowing we return this means + * you can assign what error message to use when a number has too many decimals. + */ +function _maxDecimals (value, helpers) { + // Guard clause to ensure we don't try and interact with a null or undefined value + if (!value) { + return value + } + + const parts = value.toString().split('.') + + if (parts.length === 1 || parts[1].length <= 6) { + return value + } + + return helpers.error('any.invalid') +} + +module.exports = { + go +} diff --git a/app/validators/bill-runs/two-part-tariff/authorised-volume.validator.js b/app/validators/bill-runs/two-part-tariff/authorised-volume.validator.js deleted file mode 100644 index bfe127b126..0000000000 --- a/app/validators/bill-runs/two-part-tariff/authorised-volume.validator.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict' - -/** - * Validates data submitted for the `/bill-runs/{billRunId}/review/{licenceId}/charge-reference-details/ - * {reviewChargeReferenceId}/amend-authorised-volume` page - * @module AuthorisedVolumeValidator - */ - -const Joi = require('joi') - -/** - * Validates data submitted for the `/bill-runs/{billRunId}/review/{licenceId}/charge-reference-details/ - * {reviewChargeReferenceId}/amend-authorised-volume` page - * - * When editing the authorised volume on the charge reference, the user input box is pre-populated with the current - * value. The user must overwrite this value with there own value to amend the authorised volume. - * The validation happening here is to ensure that the volume has been entered, it has a maximum 6 decimal places and - * is more than the totalBillableReturns. - * - * @param {object} payload - The payload from the request to be validated - * - * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If - * any errors are found the `error:` property will also exist detailing what the issues were - */ -function go (payload) { - const { authorisedVolume, totalBillableReturns } = payload - - const validation = _validate(authorisedVolume, Number(totalBillableReturns)) - - // The first check we are doing is validating that a number has been inputted within the correct range. If it has - // then we can move onto next validating the number of decimal places - if (!validation.error) { - const decimalSchema = Joi.number().custom(_customValidation, 'custom validation') - - return decimalSchema.validate(authorisedVolume) - } - - return validation -} - -/** - * Due to limitations in Joi validation for decimals, achieving validation for numbers with fewer than 6 decimal - * places requires a custom approach. First, convert the number into a string. Then split the string into an array using - * the decimal point (`.`) as the delimiter. This results in either one item in the array (if no decimal is present) or - * two items (if a decimal is present). The first item represents the part before the decimal, while the second item - * represents the part after. By assessing if the length of the second string is less than o equal to 6, we can validate - * if there are the correct number of decimals. - * - * @private - */ -function _customValidation (quantity, helpers) { - const maxNumberOfDecimals = 6 - const quantityParts = quantity.toString().split('.') - - if (quantityParts.length === 1 || quantityParts[1].length <= maxNumberOfDecimals) { - return quantity - } - - return helpers.message({ - custom: 'The authorised volume must not have more than 6 decimal places' - }) -} - -function _validate (authorisedVolume, totalBillableReturns) { - const schema = Joi.object({ - authorisedVolume: Joi - .number() - .min(totalBillableReturns) - .required() - .messages({ - 'number.base': 'The authorised volume must be a number', - 'number.unsafe': 'The authorised volume must be a number or fewer than 17 digits long', - 'number.min': `The authorised volume must be greater than ${totalBillableReturns}`, - 'any.required': 'Enter an authorised volume' - }) - }) - - const validation = schema.validate({ authorisedVolume }, { abortEarly: false }) - - return validation -} - -module.exports = { - go -} From 97c64ca299580a2ec43066ca37c986bc47ffd66d Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:15:38 +0000 Subject: [PATCH 045/147] Move, rename & refactor chg ref authorised submit --- .../review/submit-authorised.service.js | 67 ++++++++++++++++++ ...ubmit-amended-authorised-volume.service.js | 68 ------------------- 2 files changed, 67 insertions(+), 68 deletions(-) create mode 100644 app/services/bill-runs/review/submit-authorised.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js diff --git a/app/services/bill-runs/review/submit-authorised.service.js b/app/services/bill-runs/review/submit-authorised.service.js new file mode 100644 index 0000000000..55ee748f57 --- /dev/null +++ b/app/services/bill-runs/review/submit-authorised.service.js @@ -0,0 +1,67 @@ +'use strict' + +/** + * Handles user submission for the review charge reference authorised page + * @module SubmitAuthorisedService + */ + +const AuthorisedPresenter = require('../../../presenters/bill-runs/review/authorised.presenter.js') +const AuthorisedValidator = require('../../../validators/bill-runs/review/authorised.validator.js') +const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') +const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') + +/** + * Orchestrates validating the data for the amend authorised volume page and patching the db value + * + * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being updated + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * @param {object} payload - The submitted form data + * + * @returns {Promise} An empty object if there are no errors else the page data for the page including the + * validation error details + */ +async function go (reviewChargeReferenceId, yar, payload) { + const validationResult = _validate(payload) + + if (!validationResult) { + await _save(reviewChargeReferenceId, payload) + yar.flash('banner', 'The authorised volume for this licence have been updated') + + return {} + } + + const reviewChargeReference = await FetchReviewChargeReferenceService.go(reviewChargeReferenceId) + const pageData = AuthorisedPresenter.go(reviewChargeReference) + + return { + activeNavBar: 'search', + pageTitle: 'Set the authorised volume', + error: validationResult, + ...pageData, + amendedAuthorisedVolume: payload.amendedAuthorisedVolume + } +} + +async function _save (reviewChargeReferenceId, payload) { + return ReviewChargeReferenceModel.query() + .findById(reviewChargeReferenceId) + .patch({ amendedAuthorisedVolume: payload.amendedAuthorisedVolume }) +} + +function _validate (payload) { + const validation = AuthorisedValidator.go(payload) + + if (!validation.error) { + return null + } + + const { message } = validation.error.details[0] + + return { + text: message + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js b/app/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js deleted file mode 100644 index 1db2db604e..0000000000 --- a/app/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js +++ /dev/null @@ -1,68 +0,0 @@ -'use strict' - -/** - * Orchestrates validating and patching the data for the amend authorised volume page - * @module SubmitAmendedAuthorisedVolumeService -*/ - -const AmendAuthorisedVolumePresenter = require('../../../presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js') -const AuthorisedVolumeValidator = require('../../../validators/bill-runs/two-part-tariff/authorised-volume.validator.js') -const FetchAuthorisedVolumeService = require('./fetch-authorised-volume.service.js') -const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') - -/** - * Orchestrates validating the data for the amend authorised volume page and patching the db value - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being updated - * @param {object} payload - The submitted form data - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - * - * @returns {Promise} The updated value for the authorised volume - */ -async function go (billRunId, licenceId, reviewChargeReferenceId, payload, yar) { - const validationResult = _validate(payload) - - if (!validationResult) { - await _persistAuthorisedVolume(reviewChargeReferenceId, payload) - yar.flash('banner', 'The authorised volume for this licence have been updated') - - return { error: null } - } - - const { billRun, reviewChargeReference } = await FetchAuthorisedVolumeService.go(billRunId, reviewChargeReferenceId) - - const pageData = AmendAuthorisedVolumePresenter.go(billRun, reviewChargeReference, licenceId) - - return { - activeNavBar: 'search', - pageTitle: 'Set the authorised volume', - error: validationResult, - ...pageData - } -} - -async function _persistAuthorisedVolume (reviewChargeReferenceId, payload) { - return ReviewChargeReferenceModel.query() - .findById(reviewChargeReferenceId) - .patch({ amendedAuthorisedVolume: payload.authorisedVolume }) -} - -function _validate (payload) { - const validation = AuthorisedVolumeValidator.go(payload) - - if (!validation.error) { - return null - } - - const authorisedVolume = validation.error.details[0].message - - return { - authorisedVolume - } -} - -module.exports = { - go -} From c8656c8dfb918a5d1cb9204fd9f91c7ff2e0b779 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:16:08 +0000 Subject: [PATCH 046/147] Move chg ref authorised routes and controllers --- .../bill-runs-review.controller.js | 26 +++++++++++++++ app/controllers/bill-runs.controller.js | 33 ------------------- app/routes/bill-runs-review.routes.js | 24 ++++++++++++++ app/routes/bill-runs.routes.js | 24 -------------- 4 files changed, 50 insertions(+), 57 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 077e847679..a919c1eaf9 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -5,14 +5,27 @@ * @module BillRunsReviewController */ +const AuthorisedService = require('../services/bill-runs/review/authorised.service.js') const FactorsService = require('../services/bill-runs/review/factors.service.js') const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') +const SubmitAuthorisedService = require('../services/bill-runs/review/submit-authorised.service.js') const SubmitFactorsService = require('../services/bill-runs/review/submit-factors.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') +async function authorised (request, h) { + const { reviewChargeReferenceId } = request.params + + const pageData = await AuthorisedService.go(reviewChargeReferenceId) + + return h.view('bill-runs/review/authorised.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function factors (request, h) { const { reviewChargeReferenceId } = request.params @@ -58,6 +71,17 @@ async function reviewLicence (request, h) { }) } +async function submitAuthorised (request, h) { + const { reviewChargeReferenceId } = request.params + const pageData = await SubmitAuthorisedService.go(reviewChargeReferenceId, request.yar, request.payload) + + if (pageData.error) { + return h.view('bill-runs/review/authorised.njk', pageData) + } + + return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) +} + async function submitFactors (request, h) { const { reviewChargeReferenceId } = request.params const pageData = await SubmitFactorsService.go(reviewChargeReferenceId, request.yar, request.payload) @@ -86,10 +110,12 @@ async function submitReviewLicence (request, h) { } module.exports = { + authorised, factors, review, reviewChargeReference, reviewLicence, + submitAuthorised, submitFactors, submitReview, submitReviewLicence diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 1ff9d6e9d0..1633e24547 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -7,7 +7,6 @@ const Boom = require('@hapi/boom') -const AmendAuthorisedVolumeService = require('../services/bill-runs/two-part-tariff/amend-authorised-volume.service.js') const AmendBillableReturnsService = require('../services/bill-runs/two-part-tariff/amend-billable-returns.service.js') const CalculateChargeService = require('../services/bill-runs/two-part-tariff/calculate-charge.service.js') const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js') @@ -16,25 +15,12 @@ const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.serv const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js') const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') -const SubmitAmendedAuthorisedVolumeService = require('../services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js') const SubmitAmendedBillableReturnsService = require('..//services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../services/bill-runs/submit-cancel-bill-run.service.js') const SubmitRemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') const SubmitSendBillRunService = require('../services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../services/bill-runs/view-bill-run.service.js') -async function amendAuthorisedVolume (request, h) { - const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params - - const pageData = await AmendAuthorisedVolumeService.go(billRunId, licenceId, reviewChargeReferenceId) - - return h.view('bill-runs/amend-authorised-volume.njk', { - pageTitle: 'Set the authorised volume', - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function amendBillableReturns (request, h) { const { id: billRunId, licenceId, reviewChargeElementId } = request.params @@ -113,23 +99,6 @@ async function send (request, h) { }) } -async function submitAmendedAuthorisedVolume (request, h) { - const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params - const pageData = await SubmitAmendedAuthorisedVolumeService.go( - billRunId, - licenceId, - reviewChargeReferenceId, - request.payload, - request.yar - ) - - if (pageData.error) { - return h.view('bill-runs/amend-authorised-volume.njk', pageData) - } - - return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}/charge-reference-details/${reviewChargeReferenceId}`) -} - async function submitAmendedBillableReturns (request, h) { const { id: billRunId, licenceId, reviewChargeElementId } = request.params @@ -216,7 +185,6 @@ async function view (request, h) { } module.exports = { - amendAuthorisedVolume, amendBillableReturns, cancel, index, @@ -224,7 +192,6 @@ module.exports = { previewCharge, removeLicence, send, - submitAmendedAuthorisedVolume, submitAmendedBillableReturns, submitCancel, submitRemoveLicence, diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 2625538b20..dbfccdb8b2 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -39,6 +39,30 @@ const routes = [ } } }, + { + method: 'GET', + path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}/authorised', + options: { + handler: BillRunsReviewController.authorised, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}/authorised', + options: { + handler: BillRunsReviewController.submitAuthorised, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}/factors', diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index 1ea06b52b6..de0981b9f3 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -78,30 +78,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-authorised-volume', - options: { - handler: BillRunsController.amendAuthorisedVolume, - auth: { - access: { - scope: ['billing'] - } - } - } - }, - { - method: 'POST', - path: '/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-authorised-volume', - options: { - handler: BillRunsController.submitAmendedAuthorisedVolume, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}', From ff7021f01c3990511271e7d72467f5b2dc4e40ff Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 13:16:28 +0000 Subject: [PATCH 047/147] Remove redundant chg ref authorised fetch service --- .../fetch-authorised-volume.service.js | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js diff --git a/app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js b/app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js deleted file mode 100644 index 89eced1f18..0000000000 --- a/app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict' - -/** - * Fetches the individual charge reference details when the authorised volume is being amended for a two-part tariff - * bill run - * @module FetchAuthorisedVolumeService - */ - -const BillRunModel = require('../../../models/bill-run.model.js') -const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') - -/** - * Fetches the charge reference details for an individual licence - * - * @param {string} billRunId - UUID of the bill run - * @param {string} reviewChargeReferenceId - The UUID of the review charge reference being viewed - * - * @returns {Promise} An object containing the bill run and review charge reference instances - */ -async function go (billRunId, reviewChargeReferenceId) { - const billRun = await _fetchBillRun(billRunId) - const reviewChargeReference = await _fetchReviewChargeReference(reviewChargeReferenceId) - - return { billRun, reviewChargeReference } -} - -async function _fetchBillRun (billRunId) { - return BillRunModel.query() - .findById(billRunId) - .select( - 'id', - 'toFinancialYearEnding') -} - -async function _fetchReviewChargeReference (reviewChargeReferenceId) { - return ReviewChargeReferenceModel.query() - .findById(reviewChargeReferenceId) - .select('id', 'amendedAuthorisedVolume') - .withGraphFetched('chargeReference') - .modifyGraph('chargeReference', (builder) => { - builder.select([ - 'chargeCategoryId' - ]) - }) - .withGraphFetched('chargeReference.chargeCategory') - .modifyGraph('chargeReference.chargeCategory', (builder) => { - builder.select([ - 'shortDescription', - 'minVolume', - 'maxVolume' - ]) - }) - .withGraphFetched('reviewChargeVersion') - .modifyGraph('reviewChargeVersion', (builder) => { - builder.select([ - 'chargePeriodStartDate', - 'chargePeriodEndDate' - ]) - }) - .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder.select([ - 'amendedAllocated' - ]) - }) -} - -module.exports = { - go -} From 1ff2ec6de6ca8728c2a3f6c87c86f50effa3525d Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 17:52:01 +0000 Subject: [PATCH 048/147] Move, rename & refactor preview service --- .../bill-runs/review/preview.service.js | 106 +++++++++++++++ .../calculate-charge.service.js | 124 ------------------ 2 files changed, 106 insertions(+), 124 deletions(-) create mode 100644 app/services/bill-runs/review/preview.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/calculate-charge.service.js diff --git a/app/services/bill-runs/review/preview.service.js b/app/services/bill-runs/review/preview.service.js new file mode 100644 index 0000000000..f63ab0f02e --- /dev/null +++ b/app/services/bill-runs/review/preview.service.js @@ -0,0 +1,106 @@ +'use strict' + +/** + * Calculates the charge for a charge reference for preview by a user on the review charge reference page + * @module PreviewService + */ + +const { formatChargingModuleDate, formatMoney } = require('../../../presenters/base.presenter.js') +const CalculateChargeRequest = require('../../../requests/charging-module/calculate-charge.request.js') +const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') + +/** + * Calculates the charge for a charge reference for preview by a user on the review charge reference page + * + * It does this by sending a transaction based on the selected charge reference to the charging module so that it can + * calculate the charge. The charge amount is then added to a flash message which will be displayed to the user. + * + * If nothing has been allocated to the review charge reference (total billable returns is 0) then the service skips + * sending the request and just returns £0.00. + * + * If the request is sent but does not succeed, we display the message returned in order to help us diagnose what the + * issue could be. + * + * @param {string} reviewChargeReferenceId - The UUID of the charge reference review data to calculate the charge for + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + */ +async function go (reviewChargeReferenceId, yar) { + const reviewChargeReference = await FetchReviewChargeReferenceService.go(reviewChargeReferenceId) + const transaction = _transaction(reviewChargeReference) + + const result = await _calculateCharge(transaction) + + if (result.charge) { + yar.flash('charge', `Based on this information the example charge is ${formatMoney(result.charge)}`) + } + + yar.flash('charge', `Could not calculate a charge. ${result.message}.`) +} + +function _actualVolume (reviewChargeElements) { + return reviewChargeElements.reduce((total, reviewChargeElement) => { + total += reviewChargeElement.amendedAllocated + + return total + }, 0) +} + +async function _calculateCharge (transaction) { + if (transaction.actualVolume === 0) { + return { charge: 0 } + } + + const result = await CalculateChargeRequest.send(transaction) + + if (result.succeeded) { + return { charge: result.response.body.calculation.chargeValue } + } + + return { message: result.response.body.message } +} + +function _transaction (reviewChargeReference) { + const { + abatementAgreement: abatementFactor, + amendedAggregate: aggregateProportion, + amendedAuthorisedVolume: authorisedVolume, + amendedChargeAdjustment: adjustmentFactor, + canalAndRiverTrustAgreement: section130Agreement, + chargeReference, + reviewChargeElements, + reviewChargeVersion, + twoPartTariffAgreement: section127Agreement, + winterDiscount: winterOnly + } = reviewChargeReference + + return { + abatementFactor, + actualVolume: _actualVolume(reviewChargeElements), + adjustmentFactor, + aggregateProportion, + authorisedDays: 0, // 2PT uses volumes in the calculations rather than days so this can be set to 0 + authorisedVolume, + billableDays: 0, // 2PT uses volumes in the calculations rather than days so this can be set to 0 + chargeCategoryCode: chargeReference.chargeCategory.reference, + compensationCharge: false, // Always false for the two-part tariff annual + credit: false, + loss: chargeReference.loss, + periodStart: formatChargingModuleDate(reviewChargeVersion.chargePeriodStartDate), + periodEnd: formatChargingModuleDate(reviewChargeVersion.chargePeriodEndDate), + ruleset: 'sroc', + section127Agreement, + section130Agreement, + supportedSource: chargeReference.supportedSourceName !== null, + // If `supportedSource` is `true` then `supportedSourceName` must be present + supportedSourceName: chargeReference.supportedSourceName, + // If `twoPartTariff` is `true` then `section127Agreement` must also be `true` + twoPartTariff: section127Agreement, + waterCompanyCharge: chargeReference.waterCompanyCharge !== null, + waterUndertaker: reviewChargeVersion.reviewLicence.licence.waterUndertaker, + winterOnly + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/calculate-charge.service.js b/app/services/bill-runs/two-part-tariff/calculate-charge.service.js deleted file mode 100644 index f43c643465..0000000000 --- a/app/services/bill-runs/two-part-tariff/calculate-charge.service.js +++ /dev/null @@ -1,124 +0,0 @@ -'use strict' - -/** - * Calculates the charge for a charge reference to display in a banner to the user - * @module CalculateChargeService - */ - -const { ref } = require('objection') - -const CalculateChargeRequest = require('../../../requests/charging-module/calculate-charge.request.js') -const { formatChargingModuleDate, formatMoney } = require('../../../presenters/base.presenter.js') -const LicenceModel = require('../../../models/licence.model.js') -const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') - -/** - * Calculates the charge for a charge reference to display in a banner to the user - * - * It does this by sending a transaction based on the selected charge reference to the charging module so that it can - * calculate the charge. The charge amount is then added to a flash message which will be displayed to the user. - * - * @param {string} licenceId - The UUID of the licence related to the charge - * @param {string} reviewChargeReferenceId - The UUID of the charge reference review data to calculate the charge on - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - */ -async function go (licenceId, reviewChargeReferenceId, yar) { - const reviewChargeReference = await _fetchReviewChargeReference(reviewChargeReferenceId) - const waterUndertaker = await _fetchWaterUndertaker(licenceId) - const calculatedCharge = await _calculateCharge(reviewChargeReference, waterUndertaker) - - if (calculatedCharge) { - yar.flash('charge', `Based on this information the example charge is ${formatMoney(calculatedCharge)}.`) - } -} - -function _calculateActualVolume (reviewChargeElements) { - return reviewChargeElements.reduce((total, reviewChargeElement) => { - total += reviewChargeElement.amendedAllocated - - return total - }, 0) -} - -async function _calculateCharge (reviewChargeReference, waterUndertaker) { - const transaction = { - abatementFactor: reviewChargeReference.abatementAgreement, - actualVolume: _calculateActualVolume(reviewChargeReference.reviewChargeElements), - adjustmentFactor: reviewChargeReference.amendedChargeAdjustment, - aggregateProportion: reviewChargeReference.amendedAggregate, - authorisedDays: 0, // 2PT uses volumes in the calculations rather than days so this can be set to 0 - authorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - billableDays: 0, // 2PT uses volumes in the calculations rather than days so this can be set to 0 - chargeCategoryCode: reviewChargeReference.chargeReference.chargeCategory.reference, - compensationCharge: false, // Always false for the two-part tariff annual - credit: false, - loss: reviewChargeReference.chargeReference.loss, - periodStart: formatChargingModuleDate(reviewChargeReference.reviewChargeVersion.chargePeriodStartDate), - periodEnd: formatChargingModuleDate(reviewChargeReference.reviewChargeVersion.chargePeriodEndDate), - ruleset: 'sroc', - section127Agreement: reviewChargeReference.twoPartTariffAgreement, - section130Agreement: reviewChargeReference.canalAndRiverTrustAgreement, - supportedSource: reviewChargeReference.chargeReference.supportedSourceName !== null, - // If `supportedSource` is `true` then `supportedSourceName` must be present - supportedSourceName: reviewChargeReference.chargeReference.supportedSourceName, - // If `twoPartTariff` is `true` then `section127Agreement` must also be `true` - twoPartTariff: reviewChargeReference.twoPartTariffAgreement, - waterCompanyCharge: reviewChargeReference.chargeReference.waterCompanyCharge !== null, - waterUndertaker, - winterOnly: reviewChargeReference.winterDiscount - } - - const calculatedCharge = await CalculateChargeRequest.send(transaction) - - if (calculatedCharge.succeeded) { - return calculatedCharge.response.body.calculation.chargeValue - } else { - return null - } -} - -async function _fetchReviewChargeReference (reviewChargeReferenceId) { - return ReviewChargeReferenceModel.query() - .findById(reviewChargeReferenceId) - .select( - 'abatementAgreement', - 'amendedAggregate', - 'amendedAuthorisedVolume', - 'amendedChargeAdjustment', - 'canalAndRiverTrustAgreement', - 'twoPartTariffAgreement', - 'winterDiscount' - ) - .withGraphFetched('chargeReference') - .modifyGraph('chargeReference', (builder) => { - builder.select( - 'loss', - ref('chargeReferences.additionalCharges:supportedSource.name').castText().as('supportedSourceName'), - ref('chargeReferences.additionalCharges:isSupplyPublicWater').castText().as('waterCompanyCharge') - ) - }) - .withGraphFetched('chargeReference.chargeCategory') - .modifyGraph('chargeReference.chargeCategory', (builder) => { - builder.select('reference') - }) - .withGraphFetched('reviewChargeVersion') - .modifyGraph('reviewChargeVersion', (builder) => { - builder.select('chargePeriodStartDate', 'chargePeriodEndDate') - }) - .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder.select('amendedAllocated') - }) -} - -async function _fetchWaterUndertaker (licenceId) { - const licence = await LicenceModel.query() - .findById(licenceId) - .select('waterUndertaker') - - return licence.waterUndertaker -} - -module.exports = { - go -} From 7b9cf033b3a20363088b465fc56ef60c1e82d6c6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 17:52:30 +0000 Subject: [PATCH 049/147] Update FetchReviewChargeReference to support preview We only needed a couple of tweaks and this service can also be used instead of the separate query in the service. --- .../review/fetch-review-charge-reference.service.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/services/bill-runs/review/fetch-review-charge-reference.service.js b/app/services/bill-runs/review/fetch-review-charge-reference.service.js index 5788743697..0ed570fa86 100644 --- a/app/services/bill-runs/review/fetch-review-charge-reference.service.js +++ b/app/services/bill-runs/review/fetch-review-charge-reference.service.js @@ -58,6 +58,14 @@ async function _fetch (reviewChargeReferenceId) { 'toFinancialYearEnding' ]) }) + .withGraphFetched('licence') + .modifyGraph('licence', (builder) => { + builder + .select([ + 'id', + 'waterUndertaker' + ]) + }) }) }) .withGraphFetched('reviewChargeElements') @@ -75,6 +83,7 @@ async function _fetch (reviewChargeReferenceId) { 'id', 'volume', 'chargeCategoryId', + 'loss', ref('chargeReferences.additionalCharges:supportedSource.name').castText().as('supportedSourceName'), ref('chargeReferences.additionalCharges:isSupplyPublicWater').castText().as('waterCompanyCharge') ]) From d69f47e79ad8998fa52e0e9bbae831212bc7f0c7 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 17:53:27 +0000 Subject: [PATCH 050/147] Move chg ref preview routes and controllers --- app/controllers/bill-runs-review.controller.js | 10 ++++++++++ app/controllers/bill-runs.controller.js | 10 ---------- app/routes/bill-runs-review.routes.js | 12 ++++++++++++ app/routes/bill-runs.routes.js | 12 ------------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index a919c1eaf9..39314bed85 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -7,6 +7,7 @@ const AuthorisedService = require('../services/bill-runs/review/authorised.service.js') const FactorsService = require('../services/bill-runs/review/factors.service.js') +const PreviewService = require('../services/bill-runs/review/preview.service.js') const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') @@ -37,6 +38,14 @@ async function factors (request, h) { }) } +async function preview (request, h) { + const { reviewChargeReferenceId } = request.params + + await PreviewService.go(reviewChargeReferenceId, request.yar) + + return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) +} + async function review (request, h) { const { id } = request.params const { page } = request.query @@ -112,6 +121,7 @@ async function submitReviewLicence (request, h) { module.exports = { authorised, factors, + preview, review, reviewChargeReference, reviewLicence, diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 1633e24547..fff909386f 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -8,7 +8,6 @@ const Boom = require('@hapi/boom') const AmendBillableReturnsService = require('../services/bill-runs/two-part-tariff/amend-billable-returns.service.js') -const CalculateChargeService = require('../services/bill-runs/two-part-tariff/calculate-charge.service.js') const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js') const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/generate-bill-run.service.js') const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') @@ -68,14 +67,6 @@ async function matchDetails (request, h) { }) } -async function previewCharge (request, h) { - const { id: billRunId, licenceId, reviewChargeReferenceId } = request.params - - await CalculateChargeService.go(licenceId, reviewChargeReferenceId, request.yar) - - return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}/charge-reference-details/${reviewChargeReferenceId}`) -} - async function removeLicence (request, h) { const { id: billRunId, licenceId } = request.params @@ -189,7 +180,6 @@ module.exports = { cancel, index, matchDetails, - previewCharge, removeLicence, send, submitAmendedBillableReturns, diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index dbfccdb8b2..2c59bd5892 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -87,6 +87,18 @@ const routes = [ } } }, + { + method: 'GET', + path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}/preview', + options: { + handler: BillRunsReviewController.preview, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/bill-runs/review/licence/{reviewLicenceId}', diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index de0981b9f3..ed5d4d4c57 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -114,18 +114,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}/preview-charge/{reviewChargeReferenceId}', - options: { - handler: BillRunsController.previewCharge, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/send', From 05606cb901aaca560143c6ad60e71826919c02a1 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 30 Oct 2024 17:53:57 +0000 Subject: [PATCH 051/147] Housekeeping - Update path to module --- .../bill-runs/review/review-charge-reference.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/review-charge-reference.service.js b/app/services/bill-runs/review/review-charge-reference.service.js index 7bf3846d31..2fd1487e77 100644 --- a/app/services/bill-runs/review/review-charge-reference.service.js +++ b/app/services/bill-runs/review/review-charge-reference.service.js @@ -5,7 +5,7 @@ * @module ReviewChargeReferenceService */ -const FetchReviewChargeReferenceService = require('../review/fetch-review-charge-reference.service.js') +const FetchReviewChargeReferenceService = require('./fetch-review-charge-reference.service.js') const ReviewChargeReferencePresenter = require('../../../presenters/bill-runs/review/review-charge-reference.presenter.js') /** From 0e2b121b2216087033aea34877b8a766e8b20da3 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:14:02 +0000 Subject: [PATCH 052/147] Housekeeping - Make back links consistent Now all back links are 'Go back to review *' --- app/views/bill-runs/review/authorised.njk | 2 +- app/views/bill-runs/review/factors.njk | 2 +- app/views/bill-runs/review/review-charge-reference.njk | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/bill-runs/review/authorised.njk b/app/views/bill-runs/review/authorised.njk index c3ce376ca0..e5e2716983 100644 --- a/app/views/bill-runs/review/authorised.njk +++ b/app/views/bill-runs/review/authorised.njk @@ -8,7 +8,7 @@ {% block breadcrumbs %} {# Back link #} {{ govukBackLink({ - text: 'Go back to charge reference', + text: 'Go back to review charge reference', href: '/system/bill-runs/review/charge-reference/' + reviewChargeReferenceId }) }} {% endblock %} diff --git a/app/views/bill-runs/review/factors.njk b/app/views/bill-runs/review/factors.njk index 77df19c1d5..829b4d4c37 100644 --- a/app/views/bill-runs/review/factors.njk +++ b/app/views/bill-runs/review/factors.njk @@ -8,7 +8,7 @@ {% block breadcrumbs %} {# Back link #} {{ govukBackLink({ - text: 'Go back to charge reference', + text: 'Go back to review charge reference', href: '/system/bill-runs/review/charge-reference/' + reviewChargeReferenceId }) }} {% endblock %} diff --git a/app/views/bill-runs/review/review-charge-reference.njk b/app/views/bill-runs/review/review-charge-reference.njk index 0189b907c3..139b5f1a50 100644 --- a/app/views/bill-runs/review/review-charge-reference.njk +++ b/app/views/bill-runs/review/review-charge-reference.njk @@ -7,7 +7,7 @@ {% block breadcrumbs %} {# Back link #} {{ govukBackLink({ - text: 'Go back to licence', + text: 'Go back to review licence', href: '/system/bill-runs/review/licence/' + reviewLicenceId }) }} {% endblock %} From 96040a1110017c1c65e839e473b7b02eef4a4611 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:14:44 +0000 Subject: [PATCH 053/147] Housekeeping - fix indentation --- .../review/review-charge-reference.njk | 249 +++++++++--------- 1 file changed, 124 insertions(+), 125 deletions(-) diff --git a/app/views/bill-runs/review/review-charge-reference.njk b/app/views/bill-runs/review/review-charge-reference.njk index 139b5f1a50..77d4e3af7c 100644 --- a/app/views/bill-runs/review/review-charge-reference.njk +++ b/app/views/bill-runs/review/review-charge-reference.njk @@ -13,145 +13,144 @@ {% endblock %} {% block content %} - -{# Adjustment factor ammended banner #} -{% if bannerMessage %} - {{ govukNotificationBanner({ - titleText: 'Adjustment updated', - text: bannerMessage - }) }} -{% endif %} - -{# Charge preview banner #} -{% if chargeMessage %} - {{ govukNotificationBanner({ - titleText: 'Information', - text: chargeMessage - }) }} -{% endif %} - -{# Title area #} -
-
-

- Charge reference {{chargeCategory}}{{chargeDescription}} -

- Financial Year {{financialPeriod}} -

- Charge period {{chargePeriod}} -

+ {# Adjustment factor ammended banner #} + {% if bannerMessage %} + {{ govukNotificationBanner({ + titleText: 'Adjustment updated', + text: bannerMessage + }) }} + {% endif %} + + {# Charge preview banner #} + {% if chargeMessage %} + {{ govukNotificationBanner({ + titleText: 'Information', + text: chargeMessage + }) }} + {% endif %} + + {# Main heading #} +
+
+

+ Charge reference {{chargeCategory}}{{chargeDescription}} +

+ Financial Year {{financialPeriod}} +

+ Charge period {{chargePeriod}} +

+
-
-{# Return numbers ML #} -
-
-
-

- {{totalBillableReturns}} ML -
- Total billable returns -
-

-
-
-

- / -

-
-
-

- {{amendedAuthorisedVolume}} ML -
- Authorised volume -
-

+ {# Return numbers ML #} +
+
+
+

+ {{totalBillableReturns}} ML +
+ Total billable returns +
+

+
+
+

+ / +

+
+
+

+ {{amendedAuthorisedVolume}} ML +
+ Authorised volume +
+

+
-
-{# Buttons #} -
-
- {% if canAmend %} - + {# Buttons #} +
+
+ {% if canAmend %} + + {{ govukButton({ + text: "Change the authorised volume", + classes: "govuk-button--secondary", + preventDoubleClick: true, + href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/authorised" + }) }} + + {% endif %} + + {{ govukButton({ - text: "Change the authorised volume", + text: "Preview the charge", classes: "govuk-button--secondary", preventDoubleClick: true, - href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/authorised" + href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/preview" }) }} - {% endif %} - - - {{ govukButton({ - text: "Preview the charge", - classes: "govuk-button--secondary", - preventDoubleClick: true, - href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/preview" - }) }} - +
-
- -{# Reference details #} -{% if additionalCharges or adjustments.length > 0 %} -
-
-

Reference details

- - {% set adjustmentsValue %} - {% for adjustment in adjustments %} - {% set adjustmentsIndex = loop.index0 %} -
{{adjustment}}
- {% endfor %} - {% endset %} - - {% if canAmend %} - {% set showLink = { - items: [{ - href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/factors", - text: "Change factors" - }] - } - %} - {% endif %} - {% set tableRows = [] %} - {% if additionalCharges %} - {% set tableRow = { - key: { - text: "Additional charges" - }, - value: { - html: '
' + additionalCharges + '
' + {# Reference details #} + {% if additionalCharges or adjustments.length > 0 %} +
+
+

Reference details

+ + {% set adjustmentsValue %} + {% for adjustment in adjustments %} + {% set adjustmentsIndex = loop.index0 %} +
{{adjustment}}
+ {% endfor %} + {% endset %} + + {% if canAmend %} + {% set showLink = { + items: [{ + href: "/system/bill-runs/review/charge-reference/" + reviewChargeReferenceId + "/factors", + text: "Change factors" + }] } - } - %} - - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endif %} - - {% if adjustments %} - {% set tableRow = { - key: { - text: "Adjustments" - }, - value: { - html: adjustmentsValue - }, - actions: showLink - } - %} + %} + {% endif %} + + {% set tableRows = [] %} + {% if additionalCharges %} + {% set tableRow = { + key: { + text: "Additional charges" + }, + value: { + html: '
' + additionalCharges + '
' + } + } + %} + + {% set tableRows = (tableRows.push(tableRow), tableRows) %} + {% endif %} + + {% if adjustments %} + {% set tableRow = { + key: { + text: "Adjustments" + }, + value: { + html: adjustmentsValue + }, + actions: showLink + } + %} - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endif %} + {% set tableRows = (tableRows.push(tableRow), tableRows) %} + {% endif %} - {{ govukSummaryList({ - rows: tableRows - }) }} + {{ govukSummaryList({ + rows: tableRows + }) }} +

-

-{% endif %} + {% endif %} {% endblock %} From c3599f6fece88998ef59343f3e99edc8b3f500d8 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:15:26 +0000 Subject: [PATCH 054/147] Housekeeping - tidy up the view --- app/views/bill-runs/review/review-licence.njk | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/views/bill-runs/review/review-licence.njk b/app/views/bill-runs/review/review-licence.njk index 6833191fc3..0d8e065de5 100644 --- a/app/views/bill-runs/review/review-licence.njk +++ b/app/views/bill-runs/review/review-licence.njk @@ -30,10 +30,8 @@ {% endset %} {% set returnSummary %} -
- {{ return.purpose }} -
- {{ return.description }} +
{{ return.purpose }}
+ {{ return.description }} {% endset %} {% set tag %} @@ -62,9 +60,9 @@ attributes: { 'data-test': matchType + '-return-status-' + matchedReturnIndex } }, { - html: "
" + return.returnTotal + "
" + issues, + html: '
' + return.returnTotal + '
' + issues, classes: "govuk-body-s govuk-!-text-align-right", - attributes: { 'data-test': matchType + '-return-total-' + matchedReturnIndex} + attributes: { 'data-test': matchType + '-return-total-' + matchedReturnIndex } }] %} From db601f73c2970da23cfef79246a5f4b0aae30db6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:16:07 +0000 Subject: [PATCH 055/147] Housekeeping - make Fetch service's reuse clearer --- .../review/fetch-review-charge-reference.service.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/bill-runs/review/fetch-review-charge-reference.service.js b/app/services/bill-runs/review/fetch-review-charge-reference.service.js index 0ed570fa86..a2ad96e105 100644 --- a/app/services/bill-runs/review/fetch-review-charge-reference.service.js +++ b/app/services/bill-runs/review/fetch-review-charge-reference.service.js @@ -1,7 +1,7 @@ 'use strict' /** - * Fetches the selected review charge reference instance and related data for the 2PT review charge reference page + * Fetches the selected review charge reference instance and related data for the 2PT review charge reference pages * @module FetchReviewChargeReferenceService */ @@ -10,12 +10,15 @@ const { ref } = require('objection') const ReviewChargeReferenceModel = require('../../../models/review-charge-reference.model.js') /** - * Fetches the selected review charge reference instance and related data for the 2PT review charge reference page + * Fetches the selected review charge reference instance and related data for the 2PT review charge reference pages + * + * This fetch service fetches the data needed for the main review charge reference page, but also the authorised, + * factors and preview charge pages/services. * * @param {string} reviewChargeReferenceId - the UUID of the selected review charge reference * * @returns {module:ReviewChargeReferenceModel} the matching `ReviewChargeReferenceModel` instance and related data - * needed for the two-part tariff review charge reference page + * needed for the two-part tariff review charge reference page and sub-pages */ async function go (reviewChargeReferenceId) { return _fetch(reviewChargeReferenceId) From 2b21f8113eaf1f642ffb2ae30a25570bb476993e Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:17:24 +0000 Subject: [PATCH 056/147] Move, rename & refactor chg element presenter --- .../review/review-charge-element.presenter.js | 137 +++++++++++++++++ .../match-details.presenter.js | 143 ------------------ 2 files changed, 137 insertions(+), 143 deletions(-) create mode 100644 app/presenters/bill-runs/review/review-charge-element.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/match-details.presenter.js diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js new file mode 100644 index 0000000000..fc7796aa7c --- /dev/null +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -0,0 +1,137 @@ +'use strict' + +/** + * Formats the review charge element data ready for presenting in the review charge element page + * @module ReviewChargeElementPresenter + */ + +const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') +const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') + +/** + * Formats the review charge element data ready for presenting in the review charge element page + * + * @param {module:ReviewChargeElement} reviewChargeElement - instance of the `ReviewChargeElementModel` + * returned from `FetchReviewChargeElementService` + * @param {number} elementIndex - the index of the element within all charge elements for the charge reference. This + * helps users relate which element they are reviewing to the one they selected on the review licence screen + * + * @returns {object} page date needed for the review charge element page + */ +function go (reviewChargeElement, elementIndex) { + const { + amendedAllocated: billableReturns, + chargeElement, + id: reviewChargeElementId, + issues, + reviewChargeReference, + status + } = reviewChargeElement + + const chargePeriod = _chargePeriod(reviewChargeReference.reviewChargeVersion) + + return { + authorisedVolume: chargeElement.authorisedAnnualQuantity, + billableReturns, + chargeDescription: chargeElement.description, + chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, + chargePeriods: _chargePeriods(chargeElement, chargePeriod), + caption: `Element ${elementIndex} of ${reviewChargeReference.reviewChargeElements.length}`, + financialPeriod: formatFinancialYear( + reviewChargeReference.reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding + ), + issues: issues.length > 0 ? issues.split(', ') : [], + licenceId: reviewChargeReference.reviewChargeVersion.reviewLicence.licenceId, + matchedReturns: _matchedReturns(reviewChargeElement.reviewReturns), + reviewChargeElementId, + reviewLicenceId: reviewChargeReference.reviewChargeVersion.reviewLicence.id, + status + } +} + +function _chargePeriod (reviewChargeVersion) { + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion + + return { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } +} + +function _chargePeriods (chargeElement, chargePeriod) { + const { + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + } = chargeElement + + const abstractionPeriods = DetermineAbstractionPeriodService.go( + chargePeriod, + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + ) + + return abstractionPeriods.map((abstractionPeriod) => { + const { endDate, startDate } = abstractionPeriod + + return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` + }) +} + +function _matchedReturns (reviewReturns) { + return reviewReturns.map((reviewReturn) => { + const { description, endDate, issues, purposes, returnLog, returnId, returnReference, startDate } = reviewReturn + const { periodStartDay, periodStartMonth, periodEndDay, periodEndMonth } = returnLog + + return { + abstractionPeriod: formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth), + description, + issues: issues.length > 0 ? issues.split(', ') : [''], + purpose: purposes[0].tertiary.description, + reference: returnReference, + returnId, + returnLink: _returnLink(reviewReturn), + returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, + returnStatus: _returnStatus(reviewReturn), + returnTotal: _returnTotal(reviewReturn) + } + }) +} + +function _returnLink (reviewReturn) { + const { returnId, returnStatus } = reviewReturn + + if (['due', 'received'].includes(returnStatus)) { + return `/return/internal?returnId=${returnId}` + } + + return `/returns/return?id=${returnId}` +} + +function _returnStatus (reviewReturn) { + const { returnStatus, underQuery } = reviewReturn + + if (returnStatus === 'due') { + return 'overdue' + } + + if (underQuery) { + return 'query' + } + + return reviewReturn.returnStatus +} + +function _returnTotal (reviewReturn) { + const { allocated, quantity, returnStatus } = reviewReturn + + if (['due', 'received'].includes(returnStatus)) { + return '/' + } + + return `${allocated} ML / ${quantity} ML` +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/match-details.presenter.js b/app/presenters/bill-runs/two-part-tariff/match-details.presenter.js deleted file mode 100644 index 6b29fde8eb..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/match-details.presenter.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict' - -/** - * Formats the charge element and returns data ready for presenting in the match details page - * @module MatchDetailsPresenter - */ - -const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') -const { formatAbstractionPeriod, formatLongDate } = require('../../base.presenter.js') - -/** - * Prepares and processes bill run and review charge element and returns data for presentation - * - * @param {module:BillRunModel} billRun - the data from the bill run - * @param {module:ReviewChargeElement} reviewChargeElement - the data from the review charge element - * @param {string} licenceId - the UUID of the licence the charge element is linked to - * - * @returns {object} the prepared bill run and charge element data to be passed to the match details page - */ -function go (billRun, reviewChargeElement, licenceId) { - return { - billRunId: billRun.id, - financialYear: _financialYear(billRun.toFinancialYearEnding), - chargePeriod: _prepareDate( - reviewChargeElement.reviewChargeReference.reviewChargeVersion.chargePeriodStartDate, - reviewChargeElement.reviewChargeReference.reviewChargeVersion.chargePeriodEndDate - ), - licenceId, - chargeElement: { - chargeElementId: reviewChargeElement.id, - description: reviewChargeElement.chargeElement.description, - dates: _prepareChargeElementDates( - reviewChargeElement.chargeElement, - reviewChargeElement.reviewChargeReference.reviewChargeVersion - ), - status: reviewChargeElement.status, - billableVolume: reviewChargeElement.amendedAllocated, - authorisedVolume: reviewChargeElement.chargeElement.authorisedAnnualQuantity, - issues: reviewChargeElement.issues?.length > 0 ? reviewChargeElement.issues.split(', ') : [] - }, - matchedReturns: _matchedReturns(reviewChargeElement.reviewReturns) - } -} - -function _financialYear (financialYearEnding) { - const startYear = financialYearEnding - 1 - const endYear = financialYearEnding - - return `${startYear} to ${endYear}` -} - -function _prepareAbsPeriod (returnLog) { - const { periodStartDay, periodStartMonth, periodEndDay, periodEndMonth } = returnLog - - return formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth) -} - -function _matchedReturns (reviewReturns) { - const matchedReturns = [] - - reviewReturns.forEach((returnLog) => { - const { returnLink, returnTotal } = _returnLinkAndTotal(returnLog) - - matchedReturns.push({ - returnId: returnLog.returnId, - reference: returnLog.returnReference, - dates: _prepareDate(returnLog.startDate, returnLog.endDate), - purpose: returnLog.purposes[0]?.tertiary.description, - description: returnLog.description, - returnStatus: _returnStatus(returnLog), - returnTotal, - issues: returnLog.issues?.length > 0 ? returnLog.issues.split(', ') : [''], - returnLink, - absPeriod: _prepareAbsPeriod(returnLog.returnLog) - }) - }) - - return matchedReturns -} - -function _prepareChargeElementDates (chargeElement, chargeVersion) { - const chargePeriod = { - startDate: chargeVersion.chargePeriodStartDate, - endDate: chargeVersion.chargePeriodEndDate - } - - const { - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - } = chargeElement - - const abstractionPeriods = DetermineAbstractionPeriodService.go( - chargePeriod, - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - ) - - const dates = [] - - // NOTE: There can be more than 1 abstraction period for an element, hence why we loop through them - abstractionPeriods.forEach((abstractionPeriod) => { - dates.push(_prepareDate(abstractionPeriod.startDate, abstractionPeriod.endDate)) - }) - - return dates -} - -function _prepareDate (startDate, endDate) { - const preparedStartDate = formatLongDate(startDate) - const preparedEndDate = formatLongDate(endDate) - - return `${preparedStartDate} to ${preparedEndDate}` -} - -function _returnLinkAndTotal (returnLog) { - const { returnStatus, allocated, quantity } = returnLog - - if (['due', 'received'].includes(returnStatus)) { - return { returnTotal: '/', returnLink: `/return/internal?returnId=${returnLog.returnId}` } - } - - return { returnTotal: `${allocated} ML / ${quantity} ML`, returnLink: `/returns/return?id=${returnLog.returnId}` } -} - -function _returnStatus (returnLog) { - if (returnLog.returnStatus === 'due') { - return 'overdue' - } - - if (returnLog.underQuery) { - return 'query' - } - - return returnLog.returnStatus -} - -module.exports = { - go -} From a544f6ba56709f95cf013df1f06df75ade844412 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:18:29 +0000 Subject: [PATCH 057/147] Move, rename & refactor fetch chg element service --- .../fetch-review-charge-element.service.js | 116 ++++++++++++++++++ .../fetch-match-details.service.js | 78 ------------ 2 files changed, 116 insertions(+), 78 deletions(-) create mode 100644 app/services/bill-runs/review/fetch-review-charge-element.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/fetch-match-details.service.js diff --git a/app/services/bill-runs/review/fetch-review-charge-element.service.js b/app/services/bill-runs/review/fetch-review-charge-element.service.js new file mode 100644 index 0000000000..c9ba3ed900 --- /dev/null +++ b/app/services/bill-runs/review/fetch-review-charge-element.service.js @@ -0,0 +1,116 @@ +'use strict' + +/** + * Fetches the selected review charge element instance and related data for the 2PT review charge element page + * @module FetchReviewChargeReferenceService + */ + +const { ref } = require('objection') + +const ReviewChargeElementModel = require('../../../models/review-charge-element.model.js') + +/** + * Fetches the match details for an individual charge element + * + * @param {string} reviewChargeElementId - The UUID of the review charge element being viewed + * + * @returns {Promise} An object containing the bill run and review charge element instances + */ +async function go (reviewChargeElementId) { + return _fetch(reviewChargeElementId) +} + +async function _fetch (reviewChargeElementId) { + return ReviewChargeElementModel.query() + .findById(reviewChargeElementId) + .select([ + 'id', + 'amendedAllocated', + 'issues', + 'status' + ]) + .withGraphFetched('chargeElement') + .modifyGraph('chargeElement', (builder) => { + builder + .select([ + 'id', + 'abstractionPeriodStartDay', + 'abstractionPeriodStartMonth', + 'abstractionPeriodEndDay', + 'abstractionPeriodEndMonth', + 'authorisedAnnualQuantity', + 'description' + ]) + }) + .withGraphFetched('reviewChargeReference') + .modifyGraph('reviewChargeReference', (builder) => { + builder + .select([ + 'id', + 'amendedAuthorisedVolume' + ]) + .withGraphFetched('reviewChargeElements') + .modifyGraph('reviewChargeElements', (builder) => { + builder + .select(['id']) + }) + .withGraphFetched('reviewChargeVersion') + .modifyGraph('reviewChargeVersion', (builder) => { + builder + .select([ + 'id', + 'chargePeriodStartDate', + 'chargePeriodEndDate' + ]).withGraphFetched('reviewLicence') + .modifyGraph('reviewLicence', (builder) => { + builder + .select([ + 'id', + 'licenceId' + ]) + .withGraphFetched('billRun') + .modifyGraph('billRun', (builder) => { + builder + .select([ + 'id', + 'toFinancialYearEnding' + ]) + }) + }) + }) + }) + .withGraphFetched('reviewReturns') + .modifyGraph('reviewReturns', (builder) => { + builder + .select([ + 'reviewReturns.id', + 'reviewReturns.allocated', + 'reviewReturns.description', + 'reviewReturns.endDate', + 'reviewReturns.issues', + 'reviewReturns.quantity', + 'reviewReturns.purposes', + 'reviewReturns.returnId', + 'reviewReturns.returnReference', + 'reviewReturns.returnStatus', + 'reviewReturns.startDate', + 'reviewReturns.underQuery' + ]) + .orderBy('reviewReturns.startDate', 'asc') + .withGraphFetched('returnLog') + .modifyGraph('returnLog', (builder) => { + builder + .select([ + 'id', + ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), + ref('metadata:nald.periodStartMonth').castInt().as('periodStartMonth'), + ref('metadata:nald.periodEndDay').castInt().as('periodEndDay'), + ref('metadata:nald.periodEndMonth').castInt().as('periodEndMonth') + ]) + }) + }) +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/fetch-match-details.service.js b/app/services/bill-runs/two-part-tariff/fetch-match-details.service.js deleted file mode 100644 index e5b396fe83..0000000000 --- a/app/services/bill-runs/two-part-tariff/fetch-match-details.service.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict' - -/** - * Fetches the individual charge element match details during the review stage of a two-part tariff bill run - * @module FetchMatchDetailsService - */ - -const { ref } = require('objection') - -const BillRunModel = require('../../../models/bill-run.model.js') -const ReviewChargeElementModel = require('../../../models/review-charge-element.model.js') - -/** - * Fetches the match details for an individual charge element - * - * @param {string} billRunId - UUID of the bill run - * @param {string} reviewChargeElementId - The UUID of the review charge element being viewed - * - * @returns {Promise} An object containing the bill run and review charge element instances - */ -async function go (billRunId, reviewChargeElementId) { - const billRun = await _fetchBillRun(billRunId) - const reviewChargeElement = await _fetchReviewChargeElement(reviewChargeElementId) - - return { billRun, reviewChargeElement } -} - -async function _fetchBillRun (billRunId) { - return BillRunModel.query() - .findById(billRunId) - .select( - 'id', - 'fromFinancialYearEnding', - 'toFinancialYearEnding') -} - -async function _fetchReviewChargeElement (reviewChargeElementId) { - return ReviewChargeElementModel.query() - .findById(reviewChargeElementId) - .withGraphFetched('reviewReturns') - .withGraphFetched('reviewReturns.returnLog') - .modifyGraph('reviewReturns.returnLog', (builder) => { - builder.select([ - ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), - ref('metadata:nald.periodStartMonth').castInt().as('periodStartMonth'), - ref('metadata:nald.periodEndDay').castInt().as('periodEndDay'), - ref('metadata:nald.periodEndMonth').castInt().as('periodEndMonth')]) - }) - .withGraphFetched('chargeElement') - .modifyGraph('chargeElement', (builder) => { - builder.select([ - 'description', - 'abstractionPeriodStartDay', - 'abstractionPeriodStartMonth', - 'abstractionPeriodEndDay', - 'abstractionPeriodEndMonth', - 'authorisedAnnualQuantity' - ]) - }) - .withGraphFetched('reviewChargeReference') - .modifyGraph('reviewChargeReference', (builder) => { - builder.select([ - 'id', - 'amendedAuthorisedVolume' - ]) - }) - .withGraphFetched('reviewChargeReference.reviewChargeVersion') - .modifyGraph('reviewChargeReference.reviewChargeVersion', (builder) => { - builder.select([ - 'chargePeriodStartDate', - 'chargePeriodEndDate' - ]) - }) -} - -module.exports = { - go -} From 3d0fc35e7460eb1f452a71c79d6e80fc6fd69521 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:19:24 +0000 Subject: [PATCH 058/147] Move, rename & refactor chg element service --- .../review/review-charge-element.service.js | 37 +++++++++++++++++++ .../two-part-tariff/match-details.service.js | 36 ------------------ 2 files changed, 37 insertions(+), 36 deletions(-) create mode 100644 app/services/bill-runs/review/review-charge-element.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/match-details.service.js diff --git a/app/services/bill-runs/review/review-charge-element.service.js b/app/services/bill-runs/review/review-charge-element.service.js new file mode 100644 index 0000000000..c5bd75a7ed --- /dev/null +++ b/app/services/bill-runs/review/review-charge-element.service.js @@ -0,0 +1,37 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data needed for the review charge element page + * @module ReviewChargeElementService + */ + +const FetchReviewChargeElementService = require('./fetch-review-charge-element.service.js') +const ReviewChargeElementPresenter = require('../../../presenters/bill-runs/review/review-charge-element.presenter.js') + +/** + * Orchestrates fetching and presenting the data needed for the review charge element page + * + * @param {string} reviewChargeElementId - The UUID of the charge element being reviewed + * @param {number} elementIndex - the index of the element within all charge elements for the charge reference. This + * helps users relate which element they are reviewing to the one they selected on the review licence screen + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * + * @returns {Promise} the 'pageData' needed for the review charge element page + */ +async function go (reviewChargeElementId, elementIndex, yar) { + const reviewChargeElement = await FetchReviewChargeElementService.go(reviewChargeElementId) + + const [bannerMessage] = yar.flash('banner') + + const pageData = ReviewChargeElementPresenter.go(reviewChargeElement, elementIndex) + + return { + bannerMessage, + pageTitle: 'Review charge element', + ...pageData + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/match-details.service.js b/app/services/bill-runs/two-part-tariff/match-details.service.js deleted file mode 100644 index ba4147c3b9..0000000000 --- a/app/services/bill-runs/two-part-tariff/match-details.service.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' - -/** - * Orchestrates fetching and presenting the data needed for the match details page on a charge element in a - * two-part tariff bill run - * @module MatchDetailsService - */ - -const FetchMatchDetailsService = require('./fetch-match-details.service.js') -const MatchDetailsPresenter = require('../../../presenters/bill-runs/two-part-tariff/match-details.presenter.js') - -/** - * Orchestrates fetching and presenting the data needed for the view match details page for a charge element - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeElementId - The UUID of the review charge element being viewed - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - * - * @returns {Promise} the 'pageData' needed to view the match details of an individual charge - */ -async function go (billRunId, licenceId, reviewChargeElementId, yar) { - const { billRun, reviewChargeElement } = await FetchMatchDetailsService.go(billRunId, reviewChargeElementId) - - const [bannerMessage] = yar.flash('banner') - const pageData = MatchDetailsPresenter.go(billRun, reviewChargeElement, licenceId) - - return { - bannerMessage, - ...pageData - } -} - -module.exports = { - go -} From a5578dea33e5d575bcc96a8da19594bd7f482a76 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:20:19 +0000 Subject: [PATCH 059/147] Update review licence to pass thru element index --- app/presenters/bill-runs/review/review-licence.presenter.js | 3 ++- app/views/bill-runs/review/review-licence.njk | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index 4477f0a338..62a46cd285 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -70,7 +70,8 @@ function _chargeElements (reviewChargeElements, chargePeriod) { chargePeriods: _chargeElementChargePeriod(chargeElement, chargePeriod), returnVolumes: _chargeElementReturnVolumes(reviewReturns), description: chargeElement.description, - elementNumber: `Element ${index + 1} of ${numberOfElements}`, + elementCount: numberOfElements, + elementIndex: index + 1, status, id, issues: issues.length > 0 ? issues.split(', ') : [''], diff --git a/app/views/bill-runs/review/review-licence.njk b/app/views/bill-runs/review/review-licence.njk index 0d8e065de5..5cafd2803a 100644 --- a/app/views/bill-runs/review/review-licence.njk +++ b/app/views/bill-runs/review/review-licence.njk @@ -347,7 +347,7 @@ {% set elementRows = [] %}
- {{chargeElement.elementNumber}} + Element {{chargeElement.elementIndex}} of {{chargeElement.elementCount}} {{ statusTag(chargeElement.status) }} @@ -389,7 +389,7 @@ actions: { items: [ { - href: '/system/bill-runs/review/charge-element/' + chargeElement.id, + href: '/system/bill-runs/review/charge-element/' + chargeElement.id + '/' + chargeElement.elementIndex, html: '
View match details
' } ]} From 4b33a990d4af21c38047999d6a7bde99d0ad4c36 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:21:01 +0000 Subject: [PATCH 060/147] Move, rename & refactor chg element view --- app/views/bill-runs/match-details.njk | 230 ------------------ .../review/review-charge-element.njk | 212 ++++++++++++++++ 2 files changed, 212 insertions(+), 230 deletions(-) delete mode 100644 app/views/bill-runs/match-details.njk create mode 100644 app/views/bill-runs/review/review-charge-element.njk diff --git a/app/views/bill-runs/match-details.njk b/app/views/bill-runs/match-details.njk deleted file mode 100644 index 95a47ddf29..0000000000 --- a/app/views/bill-runs/match-details.njk +++ /dev/null @@ -1,230 +0,0 @@ -{% extends 'layout.njk' %} -{% from "govuk/components/back-link/macro.njk" import govukBackLink %} -{% from "govuk/components/tag/macro.njk" import govukTag %} -{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %} -{% from "govuk/components/table/macro.njk" import govukTable %} -{% from "govuk/components/button/macro.njk" import govukButton %} -{% from "macros/review-status-tag.njk" import statusTag %} -{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %} - -{% block breadcrumbs %} - {# Back link #} - {{ govukBackLink({ - text: 'Go back to licence', - href: '/system/bill-runs/' + billRunId + '/review/' + licenceId - }) }} -{% endblock %} - -{% block content %} - {# Billable returns ammended banner #} - {% if bannerMessage %} - {{ govukNotificationBanner({ - titleText: 'Element updated', - text: bannerMessage - }) }} - {% endif %} - -
-
-

- {{ chargeElement.description }} -
{{ chargeElement.dates }}
-

- -

- {{ statusTag(chargeElement.status) }} -

- - {# Licence nav bars #} - -
-
- -
Financial year {{ financialYear }}
-

Charge period {{ chargePeriod }}

- - {# Billable returns and volume #} -
-
-
-

-
- {{chargeElement.billableVolume}}ML -
-
- Billable returns -
-

-
-
-

-
- / -
-

-
-
-

-
- {{chargeElement.authorisedVolume}}ML -
-
- Authorised volume -
-

-
-
-

- {% if chargeElement.issues.length > 0 %} -
-

- Issue -

- {% for issue in chargeElement.issues %} - {% set issuesIndex = loop.index0 %} -
{{ issue }}
- {% endfor %} -
- {% endif %} -

-
-
-
- - {# Billable returns button #} -
-
- {{ govukButton({ - text: "Edit the billable returns", - href: "/system/bill-runs/" + billRunId + "/review/" + licenceId + "/match-details/" + chargeElement.chargeElementId + "/amend-billable-returns", - classes: "govuk-button--secondary", - preventDoubleClick: true - }) }} -
-
- - - {# Matched Returns #} - {% if matchedReturns.length > 0 %} - {% set tableRows = [] %} - {% for return in matchedReturns %} - {% set matchedReturnIndex = loop.index0 %} - - {% set action %} - {{ return.reference }} -
{{ return.dates }}
-
{{return.absPeriod}}
- {% endset %} - - {% set returnSummary %} -
- {{ return.purpose }} -
- {{ return.description }} - {% endset %} - - {% set tag %} - {{ statusTag(return.returnStatus) }} - {% endset %} - - {% set issues = '' %} - {% for issue in return.issues %} - {% set issues = issues + '
' + issue + '
' %} - {% endfor %} - - {% set tableRow = [ - { - html: '
' + action + '
', - classes: 'govuk-body-s' - }, - { - html: '
' + returnSummary + '
', - classes: 'govuk-body-s' - }, - { - html: '
' + tag + '
', - classes: 'govuk-body-s' - }, - { - html: '
' + return.returnTotal + '
' + issues + '
' , - classes: "govuk-body-s govuk-!-text-align-right" - }] - %} - - {% set tableRows = (tableRows.push(tableRow), tableRows) %} - {% endfor %} - - {# Table displaying details of the matched returns #} - {{ govukTable({ - caption: "Matched returns", - captionClasses: "govuk-table__caption--m", - attributes: { 'data-test': 'matched-returns' }, - firstCellIsHeader: false, - head: [ - { - text: 'Return reference and periods' - }, - { - text: 'Purpose and description' - }, - { - text: 'Status' - }, - { - text: 'Return totals Allocated/Total', - format: 'numeric', - classes: 'width-one-tenth' - } - ], - rows: tableRows - }) }} - {% endif %} - - {# No Returns #} - {% if matchedReturns == 0 %} -

No two-part tariff returns

- {% endif %} -{% endblock %} diff --git a/app/views/bill-runs/review/review-charge-element.njk b/app/views/bill-runs/review/review-charge-element.njk new file mode 100644 index 0000000000..bef7d3e0a9 --- /dev/null +++ b/app/views/bill-runs/review/review-charge-element.njk @@ -0,0 +1,212 @@ +{% extends 'layout.njk' %} +{% from "govuk/components/back-link/macro.njk" import govukBackLink %} +{% from "govuk/components/tag/macro.njk" import govukTag %} +{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %} +{% from "govuk/components/table/macro.njk" import govukTable %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from "macros/review-status-tag.njk" import statusTag %} +{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %} + +{% block breadcrumbs %} + {# Back link #} + {{ govukBackLink({ + text: 'Go back to review licence', + href: '/system/bill-runs/review/licence/' + reviewLicenceId + }) }} +{% endblock %} + +{% block content %} + {# Billable returns ammended banner #} + {% if bannerMessage %} + {{ govukNotificationBanner({ + titleText: 'Element updated', + text: bannerMessage + }) }} + {% endif %} + + {# Main heading #} +
+
+ {{caption}} +

{{ chargeDescription }}

+ + {% for chargePeriod in chargePeriods %} + {% set chargePeriodIndex = loop.index0 %} +

{{ chargePeriod }}

+ {% endfor %} +
+
+ +
+
+ {{ statusTag(status) }} +
+
+ + {# Licence nav bars #} + + + {# Periods #} + Financial year {{financialPeriod}} +

Charge period {{chargePeriod}}

+ + {# Billable returns, authorised volume and issues #} +
+
+
+

+ {{billableReturns}} ML +
+ Billable returns +
+

+
+
+

+ / +

+
+
+

+ {{authorisedVolume}} ML +
+ Authorised volume +
+

+
+ + {% if issues.length > 0 %} +
+

+
+

Issues

+ {% for issue in issues %} + {% set issuesIndex = loop.index0 %} +
{{issue}}
+ {% endfor %} +
+

+
+ {% endif %} +
+
+ + {# Billable returns button #} +
+
+ {{ govukButton({ + text: "Edit the billable returns", + href: "/system/bill-runs/review/charge-element/" + reviewChargeElementId + "/edit", + classes: "govuk-button--secondary", + preventDoubleClick: true + }) }} +
+
+ + + {# Matched Returns #} + {% if matchedReturns.length > 0 %} + {% set tableRows = [] %} + {% for return in matchedReturns %} + {% set returnIndex = loop.index0 %} + + {% set action %} + {{ return.reference }} +
{{return.returnPeriod}}
+
{{return.abstractionPeriod}}
+ {% endset %} + + {% set returnSummary %} +
{{ return.purpose }}
+ {{ return.description }} + {% endset %} + + {% set tag %} + {{ statusTag(return.returnStatus) }} + {% endset %} + + {% set issues = '' %} + {% for issue in return.issues %} + {% set issues = issues + '
' + issue + '
' %} + {% endfor %} + + {% set tableRow = [ + { + html: action, + classes: 'govuk-body-s', + attributes: { 'data-test': 'matched-return-action-' + returnIndex } + }, + { + html: returnSummary, + classes: 'govuk-body-s', + attributes: { 'data-test': 'matched-return-summary-' + returnIndex } + }, + { + html: tag, + classes: 'govuk-body-s', + attributes: { 'data-test': 'matched-return-status-' + returnIndex } + }, + { + html: '
' + return.returnTotal + '
' + issues, + classes: "govuk-body-s govuk-!-text-align-right", + attributes: { 'data-test': 'matched-return-total-' + returnIndex } + }] + %} + + {% set tableRows = (tableRows.push(tableRow), tableRows) %} + {% endfor %} + + {# Table displaying details of the matched returns #} + {{ govukTable({ + caption: "Matched returns", + captionClasses: "govuk-table__caption--m", + attributes: { 'data-test': 'matched-returns' }, + firstCellIsHeader: false, + head: [ + { + text: 'Return reference and periods' + }, + { + text: 'Purpose and description' + }, + { + text: 'Status' + }, + { + text: 'Return totals Allocated/Total', + format: 'numeric', + classes: 'width-one-tenth' + } + ], + rows: tableRows + }) }} + {% else %} +

No matching two-part tariff returns

+ {% endif %} +{% endblock %} From 28d3c786e5746dd944f017aa65bc2720c82075c1 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:21:35 +0000 Subject: [PATCH 061/147] Move chg element routes & controllers to /review --- app/controllers/bill-runs-review.controller.js | 13 +++++++++++++ app/controllers/bill-runs.controller.js | 14 -------------- app/routes/bill-runs-review.routes.js | 12 ++++++++++++ app/routes/bill-runs.routes.js | 12 ------------ 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 39314bed85..a60276810e 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -8,6 +8,7 @@ const AuthorisedService = require('../services/bill-runs/review/authorised.service.js') const FactorsService = require('../services/bill-runs/review/factors.service.js') const PreviewService = require('../services/bill-runs/review/preview.service.js') +const ReviewChargeElementService = require('../services/bill-runs/review/review-charge-element.service.js') const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') @@ -58,6 +59,17 @@ async function review (request, h) { }) } +async function reviewChargeElement (request, h) { + const { elementIndex, reviewChargeElementId } = request.params + + const pageData = await ReviewChargeElementService.go(reviewChargeElementId, elementIndex, request.yar) + + return h.view('bill-runs/review/review-charge-element.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function reviewChargeReference (request, h) { const { reviewChargeReferenceId } = request.params @@ -123,6 +135,7 @@ module.exports = { factors, preview, review, + reviewChargeElement, reviewChargeReference, reviewLicence, submitAuthorised, diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index fff909386f..80c080e7d1 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -11,7 +11,6 @@ const AmendBillableReturnsService = require('../services/bill-runs/two-part-tari const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js') const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/generate-bill-run.service.js') const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') -const MatchDetailsService = require('../services/bill-runs/two-part-tariff/match-details.service.js') const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') const SubmitAmendedBillableReturnsService = require('..//services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') @@ -55,18 +54,6 @@ async function index (request, h) { }) } -async function matchDetails (request, h) { - const { id: billRunId, licenceId, reviewChargeElementId } = request.params - - const pageData = await MatchDetailsService.go(billRunId, licenceId, reviewChargeElementId, request.yar) - - return h.view('bill-runs/match-details.njk', { - pageTitle: 'View match details', - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function removeLicence (request, h) { const { id: billRunId, licenceId } = request.params @@ -179,7 +166,6 @@ module.exports = { amendBillableReturns, cancel, index, - matchDetails, removeLicence, send, submitAmendedBillableReturns, diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 2c59bd5892..2f168d5f56 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -27,6 +27,18 @@ const routes = [ } } }, + { + method: 'GET', + path: '/bill-runs/review/charge-element/{reviewChargeElementId}/{elementIndex}', + options: { + handler: BillRunsReviewController.reviewChargeElement, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}', diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index ed5d4d4c57..1ef5a9440c 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -78,18 +78,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}', - options: { - handler: BillRunsController.matchDetails, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}/amend-billable-returns', From 3bfa65db9e18d9c1e46fa968a339cc3966699856 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 31 Oct 2024 09:21:58 +0000 Subject: [PATCH 062/147] Housekeeping - Make chg ref page title consistent --- .../bill-runs/review/review-charge-reference.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/review-charge-reference.service.js b/app/services/bill-runs/review/review-charge-reference.service.js index 2fd1487e77..62e0890164 100644 --- a/app/services/bill-runs/review/review-charge-reference.service.js +++ b/app/services/bill-runs/review/review-charge-reference.service.js @@ -26,7 +26,7 @@ async function go (reviewChargeReferenceId, yar) { const pageData = ReviewChargeReferencePresenter.go(reviewChargeReference) return { - pageTitle: 'Charge reference details', + pageTitle: 'Review charge reference', bannerMessage, chargeMessage, ...pageData From 28cb7a6b899fd5ffe8c028a912a2fa16299bbaae Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:44:12 +0000 Subject: [PATCH 063/147] Move, rename & refactor chg element edit presenter --- .../bill-runs/review/edit.presenter.js | 89 +++++++++++++++ .../amend-billable-returns.presenter.js | 105 ------------------ 2 files changed, 89 insertions(+), 105 deletions(-) create mode 100644 app/presenters/bill-runs/review/edit.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js diff --git a/app/presenters/bill-runs/review/edit.presenter.js b/app/presenters/bill-runs/review/edit.presenter.js new file mode 100644 index 0000000000..a311997538 --- /dev/null +++ b/app/presenters/bill-runs/review/edit.presenter.js @@ -0,0 +1,89 @@ +'use strict' + +/** + * Formats the review charge element data ready for presenting in the review charge element edit page + * @module EditPresenter + */ + +const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') +const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js') + +/** + * Prepares and processes bill run and review charge element data for presenting + * + * @param {module:ReviewChargeElement} reviewChargeElement - instance of the `ReviewChargeElementModel` + * returned from `FetchReviewChargeElementService` + * @param {number} elementIndex - the index of the element within all charge elements for the charge reference. This + * helps users relate which element they are reviewing to the one they selected on the review licence screen + * + * @returns {object} the prepared bill run and charge element data to be passed to the edit billable returns page + */ +function go (reviewChargeElement, elementIndex) { + const { + amendedAllocated: billableReturns, + chargeElement, + id: reviewChargeElementId, + reviewChargeReference + } = reviewChargeElement + + const chargePeriod = _chargePeriod(reviewChargeReference.reviewChargeVersion) + + return { + authorisedQuantity: _authorisedQuantity(reviewChargeElement), + billableReturns, + chargeDescription: chargeElement.description, + chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, + chargePeriods: _chargePeriods(chargeElement, chargePeriod), + elementIndex, + financialPeriod: formatFinancialYear( + reviewChargeReference.reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding + ), + reviewChargeElementId + } +} + +/** + * The user can only enter a volume on the billable returns that is less than the authorised volume. The authorised + * volume is either the authorised volume on the charge element or the authorised volume on the charge reference. + * Whichever is lower. + * + * @private + */ +function _authorisedQuantity (reviewChargeElement) { + const { chargeElement, reviewChargeReference } = reviewChargeElement + + return Math.min(chargeElement.authorisedAnnualQuantity, reviewChargeReference.amendedAuthorisedVolume) +} + +function _chargePeriod (reviewChargeVersion) { + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion + + return { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } +} + +function _chargePeriods (chargeElement, chargePeriod) { + const { + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + } = chargeElement + + const abstractionPeriods = DetermineAbstractionPeriodService.go( + chargePeriod, + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + ) + + return abstractionPeriods.map((abstractionPeriod) => { + const { endDate, startDate } = abstractionPeriod + + return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` + }) +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js b/app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js deleted file mode 100644 index a725a738d8..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js +++ /dev/null @@ -1,105 +0,0 @@ -'use strict' - -/** - * Formats the two part tariff review data ready for presenting in the edit billable returns page - * @module AmendBillableReturnsPresenter - */ - -const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') -const { formatLongDate } = require('../../base.presenter.js') - -/** - * Prepares and processes bill run and review charge element data for presenting - * - * @param {module:BillRunModel} billRun - the data from the bill run - * @param {module:ReviewChargeElement} reviewChargeElement - the data from the review charge element - * @param {string} licenceId - the UUID of the licence being reviewed - * - * @returns {object} the prepared bill run and charge element data to be passed to the edit billable returns page - */ -function go (billRun, reviewChargeElement, licenceId) { - return { - chargeElement: { - description: reviewChargeElement.chargeElement.description, - dates: _prepareChargeElementDates( - reviewChargeElement.chargeElement, - reviewChargeElement.reviewChargeReference.reviewChargeVersion - ), - reviewChargeElementId: reviewChargeElement.id - }, - billRun: { - id: billRun.id, - financialYear: _financialYear(billRun.toFinancialYearEnding) - }, - chargeVersion: { - chargePeriod: _prepareDate( - reviewChargeElement.reviewChargeReference.reviewChargeVersion.chargePeriodStartDate, - reviewChargeElement.reviewChargeReference.reviewChargeVersion.chargePeriodEndDate - ) - }, - licenceId, - authorisedQuantity: _authorisedQuantity(reviewChargeElement) - } -} - -/** - * The user can only enter a volume on the billable returns that is less than the authorised volume. The authorised - * volume is either the authorised volume on the charge element or the authorised volume on the charge reference. - * Whichever is lower. - * - * @private - */ -function _authorisedQuantity (reviewChargeElement) { - const { chargeElement, reviewChargeReference } = reviewChargeElement - - return Math.min(chargeElement.authorisedAnnualQuantity, reviewChargeReference.amendedAuthorisedVolume) -} - -function _financialYear (financialYearEnding) { - const startYear = financialYearEnding - 1 - const endYear = financialYearEnding - - return `${startYear} to ${endYear}` -} - -function _prepareChargeElementDates (chargeElement, chargeVersion) { - const chargePeriod = { - startDate: chargeVersion.chargePeriodStartDate, - endDate: chargeVersion.chargePeriodEndDate - } - - const { - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - } = chargeElement - - const abstractionPeriods = DetermineAbstractionPeriodService.go( - chargePeriod, - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - ) - - const dates = [] - - // NOTE: There can be more than 1 abstraction period for an element, hence why we loop through them - abstractionPeriods.forEach((abstractionPeriod) => { - dates.push(_prepareDate(abstractionPeriod.startDate, abstractionPeriod.endDate)) - }) - - return dates -} - -function _prepareDate (startDate, endDate) { - const preparedStartDate = formatLongDate(startDate) - const preparedEndDate = formatLongDate(endDate) - - return `${preparedStartDate} to ${preparedEndDate}` -} - -module.exports = { - go -} From d32171c411c21c9754efbc01cda25a0edd0a1338 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:45:55 +0000 Subject: [PATCH 064/147] Move, rename & refactor chg element service --- app/services/bill-runs/review/edit.service.js | 33 +++++++++++++++++++ .../amend-billable-returns.service.js | 30 ----------------- 2 files changed, 33 insertions(+), 30 deletions(-) create mode 100644 app/services/bill-runs/review/edit.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/amend-billable-returns.service.js diff --git a/app/services/bill-runs/review/edit.service.js b/app/services/bill-runs/review/edit.service.js new file mode 100644 index 0000000000..6ee8b3b0da --- /dev/null +++ b/app/services/bill-runs/review/edit.service.js @@ -0,0 +1,33 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data needed for the amend billable returns page + * @module EditService + */ + +const EditPresenter = require('../../../presenters/bill-runs/review/edit.presenter.js') +const FetchReviewChargeElementService = require('./fetch-review-charge-element.service.js') + +/** + * Orchestrates fetching and presenting the data needed for the amend billable returns page + * + * @param {string} reviewChargeElementId - The UUID of the charge element being reviewed + * @param {number} elementIndex - the index of the element within all charge elements for the charge reference. This + * helps users relate which element they are editing to the one they selected on the review licence screen + * + * @returns {Promise} the 'pageData' needed to view the edit billable return volumes page + */ +async function go (reviewChargeElementId, elementIndex) { + const reviewChargeElement = await FetchReviewChargeElementService.go(reviewChargeElementId) + + const pageData = EditPresenter.go(reviewChargeElement, elementIndex) + + return { + pageTitle: 'Set the billable returns quantity for this bill run', + ...pageData + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/amend-billable-returns.service.js b/app/services/bill-runs/two-part-tariff/amend-billable-returns.service.js deleted file mode 100644 index ad8dd6f6ee..0000000000 --- a/app/services/bill-runs/two-part-tariff/amend-billable-returns.service.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict' - -/** - * Orchestrates fetching and presenting the data needed for the amend billable returns page - * @module AmendBillableReturnsService - */ - -const AmendBillableReturnsPresenter = require('../../../presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js') -const FetchMatchDetailsService = require('./fetch-match-details.service.js') - -/** - * Orchestrates fetching and presenting the data needed for the amend billable returns page - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeElementId - The UUID of the review charge element being viewed - * - * @returns {Promise} the 'pageData' needed to view the edit billable return volumes page - */ -async function go (billRunId, licenceId, reviewChargeElementId) { - const { billRun, reviewChargeElement } = await FetchMatchDetailsService.go(billRunId, reviewChargeElementId) - - const pageData = AmendBillableReturnsPresenter.go(billRun, reviewChargeElement, licenceId) - - return pageData -} - -module.exports = { - go -} From 303b842e701d37dcbaa9b0322f2add368b9bbe5e Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:46:49 +0000 Subject: [PATCH 065/147] Move, rename & refactor chg element edit view --- .../bill-runs/amend-billable-returns.njk | 108 ----------------- app/views/bill-runs/review/edit.njk | 112 ++++++++++++++++++ 2 files changed, 112 insertions(+), 108 deletions(-) delete mode 100644 app/views/bill-runs/amend-billable-returns.njk create mode 100644 app/views/bill-runs/review/edit.njk diff --git a/app/views/bill-runs/amend-billable-returns.njk b/app/views/bill-runs/amend-billable-returns.njk deleted file mode 100644 index 4aaf23b8bf..0000000000 --- a/app/views/bill-runs/amend-billable-returns.njk +++ /dev/null @@ -1,108 +0,0 @@ -{% extends 'layout.njk' %} -{% from "govuk/components/back-link/macro.njk" import govukBackLink %} -{% from "govuk/components/button/macro.njk" import govukButton %} -{% from "govuk/components/inset-text/macro.njk" import govukInsetText %} -{% from "govuk/components/radios/macro.njk" import govukRadios %} -{% from "govuk/components/input/macro.njk" import govukInput %} -{% from 'govuk/components/error-summary/macro.njk' import govukErrorSummary %} - - -{% block breadcrumbs %} - {# Back link #} - {{ govukBackLink({ - text: 'Go back to licence', - href: '/system/bill-runs/' + billRun.id + '/review/' + licenceId + '/match-details/' + chargeElement.reviewChargeElementId - }) }} -{% endblock %} - -{% set quantityInputHTML %} - {% if error.customQuantityInputFormElement %} - {% set errorClass = 'govuk-input--error' %} - {% endif %} - - {{ govukInput({ - id: "custom-quantity-input", - name: "customQuantity", - errorMessage: error.customQuantityInputFormElement, - classes: "govuk-!-width-one-third " + errorClass, - value: customQuantityValue, - label: { - text: "Billable returns quantity" - }, - hint: { - text: "Enter a number with no more than 6 decimal places. For example, 20.123456" - }, - suffix: { - text: "ML" - } - }) }} - -{% endset %} - -{% block content %} - {% if error %} - {{ govukErrorSummary({ - titleText: 'There is a problem', - errorList: [ - { - text: error.message, - href: '#billable-volumes-error' - } - ] - }) }} - {% endif %} - - {% set insertText %} -
- Financial year {{billRun.financialYear}} -
-
- Charge period {{chargeVersion.chargePeriod}} -
- {%endset%} - - {% set secondHeader %} - {{ govukInsetText({ - html: insertText - }) }} - {% endset %} - -
-
- - - {{ govukRadios({ - name: 'quantity-options', - errorMessage: error.radioFormElement, - fieldset: { - legend: { - html: '' + chargeElement.description + ' ' + chargeElement.dates + '' + '
' + 'Set the billable returns quantity for this bill run' + '
' + secondHeader, - isPageHeading: true, - classes: 'govuk-fieldset__legend--l' - } - }, - items: [ - { - id: 'authorised-quantity', - value: authorisedQuantity, - html: '
Authorised ' + authorisedQuantity + 'ML
' - }, - { - id: 'custom-quantity', - value: 'customQuantity', - text: 'Custom quantity', - checked: customQuantitySelected, - conditional: { - html: quantityInputHTML - } - } - ] - }) }} - - {# Hidden input for authorised volume #} - - - {{ govukButton({ text: 'Confirm', preventDoubleClick: true }) }} -
-
-{% endblock %} diff --git a/app/views/bill-runs/review/edit.njk b/app/views/bill-runs/review/edit.njk new file mode 100644 index 0000000000..5df36d940c --- /dev/null +++ b/app/views/bill-runs/review/edit.njk @@ -0,0 +1,112 @@ +{% extends 'layout.njk' %} +{% from "govuk/components/back-link/macro.njk" import govukBackLink %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/inset-text/macro.njk" import govukInsetText %} +{% from "govuk/components/radios/macro.njk" import govukRadios %} +{% from "govuk/components/input/macro.njk" import govukInput %} +{% from 'govuk/components/error-summary/macro.njk' import govukErrorSummary %} + +{% block breadcrumbs %} + {# Back link #} + {{ govukBackLink({ + text: 'Go back to review charge element', + href: '/system/bill-runs/review/charge-element/' + reviewChargeElementId + '/' + elementIndex + }) }} +{% endblock %} + +{% block content %} + {# Main heading #} +
+
+ {% if error %} + {{ govukErrorSummary({ + titleText: 'There is a problem', + errorList: error.errorList + }) }} + {% endif %} + {{ chargeDescription }} +

{{pageTitle}}

+ + {% for chargePeriod in chargePeriods %} + {% set chargePeriodIndex = loop.index0 %} +

{{ chargePeriod }}

+ {% endfor %} +
+
+ + {# Periods #} +
+
+ Financial year {{financialPeriod}} +

Charge period {{chargePeriod}}

+ + {# Billable returns inset #} + {% set insertText %} +

+ Billable returns + {{billableReturns}} ML +

+ {% endset %} + {{ govukInsetText({ + html: insertText + }) + }} +
+
+ +
+
+ + + {% set quantityInputHTML %} + {% if error.customQuantityErrorMessage %} + {% set errorClass = 'govuk-input--error' %} + {% endif %} + + {{ govukInput({ + id: "custom-quantity", + name: "customQuantity", + classes: "govuk-!-width-one-third " + errorClass, + value: customQuantityValue, + label: { + text: "Billable returns quantity" + }, + hint: { + text: "Enter a number with no more than 6 decimal places. For example, 20.123456" + }, + suffix: { + text: "ML" + }, + errorMessage: error.customQuantityErrorMessage + }) }} + {% endset %} + + {{ govukRadios({ + id: 'quantity-options', + name: 'quantityOptions', + items: [ + { + id: 'authorised-quantity', + value: authorisedQuantity, + html: '
Authorised ' + authorisedQuantity + 'ML
' + }, + { + id: 'custom-quantity-selector', + value: 'customQuantity', + text: 'Custom quantity', + checked: customQuantitySelected, + conditional: { + html: quantityInputHTML + } + } + ], + errorMessage: error.quantityOptionsErrorMessage + }) }} + + {# Hidden input for authorised volume #} + + + {{ govukButton({ text: 'Confirm', preventDoubleClick: true }) }} +
+
+{% endblock %} From fdd44a47798e64fe656bf378e36c5b1ef34c57ec Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:48:44 +0000 Subject: [PATCH 066/147] Move, rename & refactor chg element edit validator --- .../bill-runs/review/edit.validator.js | 94 ++++++++++++++++++ .../billable-returns.validator.js | 99 ------------------- 2 files changed, 94 insertions(+), 99 deletions(-) create mode 100644 app/validators/bill-runs/review/edit.validator.js delete mode 100644 app/validators/bill-runs/two-part-tariff/billable-returns.validator.js diff --git a/app/validators/bill-runs/review/edit.validator.js b/app/validators/bill-runs/review/edit.validator.js new file mode 100644 index 0000000000..4ba3717e21 --- /dev/null +++ b/app/validators/bill-runs/review/edit.validator.js @@ -0,0 +1,94 @@ +'use strict' + +/** + * Validates data submitted for the review charge element edit page + * @module EditValidator + */ + +const Joi = require('joi') + +/** + * Validates data submitted for the review charge element edit page + * + * When editing the charge element's billable volume the user must either choose the existing authorised volume or enter + * there own custom volume. The validation happening here is to ensure that a user selects either option and if its the + * custom one, that they enter a number above 0 but below the authorised volume and that the number is less than 6 + * decimal places. + * @param {object} payload - The payload from the request to be validated + * + * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If + * any errors are found the `error:` property will also exist detailing what the issues were + */ +function go (payload) { + const { quantityOptions } = payload + + if (quantityOptions === 'customQuantity') { + return _validateCustomQuantity(payload.customQuantity, Number(payload.authorisedVolume)) + } + + return _validateAuthorisedQuantity(quantityOptions) +} + +/** + * Custom JOI validator to check a value does not have more than 6 decimal places + * + * We are limited to 6 decimals by the Rules Service that will eventually be called to calculate the charge. Due to + * limitations in Joi validation for decimals, achieving validation for numbers with more than 6 decimal places + * requires a custom approach. + * + * See {@link https://github.com/hapijs/joi/blob/master/API.md#anycustommethod-description | Joi custom validation}. + * + * @param {number} value - the value to be validated + * @param {object} helpers - a Joi object containing a numbers of helpers + * + * @returns {number|object} if valid the original value else a Joi 'any.invalid' error. Knowing we return this means + * you can assign what error message to use when a number has too many decimals. + */ +function _maxDecimals (value, helpers) { + // Guard clause to ensure we don't try and interact with a null or undefined value + if (!value) { + return value + } + + const parts = value.toString().split('.') + + if (parts.length === 1 || parts[1].length <= 6) { + return value + } + + return helpers.error('any.invalid') +} + +function _validateCustomQuantity (customQuantity, authorisedVolume) { + const schema = Joi + .number() + .min(0) + .max(authorisedVolume) + .custom(_maxDecimals, 'Max decimals') + .required() + .messages({ + 'number.unsafe': 'The quantity must be a number', + 'number.base': 'The quantity must be a number', + 'number.min': 'The quantity must be zero or higher', + 'number.max': 'The quantity must be the same as or less than the authorised amount', + 'any.required': 'Enter the billable quantity', + 'any.invalid': 'The quantity must contain no more than 6 decimal places' + }) + + return schema.validate(customQuantity, { abortEarly: true }) +} + +function _validateAuthorisedQuantity (quantityOptions) { + const schema = Joi + .number() + .required() + .messages({ + 'any.required': 'Select the billable quantity' + }) + + return schema.validate(quantityOptions, { abortEarly: true }) +} + +module.exports = { + go +} diff --git a/app/validators/bill-runs/two-part-tariff/billable-returns.validator.js b/app/validators/bill-runs/two-part-tariff/billable-returns.validator.js deleted file mode 100644 index 09f2531c7c..0000000000 --- a/app/validators/bill-runs/two-part-tariff/billable-returns.validator.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict' - -/** - * Validates data submitted for the `/bill-runs/{billRunId}/review/{licenceId}/match-details/{reviewChargeElementId} - * /amend-billable-returns` page - * @module BillableReturnsValidator - */ - -const Joi = require('joi') - -/** - * Validates data submitted for the `/bill-runs/{billRunId}/review/{licenceId}/match-details/{reviewChargeElementId} - * /amend-billable-returns` page - * - * When editing the charge elements billable volume the user must either choose the existing authorised volume or enter - * there own custom volume. The validation happening here is to ensure that a user selects either option and if its the - * custom one, that they enter a number above 0 but below the authorised volume and that the number is less than 6 - * decimal places. - * @param {object} payload - The payload from the request to be validated - * - * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If - * any errors are found the `error:` property will also exist detailing what the issues were - */ -function go (payload) { - const { 'quantity-options': selectedOption } = payload - - if (selectedOption === 'customQuantity') { - return _validateCustomQuantity(payload.customQuantity, Number(payload.authorisedVolume)) - } - - return _validateAuthorisedQuantity(selectedOption) -} - -/** - * Due to limitations in Joi validation for decimals, achieving validation for numbers with fewer than 6 decimal places - * requires a custom approach. First, convert the number into a string. Then split the string into an array using the - * decimal point (`.`) as the delimiter. This results in either one item in the array (if no decimal is present) or two - * items (if a decimal is present). The first item represents the part before the decimal, while the second item - * represents the part after. By assessing if the length of the second string is less than 7, we can validate if there - * the correct number of decimals. - * - * @private - */ -function customValidation (customQuantity, helpers) { - const maxNumberOfDecimals = 7 - const customQuantityParts = customQuantity.toString().split('.') - - if (customQuantityParts.length === 1 || customQuantityParts[1].length < maxNumberOfDecimals) { - return customQuantity - } - - return helpers.message({ custom: 'The quantity must contain no more than 6 decimal places' }) -} - -function _validateCustomQuantity (customQuantity, authorisedVolume) { - const schema = Joi.object({ - customQuantity: Joi - .number() - .min(0) - .max(authorisedVolume) - .required() - .messages({ - 'number.unsafe': 'The quantity must be a number', - 'number.base': 'The quantity must be a number', - 'number.min': 'The quantity must be zero or higher', - 'number.max': 'The quantity must be the same as or less than the authorised amount', - 'any.required': 'Enter the billable quantity' - }) - }) - - const validation = schema.validate({ customQuantity }, { abortEarly: true }) - - // The first check we are doing is validating that a number has been inputted. If it has then we can move onto our - // next check for if there are less than 7 decimal places. - if (!validation.error) { - const decimalSchema = Joi.number().custom(customValidation, 'custom validation') - - return decimalSchema.validate(customQuantity) - } - - return validation -} - -function _validateAuthorisedQuantity (selectedOption) { - const schema = Joi.object({ - selectedOption: Joi - .number() - .required() - .messages({ - 'any.required': 'Select the billable quantity' - }) - }) - - return schema.validate({ selectedOption }, { abortEarly: true }) -} - -module.exports = { - go -} From 349b12f5772928f7362f1755a18d8994eff2d410 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:49:52 +0000 Subject: [PATCH 067/147] Move, rename & refactor chg element edit service --- .../bill-runs/review/submit-edit.service.js | 79 +++++++++++++++++++ ...submit-amended-billable-returns.service.js | 76 ------------------ 2 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 app/services/bill-runs/review/submit-edit.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js diff --git a/app/services/bill-runs/review/submit-edit.service.js b/app/services/bill-runs/review/submit-edit.service.js new file mode 100644 index 0000000000..2f90c19f4f --- /dev/null +++ b/app/services/bill-runs/review/submit-edit.service.js @@ -0,0 +1,79 @@ +'use strict' + +/** + * Orchestrates validating and patching the data for the amend billable returns page + * @module SubmitEditService + */ + +const EditPresenter = require('../../../presenters/bill-runs/review/edit.presenter.js') +const EditValidator = require('../../../validators/bill-runs/review/edit.validator.js') +const FetchReviewChargeElementService = require('./fetch-review-charge-element.service.js') +const ReviewChargeElementModel = require('../../../models/review-charge-element.model.js') + +/** + * Orchestrates validating the data for the amend billable returns page and patching the db value + * + * @param {string} reviewChargeElementId - The UUID of the charge element being updated + * @param {number} elementIndex - the index of the element within all charge elements for the charge reference. This + * helps users relate which element they are editing to the one they selected on the review licence screen + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * @param {object} payload - The submitted form data + * + * @returns {Promise} The updated value for the billable returns + */ +async function go (reviewChargeElementId, elementIndex, yar, payload) { + const validationResult = _validate(payload) + + if (!validationResult) { + await _save(reviewChargeElementId, payload) + yar.flash('banner', 'The billable returns for this licence have been updated') + + return {} + } + + const reviewChargeElement = await FetchReviewChargeElementService.go(reviewChargeElementId) + const pageData = EditPresenter.go(reviewChargeElement, elementIndex) + + return { + activeNavBar: 'search', + pageTitle: 'Set the billable returns quantity for this bill run', + error: validationResult, + customQuantitySelected: payload.quantityOptions === 'customQuantity', + customQuantityValue: payload.customQuantity, + ...pageData + } +} + +function _save (reviewChargeElementId, payload) { + const volume = payload.quantityOptions === 'customQuantity' ? payload.customQuantity : payload.quantityOptions + + return ReviewChargeElementModel.query() + .findById(reviewChargeElementId) + .patch({ amendedAllocated: volume }) +} + +function _validate (payload) { + const validation = EditValidator.go(payload) + + if (!validation.error) { + return null + } + + const { message } = validation.error.details[0] + + if (payload.quantityOptions === 'customQuantity') { + return { + errorList: [{ href: '#custom-quantity', text: message }], + customQuantityErrorMessage: { text: message } + } + } + + return { + errorList: [{ href: '#quantityOptions-error', text: message }], + quantityOptionsErrorMessage: { text: message } + } +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js b/app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js deleted file mode 100644 index ef0651abe3..0000000000 --- a/app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict' - -/** - * Orchestrates validating and patching the data for the amend billable returns page - * @module SubmitAmendedBillableReturnsService -*/ - -const AmendBillableReturnsPresenter = require('../../../presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js') -const BillableReturnsValidator = require('../../../validators/bill-runs/two-part-tariff/billable-returns.validator.js') -const FetchMatchDetailsService = require('./fetch-match-details.service.js') -const ReviewChargeElementModel = require('../../../models/review-charge-element.model.js') - -/** - * Orchestrates validating the data for the amend billable returns page and patching the db value - * - * @param {string} billRunId - The UUID for the bill run - * @param {string} licenceId - The UUID of the licence that is being reviewed - * @param {string} reviewChargeElementId - The UUID of the review charge element being updated - * @param {object} payload - The submitted form data - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - * - * @returns {Promise} The updated value for the billable returns - */ -async function go (billRunId, licenceId, reviewChargeElementId, payload, yar) { - const validationResult = _validate(payload) - - if (!validationResult) { - await _persistAmendedBillableReturns(reviewChargeElementId, payload) - yar.flash('banner', 'The billable returns for this licence have been updated') - - return { error: null } - } - - const { billRun, reviewChargeElement } = await FetchMatchDetailsService.go(billRunId, reviewChargeElementId) - const pageData = AmendBillableReturnsPresenter.go(billRun, reviewChargeElement, licenceId) - - return { - activeNavBar: 'search', - pageTitle: 'Set the billable returns quantity for this bill run', - error: validationResult, - customQuantitySelected: payload['quantity-options'] === 'customQuantity', - customQuantityValue: payload.customQuantity, - ...pageData - } -} - -function _persistAmendedBillableReturns (reviewChargeElementId, payload) { - const volume = payload['quantity-options'] === 'customQuantity' ? payload.customQuantity : payload['quantity-options'] - - return ReviewChargeElementModel.query() - .findById(reviewChargeElementId) - .patch({ amendedAllocated: volume }) -} - -function _validate (payload) { - const validation = BillableReturnsValidator.go(payload) - - if (!validation.error) { - return null - } - - const { message } = validation.error.details[0] - - const radioFormElement = payload['quantity-options'] === 'customQuantity' ? null : { text: message } - const customQuantityInputFormElement = payload['quantity-options'] === 'customQuantity' ? { text: message } : null - - return { - message, - radioFormElement, - customQuantityInputFormElement - } -} - -module.exports = { - go -} From a102bee6d6c5ca9043dfe62b6e98c6f687e76a7b Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:50:45 +0000 Subject: [PATCH 068/147] Move chg element routes & controllers to /review --- .../bill-runs-review.controller.js | 29 ++++++++++++++++ app/controllers/bill-runs.controller.js | 34 ------------------- app/routes/bill-runs-review.routes.js | 24 +++++++++++++ app/routes/bill-runs.routes.js | 24 ------------- 4 files changed, 53 insertions(+), 58 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index a60276810e..763f52989a 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -7,12 +7,14 @@ const AuthorisedService = require('../services/bill-runs/review/authorised.service.js') const FactorsService = require('../services/bill-runs/review/factors.service.js') +const EditService = require('../services/bill-runs/review/edit.service.js') const PreviewService = require('../services/bill-runs/review/preview.service.js') const ReviewChargeElementService = require('../services/bill-runs/review/review-charge-element.service.js') const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') const ReviewLicenceService = require('../services/bill-runs/review/review-licence.service.js') const SubmitAuthorisedService = require('../services/bill-runs/review/submit-authorised.service.js') +const SubmitEditService = require('..//services/bill-runs/review/submit-edit.service.js') const SubmitFactorsService = require('../services/bill-runs/review/submit-factors.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') @@ -28,6 +30,17 @@ async function authorised (request, h) { }) } +async function edit (request, h) { + const { elementIndex, reviewChargeElementId } = request.params + + const pageData = await EditService.go(reviewChargeElementId, elementIndex) + + return h.view('bill-runs/review/edit.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function factors (request, h) { const { reviewChargeReferenceId } = request.params @@ -103,6 +116,20 @@ async function submitAuthorised (request, h) { return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) } +async function submitEdit (request, h) { + const { elementIndex, reviewChargeElementId } = request.params + + const pageData = await SubmitEditService.go( + reviewChargeElementId, elementIndex, request.yar, request.payload + ) + + if (pageData.error) { + return h.view('bill-runs/review/edit.njk', pageData) + } + + return h.redirect(`/system/bill-runs/review/charge-element/${reviewChargeElementId}/${elementIndex}`) +} + async function submitFactors (request, h) { const { reviewChargeReferenceId } = request.params const pageData = await SubmitFactorsService.go(reviewChargeReferenceId, request.yar, request.payload) @@ -132,6 +159,7 @@ async function submitReviewLicence (request, h) { module.exports = { authorised, + edit, factors, preview, review, @@ -139,6 +167,7 @@ module.exports = { reviewChargeReference, reviewLicence, submitAuthorised, + submitEdit, submitFactors, submitReview, submitReviewLicence diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 80c080e7d1..00a35f0fe0 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -7,30 +7,16 @@ const Boom = require('@hapi/boom') -const AmendBillableReturnsService = require('../services/bill-runs/two-part-tariff/amend-billable-returns.service.js') const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js') const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/generate-bill-run.service.js') const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') -const SubmitAmendedBillableReturnsService = require('..//services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../services/bill-runs/submit-cancel-bill-run.service.js') const SubmitRemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') const SubmitSendBillRunService = require('../services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../services/bill-runs/view-bill-run.service.js') -async function amendBillableReturns (request, h) { - const { id: billRunId, licenceId, reviewChargeElementId } = request.params - - const pageData = await AmendBillableReturnsService.go(billRunId, licenceId, reviewChargeElementId) - - return h.view('bill-runs/amend-billable-returns.njk', { - pageTitle: 'Set the billable returns quantity for this bill run', - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function cancel (request, h) { const { id } = request.params @@ -77,24 +63,6 @@ async function send (request, h) { }) } -async function submitAmendedBillableReturns (request, h) { - const { id: billRunId, licenceId, reviewChargeElementId } = request.params - - const pageData = await SubmitAmendedBillableReturnsService.go( - billRunId, - licenceId, - reviewChargeElementId, - request.payload, - request.yar - ) - - if (pageData.error) { - return h.view('bill-runs/amend-billable-returns.njk', pageData) - } - - return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}/match-details/${reviewChargeElementId}`) -} - async function submitCancel (request, h) { const { id } = request.params @@ -163,12 +131,10 @@ async function view (request, h) { } module.exports = { - amendBillableReturns, cancel, index, removeLicence, send, - submitAmendedBillableReturns, submitCancel, submitRemoveLicence, submitSend, diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 2f168d5f56..f4f81066b7 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -39,6 +39,30 @@ const routes = [ } } }, + { + method: 'GET', + path: '/bill-runs/review/charge-element/{reviewChargeElementId}/{elementIndex}/edit', + options: { + handler: BillRunsReviewController.edit, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/bill-runs/review/charge-element/{reviewChargeElementId}/{elementIndex}/edit', + options: { + handler: BillRunsReviewController.submitEdit, + auth: { + access: { + scope: ['billing'] + } + } + } + }, { method: 'GET', path: '/bill-runs/review/charge-reference/{reviewChargeReferenceId}', diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index 1ef5a9440c..d0d3d424ce 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -78,30 +78,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}/amend-billable-returns', - options: { - handler: BillRunsController.amendBillableReturns, - auth: { - access: { - scope: ['billing'] - } - } - } - }, - { - method: 'POST', - path: '/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}/amend-billable-returns', - options: { - handler: BillRunsController.submitAmendedBillableReturns, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/send', From eb207382e8c0848b04c54bbb0085fbc8e374020d Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:51:17 +0000 Subject: [PATCH 069/147] =?UTF-8?q?Housekeeping=20-=20fix=20error=20in=20p?= =?UTF-8?q?review=20for=20=C2=A30=20charge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/bill-runs/review/preview.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/bill-runs/review/preview.service.js b/app/services/bill-runs/review/preview.service.js index f63ab0f02e..315c7c6200 100644 --- a/app/services/bill-runs/review/preview.service.js +++ b/app/services/bill-runs/review/preview.service.js @@ -30,7 +30,7 @@ async function go (reviewChargeReferenceId, yar) { const result = await _calculateCharge(transaction) - if (result.charge) { + if (result.charge || result.charge === 0) { yar.flash('charge', `Based on this information the example charge is ${formatMoney(result.charge)}`) } From 02429f8e62dc8b0f52a76a9b667894b2d5d5cc33 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:51:53 +0000 Subject: [PATCH 070/147] Housekeeping - Tidy view element --- app/views/bill-runs/review/factors.njk | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/bill-runs/review/factors.njk b/app/views/bill-runs/review/factors.njk index 829b4d4c37..c2b8a2612f 100644 --- a/app/views/bill-runs/review/factors.njk +++ b/app/views/bill-runs/review/factors.njk @@ -29,9 +29,7 @@ {{pageTitle}} Financial Year {{financialPeriod}} -

- Charge period {{chargePeriod}} -

+

Charge period {{chargePeriod}}

{# Inset section #} {% if otherAdjustments.length > 0 %} From a5f49703c465735ff5fe97648627838fb8fcdae7 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:52:23 +0000 Subject: [PATCH 071/147] Housekeeping - tidy view --- app/views/bill-runs/review/authorised.njk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/bill-runs/review/authorised.njk b/app/views/bill-runs/review/authorised.njk index e5e2716983..6d444c531b 100644 --- a/app/views/bill-runs/review/authorised.njk +++ b/app/views/bill-runs/review/authorised.njk @@ -33,18 +33,20 @@ {{chargeDescription}} {{pageTitle}} + + {# Periods #} Financial Year {{financialPeriod}}

Charge period {{chargePeriod}}

+ {# Billable returns inset #} {% set insertText %}

Total billable returns {{totalBillableReturns}} ML

{% endset %} - {{ govukInsetText({ html: insertText }) From c55ac74e28294fb6c8d6adfbd511fb5002592077 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 11:52:38 +0000 Subject: [PATCH 072/147] Enable element index to with edit billable returns --- .../review/review-charge-element.presenter.js | 3 ++- app/views/bill-runs/review/review-charge-element.njk | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index fc7796aa7c..21d64e0ac2 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -36,7 +36,8 @@ function go (reviewChargeElement, elementIndex) { chargeDescription: chargeElement.description, chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, chargePeriods: _chargePeriods(chargeElement, chargePeriod), - caption: `Element ${elementIndex} of ${reviewChargeReference.reviewChargeElements.length}`, + elementCount: reviewChargeReference.reviewChargeElements.length, + elementIndex, financialPeriod: formatFinancialYear( reviewChargeReference.reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding ), diff --git a/app/views/bill-runs/review/review-charge-element.njk b/app/views/bill-runs/review/review-charge-element.njk index bef7d3e0a9..83fb3a247b 100644 --- a/app/views/bill-runs/review/review-charge-element.njk +++ b/app/views/bill-runs/review/review-charge-element.njk @@ -27,7 +27,7 @@ {# Main heading #}
- {{caption}} + Element {{elementIndex}} of {{elementCount}}

{{ chargeDescription }}

{% for chargePeriod in chargePeriods %} @@ -73,7 +73,7 @@
{# Periods #} - Financial year {{financialPeriod}} + Financial year {{financialPeriod}}

Charge period {{chargePeriod}}

{# Billable returns, authorised volume and issues #} @@ -121,9 +121,9 @@
{{ govukButton({ - text: "Edit the billable returns", - href: "/system/bill-runs/review/charge-element/" + reviewChargeElementId + "/edit", - classes: "govuk-button--secondary", + text: 'Edit the billable returns', + href: '/system/bill-runs/review/charge-element/' + reviewChargeElementId + '/' + elementIndex + '/edit', + classes: 'govuk-button--secondary', preventDoubleClick: true }) }}
From ceaa8e82b6a419031f5c6f2b142ca903eb278e23 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 12:42:26 +0000 Subject: [PATCH 073/147] Move & refactor submit review licence service --- app/controllers/bill-runs-review.controller.js | 8 ++++---- .../submit-review-licence.service.js | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) rename app/services/bill-runs/{two-part-tariff => review}/submit-review-licence.service.js (83%) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 763f52989a..7ea7eaa6ec 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -17,7 +17,7 @@ const SubmitAuthorisedService = require('../services/bill-runs/review/submit-aut const SubmitEditService = require('..//services/bill-runs/review/submit-edit.service.js') const SubmitFactorsService = require('../services/bill-runs/review/submit-factors.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') -const SubmitReviewLicenceService = require('../services/bill-runs/two-part-tariff/submit-review-licence.service.js') +const SubmitReviewLicenceService = require('../services/bill-runs/review/submit-review-licence.service.js') async function authorised (request, h) { const { reviewChargeReferenceId } = request.params @@ -150,11 +150,11 @@ async function submitReview (request, h) { } async function submitReviewLicence (request, h) { - const { id: billRunId, licenceId } = request.params + const { reviewLicenceId } = request.params - await SubmitReviewLicenceService.go(billRunId, licenceId, request.payload, request.yar) + await SubmitReviewLicenceService.go(reviewLicenceId, request.yar, request.payload) - return h.redirect(`/system/bill-runs/${billRunId}/review/${licenceId}`) + return h.redirect(`/system/bill-runs/review/licence/${reviewLicenceId}`) } module.exports = { diff --git a/app/services/bill-runs/two-part-tariff/submit-review-licence.service.js b/app/services/bill-runs/review/submit-review-licence.service.js similarity index 83% rename from app/services/bill-runs/two-part-tariff/submit-review-licence.service.js rename to app/services/bill-runs/review/submit-review-licence.service.js index e0cef342a0..24eb4627d2 100644 --- a/app/services/bill-runs/two-part-tariff/submit-review-licence.service.js +++ b/app/services/bill-runs/review/submit-review-licence.service.js @@ -18,20 +18,19 @@ const ReviewLicenceModel = require('../../../models/review-licence.model.js') * redirected to the `GET` it knows to display a notification banner to confirm that the progress or status has changed * to the user. * - * @param {module:BillRunModel} billRunId - The UUID for the bill run - * @param {module:LicenceModel} licenceId - The UUID of the licence that is being reviewed - * @param {object} payload - The Hapi `request.payload` object passed on by the controller + * @param {string} reviewLicenceId - The UUID of the licence that is being reviewed * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * @param {object} payload - The Hapi `request.payload` object passed on by the controller * * @returns {Promise} resolves to the result of the update query. Not intended to be used */ -async function go (billRunId, licenceId, payload, yar) { +async function go (reviewLicenceId, yar, payload) { const parsedPayload = _parsePayload(payload) // NOTE: The YarPlugin decorates the Hapi request object with a yar property. Yar is a session manager _bannerMessage(yar, parsedPayload) - return _update(billRunId, licenceId, parsedPayload) + return _update(reviewLicenceId, parsedPayload) } function _bannerMessage (yar, parsedPayload) { @@ -62,7 +61,7 @@ function _parsePayload (payload) { } } -async function _update (billRunId, licenceId, parsedPayload) { +async function _update (reviewLicenceId, parsedPayload) { const { progress, status } = parsedPayload const patch = {} @@ -73,9 +72,8 @@ async function _update (billRunId, licenceId, parsedPayload) { } return ReviewLicenceModel.query() + .findById(reviewLicenceId) .patch(patch) - .where('billRunId', billRunId) - .andWhere('licenceId', licenceId) } module.exports = { From 786e98dc046eb6147d9efc30aca49efddfe1cdd1 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:06:11 +0000 Subject: [PATCH 074/147] Move, rename & refactor remove licence presenter --- .../bill-runs/review/remove.presenter.js | 35 +++++++++++++++++++ .../remove-bill-run-licence.presenter.js | 35 ------------------- 2 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 app/presenters/bill-runs/review/remove.presenter.js delete mode 100644 app/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.js diff --git a/app/presenters/bill-runs/review/remove.presenter.js b/app/presenters/bill-runs/review/remove.presenter.js new file mode 100644 index 0000000000..d26197af1e --- /dev/null +++ b/app/presenters/bill-runs/review/remove.presenter.js @@ -0,0 +1,35 @@ +'use strict' + +/** + * Formats the review licence data ready for presenting in the remove review licence confirmation page + * @module RemovePresenter + */ + +const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js') + +/** + * Formats the review licence data ready for presenting in the remove review licence confirmation page + * + * @param {module:ReviewLicenceModel} reviewLicence - instance of the `ReviewLicenceModel` returned from + * `FetchRemoveReviewLicenceService` + * + * @returns {object}page date needed for the remove review licence confirmation page + */ +function go (reviewLicence) { + const { billRun, id: reviewLicenceId, licenceRef } = reviewLicence + const { billRunNumber, createdAt, region, status, toFinancialYearEnding } = billRun + + return { + billRunNumber, + billRunStatus: status, + dateCreated: formatLongDate(createdAt), + financialYearPeriod: formatFinancialYear(toFinancialYearEnding), + pageTitle: `You're about to remove ${licenceRef} from the bill run`, + region: region.displayName, + reviewLicenceId + } +} + +module.exports = { + go +} diff --git a/app/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.js b/app/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.js deleted file mode 100644 index 2586b0de55..0000000000 --- a/app/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict' - -/** - * Formats the data ready for presenting in the remove bill run licence confirmation page - * @module RemoveBillRunLicencePresenter - */ - -const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js') - -/** - * Formats the data ready for presenting in the remove bill run licence confirmation page - * - * @param {module:BillRunModel} billRun - an instance of `BillRunModel` - * @param {string} licenceId - UUID of the licence to remove from the bill run - * @param {string} licenceRef - the licence reference of the licence to remove from the bill run - * - * @returns {object} - the prepared data to be passed to the remove licence template - */ -function go (billRun, licenceId, licenceRef) { - const { billRunNumber, createdAt, region, status, toFinancialYearEnding } = billRun - - return { - pageTitle: `You're about to remove ${licenceRef} from the bill run`, - backLink: `../review/${licenceId}`, - billRunNumber, - billRunStatus: status, - dateCreated: formatLongDate(createdAt), - financialYear: formatFinancialYear(toFinancialYearEnding), - region - } -} - -module.exports = { - go -} From 2038cc3fdfc626c40d7b20ff5955dcc62d750920 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:07:18 +0000 Subject: [PATCH 075/147] Move, rename & refactor remove licence service --- .../bill-runs/review/remove.service.js | 27 ++++++++++ .../remove-bill-run-licence.service.js | 53 ------------------- 2 files changed, 27 insertions(+), 53 deletions(-) create mode 100644 app/services/bill-runs/review/remove.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js diff --git a/app/services/bill-runs/review/remove.service.js b/app/services/bill-runs/review/remove.service.js new file mode 100644 index 0000000000..aa6c5dae88 --- /dev/null +++ b/app/services/bill-runs/review/remove.service.js @@ -0,0 +1,27 @@ +'use strict' + +/** + * Orchestrates fetching and presenting the data needed for the remove review licence confirmation page + * @module RemoveService + */ + +const FetchRemoveReviewLicenceService = require('./fetch-remove-review-licence.service.js') +const RemovePresenter = require('../../../presenters/bill-runs/review/remove.presenter.js') + +/** + * Orchestrates fetching and presenting the data needed for the remove bill run licence confirmation page + * + * @param {string} reviewLicenceId - The UUID of the licence that is being removed from the bill run + * + * @returns {Promise} an object representing the `pageData` needed by the remove licence template. It contains + * details of the bill run & the licence reference. + */ +async function go (reviewLicenceId) { + const reviewLicence = await FetchRemoveReviewLicenceService.go(reviewLicenceId) + + return RemovePresenter.go(reviewLicence) +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js b/app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js deleted file mode 100644 index faecdfe314..0000000000 --- a/app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict' - -/** - * Orchestrates fetching and presenting the data needed for the remove bill run licence confirmation page - * @module RemoveBillRunLicenceService - */ - -const BillRunModel = require('../../../models/bill-run.model.js') -const LicenceModel = require('../../../models/licence.model.js') -const RemoveBillRunLicencePresenter = require('../../../presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.js') - -/** - * Orchestrates fetching and presenting the data needed for the remove bill run licence confirmation page - * - * @param {string} billRunId - The UUID of the bill run that the licence is in - * @param {string} licenceId - UUID of the licence to remove from the bill run - * - * @returns {Promise} an object representing the `pageData` needed by the remove licence template. It contains - * details of the bill run & the licence reference. - */ -async function go (billRunId, licenceId) { - const billRun = await _fetchBillRun(billRunId) - const licenceRef = await _fetchLicenceRef(licenceId) - - const pageData = RemoveBillRunLicencePresenter.go(billRun, licenceId, licenceRef) - - return pageData -} - -async function _fetchBillRun (billRunId) { - return BillRunModel.query() - .findById(billRunId) - .select( - 'billRuns.billRunNumber', - 'billRuns.createdAt', - 'billRuns.status', - 'billRuns.toFinancialYearEnding', - 'region.displayName as region' - ) - .innerJoinRelated('region') -} - -async function _fetchLicenceRef (licenceId) { - const licence = await LicenceModel.query() - .findById(licenceId) - .select('licenceRef') - - return licence.licenceRef -} - -module.exports = { - go -} From 7fe0cb0133a19b691d1da804ec5dae1ac04db29f Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:08:10 +0000 Subject: [PATCH 076/147] Add new fetch service to get data for remove page --- .../fetch-remove-review-licence.service.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 app/services/bill-runs/review/fetch-remove-review-licence.service.js diff --git a/app/services/bill-runs/review/fetch-remove-review-licence.service.js b/app/services/bill-runs/review/fetch-remove-review-licence.service.js new file mode 100644 index 0000000000..ebc56216de --- /dev/null +++ b/app/services/bill-runs/review/fetch-remove-review-licence.service.js @@ -0,0 +1,51 @@ +'use strict' + +/** + * Fetches the selected review licence instance and related data for the two-part tariff remove review licence page + * @module FetchRemoveReviewLicenceService + */ + +const ReviewLicenceModel = require('../../../models/review-licence.model.js') + +/** + * Fetches the selected review licence instance and related data for the two-part tariff remove review licence page + * + * @param {string} reviewLicenceId - the UUID of the selected review licence + * + * @returns {module:ReviewLicenceModel} the matching `ReviewLicenceModel` instance and related data needed for the + * two-part tariff remove review licence page + */ +async function go (reviewLicenceId) { + return _fetch(reviewLicenceId) +} + +async function _fetch (reviewLicenceId) { + return ReviewLicenceModel.query() + .findById(reviewLicenceId) + .select([ + 'id', + 'licenceId', + 'licenceRef' + ]) + .withGraphFetched('billRun') + .modifyGraph('billRun', (builder) => { + builder + .select([ + 'id', + 'billRunNumber', + 'createdAt', + 'status', + 'toFinancialYearEnding' + ]) + .withGraphFetched('region') + .modifyGraph('region', (builder) => { + builder.select([ + 'displayName' + ]) + }) + }) +} + +module.exports = { + go +} From 25c858831389a9e452fb5bfadfa4d862e962cddd Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:09:05 +0000 Subject: [PATCH 077/147] Move, rename & refactor remove licence view --- .../bill-runs/{remove-licence.njk => review/remove.njk} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename app/views/bill-runs/{remove-licence.njk => review/remove.njk} (94%) diff --git a/app/views/bill-runs/remove-licence.njk b/app/views/bill-runs/review/remove.njk similarity index 94% rename from app/views/bill-runs/remove-licence.njk rename to app/views/bill-runs/review/remove.njk index 7fd8dfb15b..cef03db39c 100644 --- a/app/views/bill-runs/remove-licence.njk +++ b/app/views/bill-runs/review/remove.njk @@ -10,8 +10,8 @@ {# Back link #} {{ govukBackLink({ - text: 'Go back to licence', - href: backLink + text: 'Go back to review licence', + href: '/system/bill-runs/review/licence/' + reviewLicenceId }) }} {% endblock %} @@ -68,7 +68,7 @@ }, { key: { text: "Financial year", classes: "meta-data__label" }, - value: { html: '' + financialYear + '', classes: "meta-data__value" } + value: { html: '' + financialYearPeriod + '', classes: "meta-data__value" } } ] }) From 088c46192e5234213e587b11dfa73c8770f4566f Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:09:59 +0000 Subject: [PATCH 078/147] Move, rename & refactor remove licence data service --- .../review/remove-review-licence.service.js | 82 ++++++++++++++++++ .../remove-review-data.service.js | 86 ------------------- 2 files changed, 82 insertions(+), 86 deletions(-) create mode 100644 app/services/bill-runs/review/remove-review-licence.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/remove-review-data.service.js diff --git a/app/services/bill-runs/review/remove-review-licence.service.js b/app/services/bill-runs/review/remove-review-licence.service.js new file mode 100644 index 0000000000..774682f4db --- /dev/null +++ b/app/services/bill-runs/review/remove-review-licence.service.js @@ -0,0 +1,82 @@ +'use strict' + +/** + * Deletes all data relating to a review licence from the review tables + * @module RemoveReviewLicenceService + */ + +const { db } = require('../../../../db/db.js') + +/** + * Deletes all data relating to a review licence from the review tables + * + * @param {string} reviewLicenceId - The UUID of the review licence that is being removed from the bill run + * + * @returns {Promise} the promise returned is not intended to resolve to any particular value + */ +async function go (reviewLicenceId) { + await _removeChargeElementReturns(reviewLicenceId) + await _removeReturns(reviewLicenceId) + await _removeChargeElements(reviewLicenceId) + await _removeChargeReferences(reviewLicenceId) + await _removeChargeVersions(reviewLicenceId) + + return _removeLicence(reviewLicenceId) +} + +async function _removeChargeElements (reviewLicenceId) { + return db + .del() + .from('reviewChargeElements AS rce') + .innerJoin('reviewChargeReferences AS rcr', 'rce.reviewChargeReferenceId', 'rcr.id') + .innerJoin('reviewChargeVersions AS rcv', 'rcr.reviewChargeVersionId', 'rcv.id') + .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') + .where('rl.id', reviewLicenceId) +} + +async function _removeChargeElementReturns (reviewLicenceId) { + return db + .del() + .from('reviewChargeElementsReturns AS rcer') + .innerJoin('reviewChargeElements AS rce', 'rcer.reviewChargeElementId', 'rce.id') + .innerJoin('reviewChargeReferences AS rcr', 'rce.reviewChargeReferenceId', 'rcr.id') + .innerJoin('reviewChargeVersions AS rcv', 'rcr.reviewChargeVersionId', 'rcv.id') + .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') + .where('rl.id', reviewLicenceId) +} + +async function _removeChargeReferences (reviewLicenceId) { + return db + .del() + .from('reviewChargeReferences AS rcr') + .innerJoin('reviewChargeVersions AS rcv', 'rcr.reviewChargeVersionId', 'rcv.id') + .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') + .where('rl.id', reviewLicenceId) +} + +async function _removeChargeVersions (reviewLicenceId) { + return db + .del() + .from('reviewChargeVersions AS rcv') + .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') + .where('rl.id', reviewLicenceId) +} + +async function _removeLicence (reviewLicenceId) { + return db + .del() + .from('reviewLicences') + .where('id', reviewLicenceId) +} + +async function _removeReturns (reviewLicenceId) { + return db + .del() + .from('reviewReturns AS rr') + .innerJoin('reviewLicences AS rl', 'rr.reviewLicenceId', 'rl.id') + .where('rl.id', reviewLicenceId) +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/remove-review-data.service.js b/app/services/bill-runs/two-part-tariff/remove-review-data.service.js deleted file mode 100644 index 390dabc253..0000000000 --- a/app/services/bill-runs/two-part-tariff/remove-review-data.service.js +++ /dev/null @@ -1,86 +0,0 @@ -'use strict' - -/** - * Deletes all of the persisted data relating to the bill and licence from the review tables. - * @module RemoveReviewDataService - */ - -const { db } = require('../../../../db/db.js') - -/** - * Deletes all of the persisted data relating to the bill and licence from the review tables - * - * @param {string} billRunId - The UUID of the bill run that the licence is in - * @param {string} licenceId - UUID of the licence to remove from the review tables - */ -async function go (billRunId, licenceId) { - await _removeChargeElementReturns(billRunId, licenceId) - await _removeReturns(billRunId, licenceId) - await _removeChargeElements(billRunId, licenceId) - await _removeChargeReferences(billRunId, licenceId) - await _removeChargeVersions(billRunId, licenceId) - await _removeLicence(billRunId, licenceId) -} - -async function _removeChargeElements (billRunId, licenceId) { - return db - .del() - .from('reviewChargeElements AS rce') - .innerJoin('reviewChargeReferences AS rcr', 'rce.reviewChargeReferenceId', 'rcr.id') - .innerJoin('reviewChargeVersions AS rcv', 'rcr.reviewChargeVersionId', 'rcv.id') - .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') - .where('rl.billRunId', billRunId) - .andWhere('rl.licenceId', licenceId) -} - -async function _removeChargeElementReturns (billRunId, licenceId) { - return db - .del() - .from('reviewChargeElementsReturns AS rcer') - .innerJoin('reviewChargeElements AS rce', 'rcer.reviewChargeElementId', 'rce.id') - .innerJoin('reviewChargeReferences AS rcr', 'rce.reviewChargeReferenceId', 'rcr.id') - .innerJoin('reviewChargeVersions AS rcv', 'rcr.reviewChargeVersionId', 'rcv.id') - .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') - .where('rl.billRunId', billRunId) - .andWhere('rl.licenceId', licenceId) -} - -async function _removeChargeReferences (billRunId, licenceId) { - return db - .del() - .from('reviewChargeReferences AS rcr') - .innerJoin('reviewChargeVersions AS rcv', 'rcr.reviewChargeVersionId', 'rcv.id') - .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') - .where('rl.billRunId', billRunId) - .andWhere('rl.licenceId', licenceId) -} - -async function _removeChargeVersions (billRunId, licenceId) { - return db - .del() - .from('reviewChargeVersions AS rcv') - .innerJoin('reviewLicences AS rl', 'rcv.reviewLicenceId', 'rl.id') - .where('rl.billRunId', billRunId) - .andWhere('rl.licenceId', licenceId) -} - -async function _removeLicence (billRunId, licenceId) { - return db - .del() - .from('reviewLicences') - .where('billRunId', billRunId) - .andWhere('licenceId', licenceId) -} - -async function _removeReturns (billRunId, licenceId) { - return db - .del() - .from('reviewReturns AS rr') - .innerJoin('reviewLicences AS rl', 'rr.reviewLicenceId', 'rl.id') - .where('rl.billRunId', billRunId) - .andWhere('rl.licenceId', licenceId) -} - -module.exports = { - go -} From 5fd7b6f6e086e85c23c4ce067b5a1457a85673d8 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:10:29 +0000 Subject: [PATCH 079/147] Add new process bill run post remove licence service The Submit service was doing a lot of work dealing with the bill run (whether it was empty and updating the status if so). So, we took this opportunity to refactor that logic into it's own service, reducing the number of things the submit service is responsible for. --- .../process-bill-run-post-remove.service.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 app/services/bill-runs/review/process-bill-run-post-remove.service.js diff --git a/app/services/bill-runs/review/process-bill-run-post-remove.service.js b/app/services/bill-runs/review/process-bill-run-post-remove.service.js new file mode 100644 index 0000000000..63335aaf96 --- /dev/null +++ b/app/services/bill-runs/review/process-bill-run-post-remove.service.js @@ -0,0 +1,41 @@ +'use strict' + +/** + * Determines if a two-part tariff bill run is now empty (all licences removed) and if so sets its status to empty + * @module ProcessBillRunPostRemove + */ + +const BillRunModel = require('../../../models/bill-run.model.js') +const ReviewLicenceModel = require('../../../models/review-licence.model.js') + +/** + * Determines if a two-part tariff bill run is now empty (all licences removed) and if so sets its status to empty + * + * @param {string} billRunId - UUID of the two-part tariff bill run being processed post a review licence being removed + * + * @returns {Promise} true if it was the last review licence in the bill run, so the bill run is now empty, + * else false + */ +async function go (billRunId) { + const empty = await _empty(billRunId) + + if (empty) { + await _updateStatus(billRunId) + } + + return empty +} + +async function _empty (billRunId) { + const resultSize = await ReviewLicenceModel.query().select('id').where('billRunId', billRunId).resultSize() + + return resultSize === 0 +} + +async function _updateStatus (billRunId) { + return BillRunModel.query().findById(billRunId).patch({ status: 'empty' }) +} + +module.exports = { + go +} From 5bbe563f36f468e5533287a0597f1ae110dcf22c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:12:40 +0000 Subject: [PATCH 080/147] Move, rename & refactor remove licence submit --- .../bill-runs/review/submit-remove.service.js | 64 +++++++++++++++++ .../submit-remove-bill-run-licence.service.js | 69 ------------------- 2 files changed, 64 insertions(+), 69 deletions(-) create mode 100644 app/services/bill-runs/review/submit-remove.service.js delete mode 100644 app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js diff --git a/app/services/bill-runs/review/submit-remove.service.js b/app/services/bill-runs/review/submit-remove.service.js new file mode 100644 index 0000000000..c36f53c1a4 --- /dev/null +++ b/app/services/bill-runs/review/submit-remove.service.js @@ -0,0 +1,64 @@ +'use strict' + +/** + * Orchestrates removing a review licence from a two-part tariff bill run whilst it is at the review stage + * @module SubmitRemoveService + */ + +const CreateLicenceSupplementaryYearService = require('../../licences/supplementary/create-licence-supplementary-year.service.js') +const FetchRemoveReviewLicenceModel = require('./fetch-remove-review-licence.service.js') +const ProcessBillRunPostRemove = require('./process-bill-run-post-remove.service.js') +const RemoveReviewLicenceService = require('./remove-review-licence.service.js') + +/** + * Orchestrates removing a review licence from a two-part tariff bill run whilst it is at the review stage + * + * It does this by deleting all of the persisted data relating to the licence from the review tables. The licence will + * then be flagged for 2PT supplementary billing. + * + * If after removing the review licence the bill run is empty, the bill run status will be set to `empty`. We also let + * the controller know so that the user is redirected back to the Bill runs page rather than Review bill run page. + * + * @param {string} reviewLicenceId - The UUID of the review licence that is being removed from the bill run + * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * + * @returns {Promise} an object containing the bill run ID plus a boolean flag that indicates whether this was + * the last licence in the bill run (bill run is now empty) + */ +async function go (reviewLicenceId, yar) { + const reviewLicence = await FetchRemoveReviewLicenceModel.go(reviewLicenceId) + + await RemoveReviewLicenceService.go(reviewLicenceId) + + await _flagForSupplementaryBilling(reviewLicence) + + const empty = await _empty(reviewLicence) + + if (!empty) { + // NOTE: The banner message is only set if licences remain in the bill run. This is because if there are no longer + // any licences remaining in the bill run the user is redirected to the "Bill runs" page instead of "Review + // licences". As the banner isn't displayed on the "Bill runs" page the message would remain in the cookie. + yar.flash('banner', `Licence ${reviewLicence.licenceRef} removed from the bill run.`) + } + + return { + billRunId: reviewLicence.billRun.id, + empty + } +} + +async function _empty (reviewLicence) { + const { billRun } = reviewLicence + + return ProcessBillRunPostRemove.go(billRun.id) +} + +async function _flagForSupplementaryBilling (reviewLicence) { + const { billRun, licenceId } = reviewLicence + + return CreateLicenceSupplementaryYearService.go(licenceId, [billRun.toFinancialYearEnding], true) +} + +module.exports = { + go +} diff --git a/app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js b/app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js deleted file mode 100644 index 78d2e4ba3a..0000000000 --- a/app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict' - -/** - * Orchestrates removing a licence from a bill run whilst it is at the review stage - * @module SubmitRemoveBillRunLicenceService - */ - -const BillRunModel = require('../../../models/bill-run.model.js') -const CreateLicenceSupplementaryYearService = require('../../licences/supplementary/create-licence-supplementary-year.service.js') -const LicenceModel = require('../../../models/licence.model.js') -const RemoveReviewDataService = require('./remove-review-data.service.js') -const ReviewLicenceModel = require('../../../models/review-licence.model.js') - -/** - * Orchestrates removing a licence from a bill run whilst it is at the review stage - * - * It does this by deleting all of the persisted data relating to the licence from the review tables. The licence will - * then be flagged for 2PT supplementary billing. If after removing a licence the bill run is empty, the bill run status - * will be set to `empty` and `true` returned so that the user is redirected back to the Bill runs page rather - * than Review bill run. - * - * @param {string} billRunId - The UUID of the bill run that the licence is in - * @param {string} licenceId - UUID of the licence to remove from the bill run - * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller - * - * @returns {Promise} true if all the licences have been removed from the bill run else false - */ -async function go (billRunId, licenceId, yar) { - await RemoveReviewDataService.go(billRunId, licenceId) - - await _flagForSupplementaryBilling(licenceId, billRunId) - - const allLicencesRemoved = await _allLicencesRemoved(billRunId) - - if (!allLicencesRemoved) { - const { licenceRef } = await LicenceModel.query().findById(licenceId) - - // NOTE: The banner message is only set if licences remain in the bill run. This is because if there are no longer - // any licences remaining in the bill run the user is redirected to the "Bill runs" page instead of - // "Review licences". As the banner isn't displayed on the "Bill runs" page the message would remain in the cookie. - yar.flash('banner', `Licence ${licenceRef} removed from the bill run.`) - } - - return allLicencesRemoved -} - -async function _allLicencesRemoved (billRunId) { - const count = await ReviewLicenceModel.query().where('billRunId', billRunId).resultSize() - - if (count === 0) { - await BillRunModel.query().findById(billRunId).patch({ status: 'empty' }) - - return true - } - - return false -} - -async function _flagForSupplementaryBilling (licenceId, billRunId) { - const twoPartTariff = true - const { toFinancialYearEnding } = await BillRunModel.query() - .findById(billRunId) - - return CreateLicenceSupplementaryYearService.go(licenceId, [toFinancialYearEnding], twoPartTariff) -} - -module.exports = { - go -} From 9dce0ba8b12ee7ae23bda0548f6601b7992373eb Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:13:33 +0000 Subject: [PATCH 081/147] Move remove licence routes & controllers to /review --- .../bill-runs-review.controller.js | 27 +++++++++++++++++++ app/controllers/bill-runs.controller.js | 27 ------------------- app/routes/bill-runs-review.routes.js | 24 +++++++++++++++++ app/routes/bill-runs.routes.js | 24 ----------------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 7ea7eaa6ec..1ceef83f8e 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -9,6 +9,7 @@ const AuthorisedService = require('../services/bill-runs/review/authorised.servi const FactorsService = require('../services/bill-runs/review/factors.service.js') const EditService = require('../services/bill-runs/review/edit.service.js') const PreviewService = require('../services/bill-runs/review/preview.service.js') +const RemoveService = require('../services/bill-runs/review/remove.service.js') const ReviewChargeElementService = require('../services/bill-runs/review/review-charge-element.service.js') const ReviewChargeReferenceService = require('../services/bill-runs/review/review-charge-reference.service.js') const ReviewBillRunService = require('../services/bill-runs/review/review-bill-run.service.js') @@ -16,6 +17,7 @@ const ReviewLicenceService = require('../services/bill-runs/review/review-licenc const SubmitAuthorisedService = require('../services/bill-runs/review/submit-authorised.service.js') const SubmitEditService = require('..//services/bill-runs/review/submit-edit.service.js') const SubmitFactorsService = require('../services/bill-runs/review/submit-factors.service.js') +const SubmitRemoveService = require('../services/bill-runs/review/submit-remove.service.js') const SubmitReviewBillRunService = require('../services/bill-runs/review/submit-review-bill-run.service.js') const SubmitReviewLicenceService = require('../services/bill-runs/review/submit-review-licence.service.js') @@ -60,6 +62,17 @@ async function preview (request, h) { return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) } +async function remove (request, h) { + const { reviewLicenceId } = request.params + + const pageData = await RemoveService.go(reviewLicenceId) + + return h.view('bill-runs/review/remove.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) +} + async function review (request, h) { const { id } = request.params const { page } = request.query @@ -141,6 +154,18 @@ async function submitFactors (request, h) { return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) } +async function submitRemove (request, h) { + const { reviewLicenceId } = request.params + + const result = await SubmitRemoveService.go(reviewLicenceId, request.yar) + + if (result.empty) { + return h.redirect('/system/bill-runs') + } + + return h.redirect(`/system/bill-runs/review/${result.billRunId}`) +} + async function submitReview (request, h) { const { id } = request.params @@ -162,6 +187,7 @@ module.exports = { edit, factors, preview, + remove, review, reviewChargeElement, reviewChargeReference, @@ -169,6 +195,7 @@ module.exports = { submitAuthorised, submitEdit, submitFactors, + submitRemove, submitReview, submitReviewLicence } diff --git a/app/controllers/bill-runs.controller.js b/app/controllers/bill-runs.controller.js index 00a35f0fe0..91b2fb7e56 100644 --- a/app/controllers/bill-runs.controller.js +++ b/app/controllers/bill-runs.controller.js @@ -10,10 +10,8 @@ const Boom = require('@hapi/boom') const CancelBillRunService = require('../services/bill-runs/cancel-bill-run.service.js') const GenerateBillRunService = require('../services/bill-runs/two-part-tariff/generate-bill-run.service.js') const IndexBillRunsService = require('../services/bill-runs/index-bill-runs.service.js') -const RemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') const SendBillRunService = require('../services/bill-runs/send-bill-run.service.js') const SubmitCancelBillRunService = require('../services/bill-runs/submit-cancel-bill-run.service.js') -const SubmitRemoveBillRunLicenceService = require('../services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') const SubmitSendBillRunService = require('../services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../services/bill-runs/view-bill-run.service.js') @@ -40,17 +38,6 @@ async function index (request, h) { }) } -async function removeLicence (request, h) { - const { id: billRunId, licenceId } = request.params - - const pageData = await RemoveBillRunLicenceService.go(billRunId, licenceId) - - return h.view('bill-runs/remove-licence.njk', { - activeNavBar: 'bill-runs', - ...pageData - }) -} - async function send (request, h) { const { id } = request.params @@ -77,18 +64,6 @@ async function submitCancel (request, h) { } } -async function submitRemoveLicence (request, h) { - const { id: billRunId, licenceId } = request.params - - const allLicencesRemoved = await SubmitRemoveBillRunLicenceService.go(billRunId, licenceId, request.yar) - - if (allLicencesRemoved) { - return h.redirect('/system/bill-runs') - } - - return h.redirect(`/system/bill-runs/${billRunId}/review`) -} - async function submitSend (request, h) { const { id } = request.params @@ -133,10 +108,8 @@ async function view (request, h) { module.exports = { cancel, index, - removeLicence, send, submitCancel, - submitRemoveLicence, submitSend, twoPartTariff, view diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index f4f81066b7..5fd93074c0 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -158,6 +158,30 @@ const routes = [ } } } + }, + { + method: 'GET', + path: '/bill-runs/review/licence/{reviewLicenceId}/remove', + options: { + handler: BillRunsReviewController.remove, + auth: { + access: { + scope: ['billing'] + } + } + } + }, + { + method: 'POST', + path: '/bill-runs/review/licence/{reviewLicenceId}/remove', + options: { + handler: BillRunsReviewController.submitRemove, + auth: { + access: { + scope: ['billing'] + } + } + } } ] diff --git a/app/routes/bill-runs.routes.js b/app/routes/bill-runs.routes.js index d0d3d424ce..0822eaa584 100644 --- a/app/routes/bill-runs.routes.js +++ b/app/routes/bill-runs.routes.js @@ -54,30 +54,6 @@ const routes = [ } } }, - { - method: 'GET', - path: '/bill-runs/{id}/remove/{licenceId}', - options: { - handler: BillRunsController.removeLicence, - auth: { - access: { - scope: ['billing'] - } - } - } - }, - { - method: 'POST', - path: '/bill-runs/{id}/remove/{licenceId}', - options: { - handler: BillRunsController.submitRemoveLicence, - auth: { - access: { - scope: ['billing'] - } - } - } - }, { method: 'GET', path: '/bill-runs/{id}/send', From 6060621ad26bff6566f51072b129ad9d0fff2892 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:19:15 +0000 Subject: [PATCH 082/147] Refactor review licence to link to remove licence --- .../bill-runs/review/review-licence.presenter.js | 14 +++++++------- app/views/bill-runs/review/review-licence.njk | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index 62a46cd285..e1469a145a 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -21,6 +21,7 @@ const DetermineAbstractionPeriodService = require('../../../services/bill-runs/d function go (reviewLicence) { const { billRun, + id: reviewLicenceId, licenceHolder, licenceId, licenceRef, @@ -35,16 +36,15 @@ function go (reviewLicence) { billRunId: billRun.id, chargeVersions: _chargeVersions(reviewChargeVersions, billRun.toFinancialYearEnding), elementsInReview: _elementsInReview(reviewChargeVersions), - licence: { - licenceId, - licenceRef, - status, - licenceHolder, - progress - }, + licenceHolder, + licenceId, + licenceRef, matchedReturns, pageTitle: `Licence ${licenceRef}`, + progress, region: billRun.region.displayName, + reviewLicenceId, + status, unmatchedReturns } } diff --git a/app/views/bill-runs/review/review-licence.njk b/app/views/bill-runs/review/review-licence.njk index 5cafd2803a..cfc27fc395 100644 --- a/app/views/bill-runs/review/review-licence.njk +++ b/app/views/bill-runs/review/review-licence.njk @@ -121,8 +121,8 @@

{{pageTitle}}

- Licence holder {{ licence.licenceHolder }} -

{{ statusTag(licence.status) }}
+ {{ licenceHolder }} +
{{ statusTag(status) }}

@@ -131,21 +131,21 @@
  • Summary
  • Returns
  • Charge information @@ -164,7 +164,7 @@
    {# Change status button #} - {% if licence.status === 'ready' %} + {% if status === 'ready' %} {% set statusButtonText = 'Put licence into review' %} {% set statusButtonValue = 'review' %} {% set statusButtonClass = "govuk-button--secondary" %} @@ -183,7 +183,7 @@ }) }} {# Mark progress button #} - {% if licence.progress %} + {% if progress %} {% set progressButtonText = 'Remove progress mark' %} {% set progressButtonValue = 'unmark' %} {% else %} @@ -203,7 +203,7 @@ {{ govukButton({ text: 'Remove from bill run', classes: "govuk-button--secondary", - href: "../remove/" + licence.licenceId, + href: '/system/bill-runs/review/licence/' + reviewLicenceId + '/remove', preventDoubleClick: true }) }}
    From 285cf10bb8f2f22e2bfb4f8e4ce2f56ab91f444d Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:43:57 +0000 Subject: [PATCH 083/147] Add $formatChargePeriod instance method to model --- app/models/review-charge-version.model.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/models/review-charge-version.model.js b/app/models/review-charge-version.model.js index 1963a48ced..012a46949d 100644 --- a/app/models/review-charge-version.model.js +++ b/app/models/review-charge-version.model.js @@ -8,6 +8,7 @@ const { Model } = require('objection') const BaseModel = require('./base.model.js') +const { formatLongDate } = require('../presenters/base.presenter.js') class ReviewChargeVersionModel extends BaseModel { static get tableName () { @@ -42,6 +43,18 @@ class ReviewChargeVersionModel extends BaseModel { } } } + + /** + * Formats the charge period into its string variant, for example, '1 April 2023 to 10 October 2023' + * + * @returns {string} The charge period formatted as a 'DD MMMM YYYY to DD MMMM YYYY' string + */ + $formatChargePeriod () { + const startDate = this.chargePeriodStartDate + const endDate = this.chargePeriodEndDate + + return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` + } } module.exports = ReviewChargeVersionModel From 28e0b1e2033c2edb78dc2fb94870fa3b14061c2b Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 22:44:42 +0000 Subject: [PATCH 084/147] Refactor presenters to use new instance method This removes a lot of duplication from the presenters. It'll also help slim down the tests needed at the presenter level. --- .../bill-runs/review/authorised.presenter.js | 11 ++--------- .../bill-runs/review/edit.presenter.js | 18 ++++++++---------- .../bill-runs/review/factors.presenter.js | 11 ++--------- .../review/review-charge-element.presenter.js | 18 ++++++++---------- .../review-charge-reference.presenter.js | 11 ++--------- .../review/review-licence.presenter.js | 2 +- 6 files changed, 23 insertions(+), 48 deletions(-) diff --git a/app/presenters/bill-runs/review/authorised.presenter.js b/app/presenters/bill-runs/review/authorised.presenter.js index afe3164364..f58ea568b4 100644 --- a/app/presenters/bill-runs/review/authorised.presenter.js +++ b/app/presenters/bill-runs/review/authorised.presenter.js @@ -7,7 +7,7 @@ const Big = require('big.js') -const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') +const { formatFinancialYear } = require('../../base.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference authorised page @@ -29,20 +29,13 @@ function go (reviewChargeReference) { return { amendedAuthorisedVolume, chargeDescription: chargeReference.chargeCategory.shortDescription, - chargePeriod: _chargePeriod(reviewChargeVersion), + chargePeriod: reviewChargeVersion.$formatChargePeriod(), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, totalBillableReturns: _totalBillableReturns(reviewChargeElements) } } -function _chargePeriod (reviewChargeVersion) { - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion - const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } - - return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` -} - function _totalBillableReturns (reviewChargeElements) { return reviewChargeElements.reduce((total, reviewChargeElement) => { const { amendedAllocated } = reviewChargeElement diff --git a/app/presenters/bill-runs/review/edit.presenter.js b/app/presenters/bill-runs/review/edit.presenter.js index a311997538..8a7fe80f97 100644 --- a/app/presenters/bill-runs/review/edit.presenter.js +++ b/app/presenters/bill-runs/review/edit.presenter.js @@ -26,14 +26,12 @@ function go (reviewChargeElement, elementIndex) { reviewChargeReference } = reviewChargeElement - const chargePeriod = _chargePeriod(reviewChargeReference.reviewChargeVersion) - return { authorisedQuantity: _authorisedQuantity(reviewChargeElement), billableReturns, chargeDescription: chargeElement.description, - chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, - chargePeriods: _chargePeriods(chargeElement, chargePeriod), + chargePeriod: reviewChargeReference.reviewChargeVersion.$formatChargePeriod(), + chargePeriods: _chargePeriods(reviewChargeElement), elementIndex, financialPeriod: formatFinancialYear( reviewChargeReference.reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding @@ -55,13 +53,9 @@ function _authorisedQuantity (reviewChargeElement) { return Math.min(chargeElement.authorisedAnnualQuantity, reviewChargeReference.amendedAuthorisedVolume) } -function _chargePeriod (reviewChargeVersion) { - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion - - return { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } -} +function _chargePeriods (reviewChargeElement) { + const { chargeElement, reviewChargeReference } = reviewChargeElement -function _chargePeriods (chargeElement, chargePeriod) { const { abstractionPeriodStartDay, abstractionPeriodStartMonth, @@ -69,6 +63,10 @@ function _chargePeriods (chargeElement, chargePeriod) { abstractionPeriodEndMonth } = chargeElement + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeReference.reviewChargeVersion + + const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } + const abstractionPeriods = DetermineAbstractionPeriodService.go( chargePeriod, abstractionPeriodStartDay, diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js index 19e794c452..8cb2f7af34 100644 --- a/app/presenters/bill-runs/review/factors.presenter.js +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -5,7 +5,7 @@ * @module FactorsPresenter */ -const { formatLongDate, formatFinancialYear } = require('../../base.presenter.js') +const { formatFinancialYear } = require('../../base.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference factors page @@ -31,7 +31,7 @@ function go (reviewChargeReference) { amendedAggregate, amendedChargeAdjustment, chargeDescription: chargeReference.chargeCategory.shortDescription, - chargePeriod: _chargePeriod(reviewChargeVersion), + chargePeriod: reviewChargeVersion.$formatChargePeriod(), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), otherAdjustments: [...additionalCharges, ...adjustments], reviewChargeReferenceId @@ -83,13 +83,6 @@ function _adjustments (reviewChargeReference) { return adjustments } -function _chargePeriod (reviewChargeVersion) { - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion - const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } - - return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` -} - module.exports = { go } diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index 21d64e0ac2..3e27d762c0 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -28,14 +28,12 @@ function go (reviewChargeElement, elementIndex) { status } = reviewChargeElement - const chargePeriod = _chargePeriod(reviewChargeReference.reviewChargeVersion) - return { authorisedVolume: chargeElement.authorisedAnnualQuantity, billableReturns, chargeDescription: chargeElement.description, - chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, - chargePeriods: _chargePeriods(chargeElement, chargePeriod), + chargePeriod: reviewChargeReference.reviewChargeVersion.$formatChargePeriod(), + chargePeriods: _chargePeriods(reviewChargeElement), elementCount: reviewChargeReference.reviewChargeElements.length, elementIndex, financialPeriod: formatFinancialYear( @@ -50,13 +48,9 @@ function go (reviewChargeElement, elementIndex) { } } -function _chargePeriod (reviewChargeVersion) { - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion - - return { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } -} +function _chargePeriods (reviewChargeElement) { + const { chargeElement, reviewChargeReference } = reviewChargeElement -function _chargePeriods (chargeElement, chargePeriod) { const { abstractionPeriodStartDay, abstractionPeriodStartMonth, @@ -64,6 +58,10 @@ function _chargePeriods (chargeElement, chargePeriod) { abstractionPeriodEndMonth } = chargeElement + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeReference.reviewChargeVersion + + const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } + const abstractionPeriods = DetermineAbstractionPeriodService.go( chargePeriod, abstractionPeriodStartDay, diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js index 887ce90126..178d8758f0 100644 --- a/app/presenters/bill-runs/review/review-charge-reference.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -7,7 +7,7 @@ const Big = require('big.js') -const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js') +const { formatFinancialYear } = require('../../base.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference page @@ -33,7 +33,7 @@ function go (reviewChargeReference) { canAmend: _canAmend(reviewChargeReference), chargeCategory: chargeReference.chargeCategory.reference, chargeDescription: chargeReference.chargeCategory.shortDescription, - chargePeriod: _chargePeriod(reviewChargeVersion), + chargePeriod: reviewChargeVersion.$formatChargePeriod(), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, reviewLicenceId: reviewChargeVersion.reviewLicence.id, @@ -104,13 +104,6 @@ function _canAmend (reviewChargeReference) { return (aggregate !== 1 || chargeAdjustment !== 1) } -function _chargePeriod (reviewChargeVersion) { - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion - const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } - - return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` -} - function _totalBillableReturns (reviewChargeElements) { return reviewChargeElements.reduce((total, reviewChargeElement) => { const { amendedAllocated } = reviewChargeElement diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index e1469a145a..77213f600c 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -161,7 +161,7 @@ function _chargeVersions (reviewChargeVersions, toFinancialYearEnding) { return { billingAccountDetails: _billingAccountDetails(chargeVersion.billingAccount), - chargePeriod: `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}`, + chargePeriod: reviewChargeVersion.$formatChargePeriod(), chargeReferences: _chargeReferences(reviewChargeReferences, chargePeriod), description: _chargeVersionDescription(reviewChargeReferences), financialPeriod: formatFinancialYear(toFinancialYearEnding) From 43c5c135f6ea47b134c90a6e32c27112e8ae21bc Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 3 Nov 2024 23:12:29 +0000 Subject: [PATCH 085/147] Create new base review presenter & add first helpler Determining the charge periods for an element entails extracting a number of properties from various objects, and then passing the values through DetermineAbstractionPeriodService. The results then need to be formatted. We've got 3 presenters that have to work this out, resulting in lots of duplication of the same code. To remove the duplication, we add a new `base-review.presenter.js`. We'll be adding some more duplicated presenter logic to it in the next few commits. --- .../bill-runs/review/base-review.presenter.js | 64 +++++++++++++++++++ .../bill-runs/review/edit.presenter.js | 35 +--------- .../review/review-charge-element.presenter.js | 33 +--------- .../review/review-licence.presenter.js | 27 +------- 4 files changed, 71 insertions(+), 88 deletions(-) create mode 100644 app/presenters/bill-runs/review/base-review.presenter.js diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js new file mode 100644 index 0000000000..5ca4bdb467 --- /dev/null +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -0,0 +1,64 @@ +'use strict' + +const { formatLongDate } = require('../../base.presenter.js') +const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') + +/** + * Determine the charge periods for a `ReviewChargeElementModel` and format them for display + * + * If the charge period is known, for example, the review licence presenter determines first and then passes it to + * various functions, then this can be provided. Else the function will assume the `ReviewChargeElementModel` instance + * contains a `reviewChargeReference` property that then contains a `reviewChargeVersion`. The charge period will be + * determined by extracting the start and end date from it. + * + * With the abstraction details and charge period determined, it calls `DetermineAbstractionPeriodService` to calculate + * the charge periods for the _element_. An element can have 1 or 2 charge periods, due to the way abstraction periods + * and financial years cross-over. + * + * With these calculated, they are passed through `formatLongDate()` and return for display in the UI. + * + * @param {module:ReviewChargeElementModel} reviewChargeElement - instance of `ReviewChargeElementModel` containing at + * least a `chargeElement` property populated with abstraction days and months + * @param {*} [chargePeriod] + * + * @returns {string[]} an array containing the review charge element's charge period(s) formatted as 'DD MMMM YYYY to DD + * MMMM YYYY' + */ +function formatChargePeriods (reviewChargeElement, chargePeriod = null) { + const { chargeElement, reviewChargeReference } = reviewChargeElement + + const { + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + } = chargeElement + + if (!chargePeriod) { + chargePeriod = _chargePeriod(reviewChargeReference.reviewChargeVersion) + } + + const abstractionPeriods = DetermineAbstractionPeriodService.go( + chargePeriod, + abstractionPeriodStartDay, + abstractionPeriodStartMonth, + abstractionPeriodEndDay, + abstractionPeriodEndMonth + ) + + return abstractionPeriods.map((abstractionPeriod) => { + const { endDate, startDate } = abstractionPeriod + + return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` + }) +} + +function _chargePeriod (reviewChargeVersion) { + const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion + + return { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } +} + +module.exports = { + formatChargePeriods +} diff --git a/app/presenters/bill-runs/review/edit.presenter.js b/app/presenters/bill-runs/review/edit.presenter.js index 8a7fe80f97..9edbc0fd69 100644 --- a/app/presenters/bill-runs/review/edit.presenter.js +++ b/app/presenters/bill-runs/review/edit.presenter.js @@ -5,8 +5,8 @@ * @module EditPresenter */ -const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') -const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js') +const { formatFinancialYear } = require('../../base.presenter.js') +const { formatChargePeriods } = require('./base-review.presenter.js') /** * Prepares and processes bill run and review charge element data for presenting @@ -31,7 +31,7 @@ function go (reviewChargeElement, elementIndex) { billableReturns, chargeDescription: chargeElement.description, chargePeriod: reviewChargeReference.reviewChargeVersion.$formatChargePeriod(), - chargePeriods: _chargePeriods(reviewChargeElement), + chargePeriods: formatChargePeriods(reviewChargeElement), elementIndex, financialPeriod: formatFinancialYear( reviewChargeReference.reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding @@ -53,35 +53,6 @@ function _authorisedQuantity (reviewChargeElement) { return Math.min(chargeElement.authorisedAnnualQuantity, reviewChargeReference.amendedAuthorisedVolume) } -function _chargePeriods (reviewChargeElement) { - const { chargeElement, reviewChargeReference } = reviewChargeElement - - const { - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - } = chargeElement - - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeReference.reviewChargeVersion - - const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } - - const abstractionPeriods = DetermineAbstractionPeriodService.go( - chargePeriod, - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - ) - - return abstractionPeriods.map((abstractionPeriod) => { - const { endDate, startDate } = abstractionPeriod - - return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` - }) -} - module.exports = { go } diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index 3e27d762c0..71e6163357 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -5,8 +5,8 @@ * @module ReviewChargeElementPresenter */ -const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') +const { formatChargePeriods } = require('./base-review.presenter.js') /** * Formats the review charge element data ready for presenting in the review charge element page @@ -33,7 +33,7 @@ function go (reviewChargeElement, elementIndex) { billableReturns, chargeDescription: chargeElement.description, chargePeriod: reviewChargeReference.reviewChargeVersion.$formatChargePeriod(), - chargePeriods: _chargePeriods(reviewChargeElement), + chargePeriods: formatChargePeriods(reviewChargeElement), elementCount: reviewChargeReference.reviewChargeElements.length, elementIndex, financialPeriod: formatFinancialYear( @@ -48,35 +48,6 @@ function go (reviewChargeElement, elementIndex) { } } -function _chargePeriods (reviewChargeElement) { - const { chargeElement, reviewChargeReference } = reviewChargeElement - - const { - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - } = chargeElement - - const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeReference.reviewChargeVersion - - const chargePeriod = { startDate: chargePeriodStartDate, endDate: chargePeriodEndDate } - - const abstractionPeriods = DetermineAbstractionPeriodService.go( - chargePeriod, - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - ) - - return abstractionPeriods.map((abstractionPeriod) => { - const { endDate, startDate } = abstractionPeriod - - return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` - }) -} - function _matchedReturns (reviewReturns) { return reviewReturns.map((reviewReturn) => { const { description, endDate, issues, purposes, returnLog, returnId, returnReference, startDate } = reviewReturn diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index 77213f600c..e4dc4b6ad1 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -8,7 +8,7 @@ const Big = require('big.js') const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') -const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') +const { formatChargePeriods } = require('./base-review.presenter.js') /** * Formats the review licence data ready for presenting in the review licence page @@ -67,7 +67,7 @@ function _chargeElements (reviewChargeElements, chargePeriod) { return { billableReturns: `${amendedAllocated} ML / ${chargeElement.authorisedAnnualQuantity} ML`, - chargePeriods: _chargeElementChargePeriod(chargeElement, chargePeriod), + chargePeriods: formatChargePeriods(reviewChargeElement, chargePeriod), returnVolumes: _chargeElementReturnVolumes(reviewReturns), description: chargeElement.description, elementCount: numberOfElements, @@ -80,29 +80,6 @@ function _chargeElements (reviewChargeElements, chargePeriod) { }) } -function _chargeElementChargePeriod (chargeElement, chargePeriod) { - const { - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - } = chargeElement - - const abstractionPeriods = DetermineAbstractionPeriodService.go( - chargePeriod, - abstractionPeriodStartDay, - abstractionPeriodStartMonth, - abstractionPeriodEndDay, - abstractionPeriodEndMonth - ) - - return abstractionPeriods.map((abstractionPeriod) => { - const { endDate, startDate } = abstractionPeriod - - return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` - }) -} - function _chargeElementReturnVolumes (reviewReturns) { return reviewReturns.map((reviewReturn) => { const { quantity, returnReference, returnStatus } = reviewReturn From ec4af067ebf6341617b0b09ca792c1392e17d1ca Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 08:49:24 +0000 Subject: [PATCH 086/147] Revert model change and move formatter to presenter --- app/models/review-charge-version.model.js | 13 ------------- .../bill-runs/review/authorised.presenter.js | 3 ++- .../bill-runs/review/base-review.presenter.js | 15 +++++++++++++++ app/presenters/bill-runs/review/edit.presenter.js | 4 ++-- .../bill-runs/review/factors.presenter.js | 3 ++- .../review/review-charge-element.presenter.js | 4 ++-- .../review/review-charge-reference.presenter.js | 3 ++- .../bill-runs/review/review-licence.presenter.js | 4 ++-- 8 files changed, 27 insertions(+), 22 deletions(-) diff --git a/app/models/review-charge-version.model.js b/app/models/review-charge-version.model.js index 012a46949d..1963a48ced 100644 --- a/app/models/review-charge-version.model.js +++ b/app/models/review-charge-version.model.js @@ -8,7 +8,6 @@ const { Model } = require('objection') const BaseModel = require('./base.model.js') -const { formatLongDate } = require('../presenters/base.presenter.js') class ReviewChargeVersionModel extends BaseModel { static get tableName () { @@ -43,18 +42,6 @@ class ReviewChargeVersionModel extends BaseModel { } } } - - /** - * Formats the charge period into its string variant, for example, '1 April 2023 to 10 October 2023' - * - * @returns {string} The charge period formatted as a 'DD MMMM YYYY to DD MMMM YYYY' string - */ - $formatChargePeriod () { - const startDate = this.chargePeriodStartDate - const endDate = this.chargePeriodEndDate - - return `${formatLongDate(startDate)} to ${formatLongDate(endDate)}` - } } module.exports = ReviewChargeVersionModel diff --git a/app/presenters/bill-runs/review/authorised.presenter.js b/app/presenters/bill-runs/review/authorised.presenter.js index f58ea568b4..40cb13838a 100644 --- a/app/presenters/bill-runs/review/authorised.presenter.js +++ b/app/presenters/bill-runs/review/authorised.presenter.js @@ -8,6 +8,7 @@ const Big = require('big.js') const { formatFinancialYear } = require('../../base.presenter.js') +const { formatChargePeriod } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference authorised page @@ -29,7 +30,7 @@ function go (reviewChargeReference) { return { amendedAuthorisedVolume, chargeDescription: chargeReference.chargeCategory.shortDescription, - chargePeriod: reviewChargeVersion.$formatChargePeriod(), + chargePeriod: formatChargePeriod(reviewChargeVersion), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, totalBillableReturns: _totalBillableReturns(reviewChargeElements) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index 5ca4bdb467..aa726ba8f9 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -3,6 +3,20 @@ const { formatLongDate } = require('../../base.presenter.js') const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') +/** + * Formats the charge period into its string variant, for example, '1 April 2023 to 10 October 2023' + * + * @param {module:ReviewChargeVersionModel} reviewChargeVersion - instance of `ReviewChargeVersionModel` to format the + * charge period for + * + * @returns {string} The review charge version's charge period formatted as a 'DD MMMM YYYY to DD MMMM YYYY' string + */ +function formatChargePeriod (reviewChargeVersion) { + const chargePeriod = _chargePeriod(reviewChargeVersion) + + return `${formatLongDate(chargePeriod.startDate)} to ${formatLongDate(chargePeriod.endDate)}` +} + /** * Determine the charge periods for a `ReviewChargeElementModel` and format them for display * @@ -60,5 +74,6 @@ function _chargePeriod (reviewChargeVersion) { } module.exports = { + formatChargePeriod, formatChargePeriods } diff --git a/app/presenters/bill-runs/review/edit.presenter.js b/app/presenters/bill-runs/review/edit.presenter.js index 9edbc0fd69..f3684a6dbc 100644 --- a/app/presenters/bill-runs/review/edit.presenter.js +++ b/app/presenters/bill-runs/review/edit.presenter.js @@ -6,7 +6,7 @@ */ const { formatFinancialYear } = require('../../base.presenter.js') -const { formatChargePeriods } = require('./base-review.presenter.js') +const { formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') /** * Prepares and processes bill run and review charge element data for presenting @@ -30,7 +30,7 @@ function go (reviewChargeElement, elementIndex) { authorisedQuantity: _authorisedQuantity(reviewChargeElement), billableReturns, chargeDescription: chargeElement.description, - chargePeriod: reviewChargeReference.reviewChargeVersion.$formatChargePeriod(), + chargePeriod: formatChargePeriod(reviewChargeReference.reviewChargeVersion), chargePeriods: formatChargePeriods(reviewChargeElement), elementIndex, financialPeriod: formatFinancialYear( diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js index 8cb2f7af34..b8929006a7 100644 --- a/app/presenters/bill-runs/review/factors.presenter.js +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -6,6 +6,7 @@ */ const { formatFinancialYear } = require('../../base.presenter.js') +const { formatChargePeriod } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference factors page @@ -31,7 +32,7 @@ function go (reviewChargeReference) { amendedAggregate, amendedChargeAdjustment, chargeDescription: chargeReference.chargeCategory.shortDescription, - chargePeriod: reviewChargeVersion.$formatChargePeriod(), + chargePeriod: formatChargePeriod(reviewChargeVersion), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), otherAdjustments: [...additionalCharges, ...adjustments], reviewChargeReferenceId diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index 71e6163357..a76ab7abfd 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -6,7 +6,7 @@ */ const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') -const { formatChargePeriods } = require('./base-review.presenter.js') +const { formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') /** * Formats the review charge element data ready for presenting in the review charge element page @@ -32,7 +32,7 @@ function go (reviewChargeElement, elementIndex) { authorisedVolume: chargeElement.authorisedAnnualQuantity, billableReturns, chargeDescription: chargeElement.description, - chargePeriod: reviewChargeReference.reviewChargeVersion.$formatChargePeriod(), + chargePeriod: formatChargePeriod(reviewChargeReference.reviewChargeVersion), chargePeriods: formatChargePeriods(reviewChargeElement), elementCount: reviewChargeReference.reviewChargeElements.length, elementIndex, diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js index 178d8758f0..bc77e23397 100644 --- a/app/presenters/bill-runs/review/review-charge-reference.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -8,6 +8,7 @@ const Big = require('big.js') const { formatFinancialYear } = require('../../base.presenter.js') +const { formatChargePeriod } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference page @@ -33,7 +34,7 @@ function go (reviewChargeReference) { canAmend: _canAmend(reviewChargeReference), chargeCategory: chargeReference.chargeCategory.reference, chargeDescription: chargeReference.chargeCategory.shortDescription, - chargePeriod: reviewChargeVersion.$formatChargePeriod(), + chargePeriod: formatChargePeriod(reviewChargeVersion), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, reviewLicenceId: reviewChargeVersion.reviewLicence.id, diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index e4dc4b6ad1..39b3ab4739 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -8,7 +8,7 @@ const Big = require('big.js') const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') -const { formatChargePeriods } = require('./base-review.presenter.js') +const { formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') /** * Formats the review licence data ready for presenting in the review licence page @@ -138,7 +138,7 @@ function _chargeVersions (reviewChargeVersions, toFinancialYearEnding) { return { billingAccountDetails: _billingAccountDetails(chargeVersion.billingAccount), - chargePeriod: reviewChargeVersion.$formatChargePeriod(), + chargePeriod: formatChargePeriod(reviewChargeVersion), chargeReferences: _chargeReferences(reviewChargeReferences, chargePeriod), description: _chargeVersionDescription(reviewChargeReferences), financialPeriod: formatFinancialYear(toFinancialYearEnding) From 2a693b736f5d7a93a4b923197b8687dd614996e5 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 08:57:26 +0000 Subject: [PATCH 087/147] Move total billable returns into base presenter --- .../bill-runs/review/authorised.presenter.js | 14 ++------------ .../bill-runs/review/base-review.presenter.js | 18 ++++++++++++++++++ .../review-charge-reference.presenter.js | 14 ++------------ .../review/review-licence.presenter.js | 14 ++------------ 4 files changed, 24 insertions(+), 36 deletions(-) diff --git a/app/presenters/bill-runs/review/authorised.presenter.js b/app/presenters/bill-runs/review/authorised.presenter.js index 40cb13838a..e3abf13869 100644 --- a/app/presenters/bill-runs/review/authorised.presenter.js +++ b/app/presenters/bill-runs/review/authorised.presenter.js @@ -5,10 +5,8 @@ * @module AuthorisedPresenter */ -const Big = require('big.js') - const { formatFinancialYear } = require('../../base.presenter.js') -const { formatChargePeriod } = require('./base-review.presenter.js') +const { calculateTotalBillableReturns, formatChargePeriod } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference authorised page @@ -33,18 +31,10 @@ function go (reviewChargeReference) { chargePeriod: formatChargePeriod(reviewChargeVersion), financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, - totalBillableReturns: _totalBillableReturns(reviewChargeElements) + totalBillableReturns: calculateTotalBillableReturns(reviewChargeElements) } } -function _totalBillableReturns (reviewChargeElements) { - return reviewChargeElements.reduce((total, reviewChargeElement) => { - const { amendedAllocated } = reviewChargeElement - - return Big(total).plus(amendedAllocated).toNumber() - }, 0) -} - module.exports = { go } diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index aa726ba8f9..27db757a5c 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -1,8 +1,25 @@ 'use strict' +const Big = require('big.js') + const { formatLongDate } = require('../../base.presenter.js') const DetermineAbstractionPeriodService = require('../../../services/bill-runs/determine-abstraction-periods.service.js') +/** + * Calculates the total allocated volume across all review change elements + * + * @param {module:ReviewChargeElementModel[]} reviewChargeElements - array of `ReviewChargeElementModel` instances + * + * @returns {string} the sum of allocated volume against all review charge elements without loss of precision + */ +function calculateTotalBillableReturns (reviewChargeElements) { + return reviewChargeElements.reduce((total, reviewChargeElement) => { + const { amendedAllocated } = reviewChargeElement + + return Big(total).plus(amendedAllocated).toNumber() + }, 0) +} + /** * Formats the charge period into its string variant, for example, '1 April 2023 to 10 October 2023' * @@ -74,6 +91,7 @@ function _chargePeriod (reviewChargeVersion) { } module.exports = { + calculateTotalBillableReturns, formatChargePeriod, formatChargePeriods } diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js index bc77e23397..203ba778bd 100644 --- a/app/presenters/bill-runs/review/review-charge-reference.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -5,10 +5,8 @@ * @module ReviewChargeReferencePresenter */ -const Big = require('big.js') - const { formatFinancialYear } = require('../../base.presenter.js') -const { formatChargePeriod } = require('./base-review.presenter.js') +const { calculateTotalBillableReturns, formatChargePeriod } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference page @@ -38,7 +36,7 @@ function go (reviewChargeReference) { financialPeriod: formatFinancialYear(reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding), reviewChargeReferenceId, reviewLicenceId: reviewChargeVersion.reviewLicence.id, - totalBillableReturns: _totalBillableReturns(reviewChargeElements) + totalBillableReturns: calculateTotalBillableReturns(reviewChargeElements) } } @@ -105,14 +103,6 @@ function _canAmend (reviewChargeReference) { return (aggregate !== 1 || chargeAdjustment !== 1) } -function _totalBillableReturns (reviewChargeElements) { - return reviewChargeElements.reduce((total, reviewChargeElement) => { - const { amendedAllocated } = reviewChargeElement - - return Big(total).plus(amendedAllocated).toNumber() - }, 0) -} - module.exports = { go } diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index 39b3ab4739..24e37f79f4 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -5,10 +5,8 @@ * @module ReviewLicencePresenter */ -const Big = require('big.js') - const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') -const { formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') +const { calculateTotalBillableReturns, formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') /** * Formats the review licence data ready for presenting in the review licence page @@ -95,7 +93,7 @@ function _chargeElementReturnVolumes (reviewReturns) { function _chargeReferences (reviewChargeReferences, chargePeriod) { return reviewChargeReferences.map((reviewChargeReference) => { const { amendedAuthorisedVolume, chargeReference, reviewChargeElements, id } = reviewChargeReference - const totalAllocated = _totalAllocated(reviewChargeElements) + const totalAllocated = calculateTotalBillableReturns(reviewChargeElements) return { billableReturnsWarning: totalAllocated > amendedAuthorisedVolume, @@ -227,14 +225,6 @@ function _returnTotal (reviewReturn) { return `${allocated} ML / ${quantity} ML` } -function _totalAllocated (reviewChargeElements) { - return reviewChargeElements.reduce((total, reviewChargeElement) => { - const { amendedAllocated } = reviewChargeElement - - return Big(total).plus(amendedAllocated).toNumber() - }, 0) -} - module.exports = { go } From e71efaa22bac77bdbf951be401a7ce3bdf6d64d2 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 09:40:56 +0000 Subject: [PATCH 088/147] Move additional charges and return link into base --- .../bill-runs/review/base-review.presenter.js | 54 +++++++++++++++++++ .../bill-runs/review/factors.presenter.js | 20 +------ .../review/review-charge-element.presenter.js | 18 +++---- .../review-charge-reference.presenter.js | 24 +++------ .../review/review-licence.presenter.js | 19 +++---- 5 files changed, 75 insertions(+), 60 deletions(-) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index 27db757a5c..f8405f2fc7 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -20,6 +20,58 @@ function calculateTotalBillableReturns (reviewChargeElements) { }, 0) } +/** + * Determine the link for a return, for example, should it go to the edit or view page? + * + * @param {module:ReviewReturnModel} reviewReturn - instance of `ReviewReturn` to determine the link for + * + * @returns {string} the relative URL the view template should use to link to the return + */ +function determineReturnLink (reviewReturn) { + const { returnId, returnStatus } = reviewReturn + + if (['due', 'received'].includes(returnStatus)) { + return `/return/internal?returnId=${returnId}` + } + + return `/returns/return?id=${returnId}` +} + +/** + * Extract and format the additional charges from a charge reference for display + * + * If the charge reference has both a supported source and is a public water company then the following is returned. + * + * ```javascript + * const additionalCharges = [ + * 'Supported source foo', + * 'Public Water Supply' + * ] + * ``` + * + * If it has known an empty array is returned + * + * @param {object} chargeReference - an object representing as 'Charge Reference' that has the properties + * `supportedSourceName` and `waterCompanyCharge`, taken from the charge reference's `additionalCharges` field + * + * @returns {string[]} the additional charges (if present) formatted as a string for display + */ +function formatAdditionalCharges (chargeReference) { + const { supportedSourceName, waterCompanyCharge } = chargeReference + + const additionalCharges = [] + + if (supportedSourceName) { + additionalCharges.push(`Supported source ${supportedSourceName}`) + } + + if (waterCompanyCharge) { + additionalCharges.push('Public Water Supply') + } + + return additionalCharges +} + /** * Formats the charge period into its string variant, for example, '1 April 2023 to 10 October 2023' * @@ -92,6 +144,8 @@ function _chargePeriod (reviewChargeVersion) { module.exports = { calculateTotalBillableReturns, + determineReturnLink, + formatAdditionalCharges, formatChargePeriod, formatChargePeriods } diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js index b8929006a7..b2abfcb2c3 100644 --- a/app/presenters/bill-runs/review/factors.presenter.js +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -6,7 +6,7 @@ */ const { formatFinancialYear } = require('../../base.presenter.js') -const { formatChargePeriod } = require('./base-review.presenter.js') +const { formatAdditionalCharges, formatChargePeriod } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference factors page @@ -25,7 +25,7 @@ function go (reviewChargeReference) { id: reviewChargeReferenceId } = reviewChargeReference - const additionalCharges = _additionalCharges(chargeReference) + const additionalCharges = formatAdditionalCharges(chargeReference) const adjustments = _adjustments(reviewChargeReference) return { @@ -39,22 +39,6 @@ function go (reviewChargeReference) { } } -function _additionalCharges (chargeReference) { - const { supportedSourceName, waterCompanyCharge } = chargeReference - - const additionalCharges = [] - - if (supportedSourceName) { - additionalCharges.push(`Supported source ${supportedSourceName}`) - } - - if (waterCompanyCharge) { - additionalCharges.push('Public Water Supply') - } - - return additionalCharges -} - function _adjustments (reviewChargeReference) { const { abatementAgreement, diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index a76ab7abfd..ad2f121008 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -6,7 +6,11 @@ */ const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') -const { formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') +const { + determineReturnLink, + formatChargePeriod, + formatChargePeriods +} = require('./base-review.presenter.js') /** * Formats the review charge element data ready for presenting in the review charge element page @@ -60,7 +64,7 @@ function _matchedReturns (reviewReturns) { purpose: purposes[0].tertiary.description, reference: returnReference, returnId, - returnLink: _returnLink(reviewReturn), + returnLink: determineReturnLink(reviewReturn), returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, returnStatus: _returnStatus(reviewReturn), returnTotal: _returnTotal(reviewReturn) @@ -68,16 +72,6 @@ function _matchedReturns (reviewReturns) { }) } -function _returnLink (reviewReturn) { - const { returnId, returnStatus } = reviewReturn - - if (['due', 'received'].includes(returnStatus)) { - return `/return/internal?returnId=${returnId}` - } - - return `/returns/return?id=${returnId}` -} - function _returnStatus (reviewReturn) { const { returnStatus, underQuery } = reviewReturn diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js index 203ba778bd..6756f1d1aa 100644 --- a/app/presenters/bill-runs/review/review-charge-reference.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -6,7 +6,11 @@ */ const { formatFinancialYear } = require('../../base.presenter.js') -const { calculateTotalBillableReturns, formatChargePeriod } = require('./base-review.presenter.js') +const { + calculateTotalBillableReturns, + formatAdditionalCharges, + formatChargePeriod +} = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference page @@ -26,7 +30,7 @@ function go (reviewChargeReference) { } = reviewChargeReference return { - additionalCharges: _additionalCharges(chargeReference), + additionalCharges: formatAdditionalCharges(chargeReference).join(', '), adjustments: _adjustments(reviewChargeReference), amendedAuthorisedVolume, canAmend: _canAmend(reviewChargeReference), @@ -40,22 +44,6 @@ function go (reviewChargeReference) { } } -function _additionalCharges (chargeReference) { - const { supportedSourceName, waterCompanyCharge } = chargeReference - - const additionalCharges = [] - - if (supportedSourceName) { - additionalCharges.push(`Supported source ${supportedSourceName}`) - } - - if (waterCompanyCharge) { - additionalCharges.push('Public Water Supply') - } - - return additionalCharges.join(', ') -} - function _adjustments (reviewChargeReference) { const { abatementAgreement, diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index 24e37f79f4..eeece754cf 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -6,7 +6,12 @@ */ const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require('../../base.presenter.js') -const { calculateTotalBillableReturns, formatChargePeriod, formatChargePeriods } = require('./base-review.presenter.js') +const { + calculateTotalBillableReturns, + determineReturnLink, + formatChargePeriod, + formatChargePeriods +} = require('./base-review.presenter.js') /** * Formats the review licence data ready for presenting in the review licence page @@ -175,7 +180,7 @@ function _formatReviewReturns (reviewReturns) { purpose: purposes[0].tertiary.description, reference: returnReference, returnId, - returnLink: _returnLink(reviewReturn), + returnLink: determineReturnLink(reviewReturn), returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, returnStatus: _returnStatus(reviewReturn), returnTotal: _returnTotal(reviewReturn) @@ -191,16 +196,6 @@ function _formatReviewReturns (reviewReturns) { return { matchedReturns, unmatchedReturns } } -function _returnLink (reviewReturn) { - const { returnId, returnStatus } = reviewReturn - - if (['due', 'received'].includes(returnStatus)) { - return `/return/internal?returnId=${returnId}` - } - - return `/returns/return?id=${returnId}` -} - function _returnStatus (reviewReturn) { const { returnStatus, underQuery } = reviewReturn From cbcf175357221f8de463fbff2e7627bbce6bbefe Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 09:49:40 +0000 Subject: [PATCH 089/147] Move return status to base presenter --- .../bill-runs/review/base-review.presenter.js | 31 ++++++++++++++++++- .../review/review-charge-element.presenter.js | 19 ++---------- .../review/review-licence.presenter.js | 19 ++---------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index f8405f2fc7..37916fbd68 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -136,6 +136,34 @@ function formatChargePeriods (reviewChargeElement, chargePeriod = null) { }) } +/** + * Format the status for a review return, for example, 'overdue' + * + * We cannot just return the status from the DB for a return because of the disparity between what we show and how the + * status is stored. For example, the status field in the DB holds completed, due, received, and void. When the review + * screens display the return we can assume anything with a status of `due` is overdue, hence the first disparity. + * + * The other is that if a return is under query this is not reflected in the status. Instead, a flag is set in a + * different field. + * + * @param {module:ReviewReturnModel} reviewReturn - instance of `ReviewReturn` to format the status for + * + * @returns {string} the return's status formatted for display + */ +function formatReturnStatus (reviewReturn) { + const { returnStatus, underQuery } = reviewReturn + + if (returnStatus === 'due') { + return 'overdue' + } + + if (underQuery) { + return 'query' + } + + return reviewReturn.returnStatus +} + function _chargePeriod (reviewChargeVersion) { const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion @@ -147,5 +175,6 @@ module.exports = { determineReturnLink, formatAdditionalCharges, formatChargePeriod, - formatChargePeriods + formatChargePeriods, + formatReturnStatus } diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index ad2f121008..489a58f917 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -9,7 +9,8 @@ const { formatAbstractionPeriod, formatFinancialYear, formatLongDate } = require const { determineReturnLink, formatChargePeriod, - formatChargePeriods + formatChargePeriods, + formatReturnStatus } = require('./base-review.presenter.js') /** @@ -66,26 +67,12 @@ function _matchedReturns (reviewReturns) { returnId, returnLink: determineReturnLink(reviewReturn), returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, - returnStatus: _returnStatus(reviewReturn), + returnStatus: formatReturnStatus(reviewReturn), returnTotal: _returnTotal(reviewReturn) } }) } -function _returnStatus (reviewReturn) { - const { returnStatus, underQuery } = reviewReturn - - if (returnStatus === 'due') { - return 'overdue' - } - - if (underQuery) { - return 'query' - } - - return reviewReturn.returnStatus -} - function _returnTotal (reviewReturn) { const { allocated, quantity, returnStatus } = reviewReturn diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index eeece754cf..d36e0ee42c 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -10,7 +10,8 @@ const { calculateTotalBillableReturns, determineReturnLink, formatChargePeriod, - formatChargePeriods + formatChargePeriods, + formatReturnStatus } = require('./base-review.presenter.js') /** @@ -182,7 +183,7 @@ function _formatReviewReturns (reviewReturns) { returnId, returnLink: determineReturnLink(reviewReturn), returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, - returnStatus: _returnStatus(reviewReturn), + returnStatus: formatReturnStatus(reviewReturn), returnTotal: _returnTotal(reviewReturn) } @@ -196,20 +197,6 @@ function _formatReviewReturns (reviewReturns) { return { matchedReturns, unmatchedReturns } } -function _returnStatus (reviewReturn) { - const { returnStatus, underQuery } = reviewReturn - - if (returnStatus === 'due') { - return 'overdue' - } - - if (underQuery) { - return 'query' - } - - return reviewReturn.returnStatus -} - function _returnTotal (reviewReturn) { const { allocated, quantity, returnStatus } = reviewReturn From e69585e6af69550acbc297d785d70ab248ca5e77 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 09:54:14 +0000 Subject: [PATCH 090/147] Move return total to base presenter --- .../bill-runs/review/base-review.presenter.js | 20 ++++++++++++++++++- .../review/review-charge-element.presenter.js | 15 +++----------- .../review/review-licence.presenter.js | 15 +++----------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index 37916fbd68..9f39efae14 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -164,6 +164,23 @@ function formatReturnStatus (reviewReturn) { return reviewReturn.returnStatus } +/** + * Format the total allocated vs quantity for a review return, for example, '15.5 ML / 20 ML' + * + * @param {module:ReviewReturnModel} reviewReturn - instance of `ReviewReturn` to format the totals for + * + * @returns the return's totals formatted for display + */ +function formatReturnTotals (reviewReturn) { + const { allocated, quantity, returnStatus } = reviewReturn + + if (['due', 'received'].includes(returnStatus)) { + return '/' + } + + return `${allocated} ML / ${quantity} ML` +} + function _chargePeriod (reviewChargeVersion) { const { chargePeriodStartDate, chargePeriodEndDate } = reviewChargeVersion @@ -176,5 +193,6 @@ module.exports = { formatAdditionalCharges, formatChargePeriod, formatChargePeriods, - formatReturnStatus + formatReturnStatus, + formatReturnTotals } diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index 489a58f917..2ad02246d7 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -10,7 +10,8 @@ const { determineReturnLink, formatChargePeriod, formatChargePeriods, - formatReturnStatus + formatReturnStatus, + formatReturnTotals } = require('./base-review.presenter.js') /** @@ -68,21 +69,11 @@ function _matchedReturns (reviewReturns) { returnLink: determineReturnLink(reviewReturn), returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, returnStatus: formatReturnStatus(reviewReturn), - returnTotal: _returnTotal(reviewReturn) + returnTotal: formatReturnTotals(reviewReturn) } }) } -function _returnTotal (reviewReturn) { - const { allocated, quantity, returnStatus } = reviewReturn - - if (['due', 'received'].includes(returnStatus)) { - return '/' - } - - return `${allocated} ML / ${quantity} ML` -} - module.exports = { go } diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index d36e0ee42c..fafec8b36f 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -11,7 +11,8 @@ const { determineReturnLink, formatChargePeriod, formatChargePeriods, - formatReturnStatus + formatReturnStatus, + formatReturnTotals } = require('./base-review.presenter.js') /** @@ -184,7 +185,7 @@ function _formatReviewReturns (reviewReturns) { returnLink: determineReturnLink(reviewReturn), returnPeriod: `${formatLongDate(startDate)} to ${formatLongDate(endDate)}`, returnStatus: formatReturnStatus(reviewReturn), - returnTotal: _returnTotal(reviewReturn) + returnTotal: formatReturnTotals(reviewReturn) } if (reviewReturn.reviewChargeElements.length > 0) { @@ -197,16 +198,6 @@ function _formatReviewReturns (reviewReturns) { return { matchedReturns, unmatchedReturns } } -function _returnTotal (reviewReturn) { - const { allocated, quantity, returnStatus } = reviewReturn - - if (['due', 'received'].includes(returnStatus)) { - return '/' - } - - return `${allocated} ML / ${quantity} ML` -} - module.exports = { go } From 15f9c3604d2f81aad47ee72399a0c57ce0939ab1 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 09:59:37 +0000 Subject: [PATCH 091/147] Housekeeping - Update param in review link --- app/controllers/bill-runs-review.controller.js | 10 +++++----- app/routes/bill-runs-review.routes.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index 1ceef83f8e..bfffa58b05 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -74,10 +74,10 @@ async function remove (request, h) { } async function review (request, h) { - const { id } = request.params + const { billRunId } = request.params const { page } = request.query - const pageData = await ReviewBillRunService.go(id, page, request.yar) + const pageData = await ReviewBillRunService.go(billRunId, page, request.yar) return h.view('bill-runs/review/review.njk', { activeNavBar: 'bill-runs', @@ -167,11 +167,11 @@ async function submitRemove (request, h) { } async function submitReview (request, h) { - const { id } = request.params + const { billRunId } = request.params - await SubmitReviewBillRunService.go(id, request.payload, request.yar) + await SubmitReviewBillRunService.go(billRunId, request.payload, request.yar) - return h.redirect(`/system/bill-runs/review/${id}`) + return h.redirect(`/system/bill-runs/review/${billRunId}`) } async function submitReviewLicence (request, h) { diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 5fd93074c0..955bfd2ba7 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -5,7 +5,7 @@ const BillRunsReviewController = require('../controllers/bill-runs-review.contro const routes = [ { method: 'GET', - path: '/bill-runs/review/{id}', + path: '/bill-runs/review/{billRunId}', options: { handler: BillRunsReviewController.review, auth: { @@ -17,7 +17,7 @@ const routes = [ }, { method: 'POST', - path: '/bill-runs/review/{id}', + path: '/bill-runs/review/{billRunId}', options: { handler: BillRunsReviewController.submitReview, auth: { From d5ba94b36e36eabd36b67d417ff1032f80012722 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 11:28:44 +0000 Subject: [PATCH 092/147] Make controller names consistent with others --- app/controllers/bill-runs-review.controller.js | 8 ++++---- app/routes/bill-runs-review.routes.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index bfffa58b05..cc96136b61 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -73,7 +73,7 @@ async function remove (request, h) { }) } -async function review (request, h) { +async function reviewBillRun (request, h) { const { billRunId } = request.params const { page } = request.query @@ -166,7 +166,7 @@ async function submitRemove (request, h) { return h.redirect(`/system/bill-runs/review/${result.billRunId}`) } -async function submitReview (request, h) { +async function submitReviewBillRun (request, h) { const { billRunId } = request.params await SubmitReviewBillRunService.go(billRunId, request.payload, request.yar) @@ -188,7 +188,7 @@ module.exports = { factors, preview, remove, - review, + reviewBillRun, reviewChargeElement, reviewChargeReference, reviewLicence, @@ -196,6 +196,6 @@ module.exports = { submitEdit, submitFactors, submitRemove, - submitReview, + submitReviewBillRun, submitReviewLicence } diff --git a/app/routes/bill-runs-review.routes.js b/app/routes/bill-runs-review.routes.js index 955bfd2ba7..c1a47bf9b6 100644 --- a/app/routes/bill-runs-review.routes.js +++ b/app/routes/bill-runs-review.routes.js @@ -7,7 +7,7 @@ const routes = [ method: 'GET', path: '/bill-runs/review/{billRunId}', options: { - handler: BillRunsReviewController.review, + handler: BillRunsReviewController.reviewBillRun, auth: { access: { scope: ['billing'] @@ -19,7 +19,7 @@ const routes = [ method: 'POST', path: '/bill-runs/review/{billRunId}', options: { - handler: BillRunsReviewController.submitReview, + handler: BillRunsReviewController.submitReviewBillRun, auth: { access: { scope: ['billing'] From 296576009dce79491794c9a0bd4f0f3af743a73c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 4 Nov 2024 22:19:46 +0000 Subject: [PATCH 093/147] Fix active nav bar Spotted when starting to fix the tests that where we are not specifying the active nav bar in the controller, we were returning 'search' instead of 'bill-runs'. This means the nav bar was flicking between options depending on what review page you were on. To try and avoid this in future we set the active in _all_ controllers and avoid setting it in the services. --- app/controllers/bill-runs-review.controller.js | 15 ++++++++++++--- .../bill-runs/review/submit-authorised.service.js | 7 +++---- .../bill-runs/review/submit-edit.service.js | 5 ++--- .../bill-runs/review/submit-factors.service.js | 7 +++---- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/controllers/bill-runs-review.controller.js b/app/controllers/bill-runs-review.controller.js index cc96136b61..ecc06fa0f8 100644 --- a/app/controllers/bill-runs-review.controller.js +++ b/app/controllers/bill-runs-review.controller.js @@ -123,7 +123,10 @@ async function submitAuthorised (request, h) { const pageData = await SubmitAuthorisedService.go(reviewChargeReferenceId, request.yar, request.payload) if (pageData.error) { - return h.view('bill-runs/review/authorised.njk', pageData) + return h.view('bill-runs/review/authorised.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) } return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) @@ -137,7 +140,10 @@ async function submitEdit (request, h) { ) if (pageData.error) { - return h.view('bill-runs/review/edit.njk', pageData) + return h.view('bill-runs/review/edit.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) } return h.redirect(`/system/bill-runs/review/charge-element/${reviewChargeElementId}/${elementIndex}`) @@ -148,7 +154,10 @@ async function submitFactors (request, h) { const pageData = await SubmitFactorsService.go(reviewChargeReferenceId, request.yar, request.payload) if (pageData.error) { - return h.view('bill-runs/review/factors.njk', pageData) + return h.view('bill-runs/review/factors.njk', { + activeNavBar: 'bill-runs', + ...pageData + }) } return h.redirect(`/system/bill-runs/review/charge-reference/${reviewChargeReferenceId}`) diff --git a/app/services/bill-runs/review/submit-authorised.service.js b/app/services/bill-runs/review/submit-authorised.service.js index 55ee748f57..a1ec47b74f 100644 --- a/app/services/bill-runs/review/submit-authorised.service.js +++ b/app/services/bill-runs/review/submit-authorised.service.js @@ -34,11 +34,10 @@ async function go (reviewChargeReferenceId, yar, payload) { const pageData = AuthorisedPresenter.go(reviewChargeReference) return { - activeNavBar: 'search', - pageTitle: 'Set the authorised volume', + amendedAuthorisedVolume: payload.amendedAuthorisedVolume, error: validationResult, - ...pageData, - amendedAuthorisedVolume: payload.amendedAuthorisedVolume + pageTitle: 'Set the authorised volume', + ...pageData } } diff --git a/app/services/bill-runs/review/submit-edit.service.js b/app/services/bill-runs/review/submit-edit.service.js index 2f90c19f4f..d7c35da9a1 100644 --- a/app/services/bill-runs/review/submit-edit.service.js +++ b/app/services/bill-runs/review/submit-edit.service.js @@ -35,11 +35,10 @@ async function go (reviewChargeElementId, elementIndex, yar, payload) { const pageData = EditPresenter.go(reviewChargeElement, elementIndex) return { - activeNavBar: 'search', - pageTitle: 'Set the billable returns quantity for this bill run', - error: validationResult, customQuantitySelected: payload.quantityOptions === 'customQuantity', customQuantityValue: payload.customQuantity, + error: validationResult, + pageTitle: 'Set the billable returns quantity for this bill run', ...pageData } } diff --git a/app/services/bill-runs/review/submit-factors.service.js b/app/services/bill-runs/review/submit-factors.service.js index 2788aeffb6..9415757ad9 100644 --- a/app/services/bill-runs/review/submit-factors.service.js +++ b/app/services/bill-runs/review/submit-factors.service.js @@ -43,12 +43,11 @@ async function go (reviewChargeReferenceId, yar, payload) { const pageData = FactorsPresenter.go(reviewChargeReference) return { - activeNavBar: 'search', + amendedAggregate: payload.amendedAggregate, + amendedChargeAdjustment: payload.amendedChargeAdjustment, error: validationResult, pageTitle: 'Set the adjustment factors', - ...pageData, - amendedAggregate: payload.amendedAggregate, - amendedChargeAdjustment: payload.amendedChargeAdjustment + ...pageData } } From e2569a3d191f9e63cd4943cd384017125073c86e Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 16:38:39 +0000 Subject: [PATCH 094/147] Housekeeping - remove hard coded return reference Plus make the generation of the reference consistent by putting the logic in one place. --- test/support/helpers/return-log.helper.js | 6 +++--- test/support/helpers/return-requirement.helper.js | 14 ++++++++++++-- test/support/helpers/review-return.helper.js | 14 +++++++------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/test/support/helpers/return-log.helper.js b/test/support/helpers/return-log.helper.js index a9e7fbe5be..f9657a0fef 100644 --- a/test/support/helpers/return-log.helper.js +++ b/test/support/helpers/return-log.helper.js @@ -5,9 +5,9 @@ */ const { generateLicenceRef } = require('./licence.helper.js') -const { randomInteger } = require('../general.js') const { timestampForPostgres } = require('../../../app/lib/general.lib.js') const ReturnLogModel = require('../../../app/models/return-log.model.js') +const { generateLegacyId } = require('./return-requirement.helper.js') /** * Add a new return log @@ -51,7 +51,7 @@ function add (data = {}) { */ function defaults (data = {}) { const licenceRef = data.licenceRef ? data.licenceRef : generateLicenceRef() - const returnReference = data.returnReference ? data.returnReference : randomInteger(10000000, 19999999) + const returnReference = data.returnReference ? data.returnReference : generateLegacyId() const timestamp = timestampForPostgres() const receivedDate = data.receivedDate ? data.receivedDate : null @@ -127,7 +127,7 @@ function generateReturnLogId ( } if (!returnReference) { - returnReference = randomInteger(10000000, 19999999) + returnReference = generateLegacyId() } return `v${version}:1:${licenceRef}:${returnReference}:${startDate}:${endDate}` diff --git a/test/support/helpers/return-requirement.helper.js b/test/support/helpers/return-requirement.helper.js index 614b6e3a1e..b6f95a8a2d 100644 --- a/test/support/helpers/return-requirement.helper.js +++ b/test/support/helpers/return-requirement.helper.js @@ -46,7 +46,7 @@ function add (data = {}) { * @returns {object} - Returns the set defaults with the override data spread */ function defaults (data = {}) { - const legacyId = data.legacyId ? data.legacyId : randomInteger(100, 99999) + const legacyId = data.legacyId ? data.legacyId : generateLegacyId() const defaults = { abstractionPeriodStartDay: 1, @@ -66,7 +66,17 @@ function defaults (data = {}) { } } +/** + * Generates a return requirement legacy ID (also known as return reference) + * + * @returns {number} + */ +function generateLegacyId () { + return randomInteger(100, 19999999) +} + module.exports = { add, - defaults + defaults, + generateLegacyId } diff --git a/test/support/helpers/review-return.helper.js b/test/support/helpers/review-return.helper.js index 071f17034d..2284bd4949 100644 --- a/test/support/helpers/review-return.helper.js +++ b/test/support/helpers/review-return.helper.js @@ -4,10 +4,10 @@ * @module ReviewReturnHelper */ -const { randomInteger } = require('../general.js') const { generateUUID } = require('../../../app/lib/general.lib.js') const { generateLicenceRef } = require('./licence.helper.js') const { generateReturnLogId } = require('./return-log.helper.js') +const { generateLegacyId } = require('./return-requirement.helper.js') const ReviewReturnModel = require('../../../app/models/review-return.model.js') /** @@ -17,7 +17,7 @@ const ReviewReturnModel = require('../../../app/models/review-return.model.js') * * - `reviewLicenceId` - [random UUID] * - `returnId` - v1:1:[the generated licenceRef]:[the generated returnReference]:2022-04-01:2023-03-31 - * - `returnReference` - `10031343` + * - `returnReference` - [randomly generated - 10000321] * - `quantity` - 0 * - `allocated` - 0 * - `underQuery` - false @@ -26,11 +26,11 @@ const ReviewReturnModel = require('../../../app/models/review-return.model.js') * - `abstractionOutsidePeriod` - false * - `receivedDate` - 2022-06-03 * - `dueDate` - 2022-06-03 - * - `purposes` - {} + * - `purposes` - [{}] * - `description` - Lands at Mosshayne Farm, Exeter & Broadclyst * - `startDate` - 2022-04-01 * - `endDate` - 2022-05-06 - * - `issues` - null + * - `issues` - '' * * @param {object} [data] - Any data you want to use instead of the defaults used here or in the database * @@ -56,12 +56,12 @@ function add (data = {}) { */ function defaults (data = {}) { const licenceRef = data.licenceRef ? data.licenceRef : generateLicenceRef() - const returnReference = data.returnReference ? data.returnReference : randomInteger(10000000, 19999999) + const returnReference = data.returnReference ? data.returnReference : generateLegacyId() const defaults = { reviewLicenceId: generateUUID(), returnId: generateReturnLogId('2022-04-01', '2023-03-31', 1, licenceRef, returnReference), - returnReference: '10031343', + returnReference, quantity: 0, allocated: 0, underQuery: false, @@ -74,7 +74,7 @@ function defaults (data = {}) { description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', startDate: new Date('2022-04-01'), endDate: new Date('2022-05-06'), - issues: null + issues: '' } return { From b94b4b7587b2f027c4b46f4c23354b5cd8059229 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 16:40:10 +0000 Subject: [PATCH 095/147] Fix issue handling Spotted that where there are no issues, our logic was written with the assumption the value we'd see in the DB was null. In fact, it is getting set to an empty string. Really, it should be null. But fixing that feels outside the scope of this tidying up. So, instead we move to formatting of issues to a central place so we don't overlook this quirk in future. --- .../bill-runs/review/base-review.presenter.js | 22 +++++++++++++++++++ .../review/review-charge-element.presenter.js | 5 +++-- .../review/review-licence.presenter.js | 5 +++-- .../helpers/review-charge-element.helper.js | 4 ++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index 9f39efae14..38426a611e 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -136,6 +136,27 @@ function formatChargePeriods (reviewChargeElement, chargePeriod = null) { }) } +/** + * Formats the issues held against review charge elements and returns for display + * + * TODO: Use NULL for no issues not an empty string + * + * An oversight when setting up the table/logic means 'issues' in `review_returns` and `review_charge_elements` is never + * null. If there are no issues we are setting it to an empty string not NULL. This means we always get a string back + * from the DB. + * + * @param {string} issues - the issues from the review charge element or return as a comma separated string + * + * @returns {string[]} the issues as a string array, else an empty array if issues is equal to '' + */ +function formatIssues (issues) { + if (issues === '') { + return [] + } + + return issues.split(', ') +} + /** * Format the status for a review return, for example, 'overdue' * @@ -193,6 +214,7 @@ module.exports = { formatAdditionalCharges, formatChargePeriod, formatChargePeriods, + formatIssues, formatReturnStatus, formatReturnTotals } diff --git a/app/presenters/bill-runs/review/review-charge-element.presenter.js b/app/presenters/bill-runs/review/review-charge-element.presenter.js index 2ad02246d7..7aad97b289 100644 --- a/app/presenters/bill-runs/review/review-charge-element.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-element.presenter.js @@ -10,6 +10,7 @@ const { determineReturnLink, formatChargePeriod, formatChargePeriods, + formatIssues, formatReturnStatus, formatReturnTotals } = require('./base-review.presenter.js') @@ -45,7 +46,7 @@ function go (reviewChargeElement, elementIndex) { financialPeriod: formatFinancialYear( reviewChargeReference.reviewChargeVersion.reviewLicence.billRun.toFinancialYearEnding ), - issues: issues.length > 0 ? issues.split(', ') : [], + issues: formatIssues(issues), licenceId: reviewChargeReference.reviewChargeVersion.reviewLicence.licenceId, matchedReturns: _matchedReturns(reviewChargeElement.reviewReturns), reviewChargeElementId, @@ -62,7 +63,7 @@ function _matchedReturns (reviewReturns) { return { abstractionPeriod: formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth), description, - issues: issues.length > 0 ? issues.split(', ') : [''], + issues: formatIssues(issues), purpose: purposes[0].tertiary.description, reference: returnReference, returnId, diff --git a/app/presenters/bill-runs/review/review-licence.presenter.js b/app/presenters/bill-runs/review/review-licence.presenter.js index fafec8b36f..bcd06cc9ae 100644 --- a/app/presenters/bill-runs/review/review-licence.presenter.js +++ b/app/presenters/bill-runs/review/review-licence.presenter.js @@ -11,6 +11,7 @@ const { determineReturnLink, formatChargePeriod, formatChargePeriods, + formatIssues, formatReturnStatus, formatReturnTotals } = require('./base-review.presenter.js') @@ -79,7 +80,7 @@ function _chargeElements (reviewChargeElements, chargePeriod) { elementIndex: index + 1, status, id, - issues: issues.length > 0 ? issues.split(', ') : [''], + issues: formatIssues(issues), purpose: chargeElement.purpose.description } }) @@ -178,7 +179,7 @@ function _formatReviewReturns (reviewReturns) { const formattedReviewReturn = { abstractionPeriod: formatAbstractionPeriod(periodStartDay, periodStartMonth, periodEndDay, periodEndMonth), description, - issues: issues.length > 0 ? issues.split(', ') : [''], + issues: formatIssues(issues), purpose: purposes[0].tertiary.description, reference: returnReference, returnId, diff --git a/test/support/helpers/review-charge-element.helper.js b/test/support/helpers/review-charge-element.helper.js index 90554b29bc..4ff40b608d 100644 --- a/test/support/helpers/review-charge-element.helper.js +++ b/test/support/helpers/review-charge-element.helper.js @@ -16,7 +16,7 @@ const ReviewChargeElementModel = require('../../../app/models/review-charge-elem * - `reviewChargeReferenceId` - [random UUID] * - `allocated` - 0 * - `chargeDatesOverlap` - false - * - `issues` - null + * - `issues` - '' * - `status` - ready * - `amendedAllocated` - 0 * @@ -48,7 +48,7 @@ function defaults (data = {}) { reviewChargeReferenceId: generateUUID(), allocated: 0, chargeDatesOverlap: false, - issues: null, + issues: '', status: 'ready', amendedAllocated: 0 } From e3c4368a1fd84e9035f4ac2290b6a4fae1c2e637 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 16:42:36 +0000 Subject: [PATCH 096/147] Housekeeping - missed IDs in fetch queries --- .../bill-runs/review/fetch-remove-review-licence.service.js | 1 + app/services/bill-runs/review/fetch-review-licence.service.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/services/bill-runs/review/fetch-remove-review-licence.service.js b/app/services/bill-runs/review/fetch-remove-review-licence.service.js index ebc56216de..7b85d9675d 100644 --- a/app/services/bill-runs/review/fetch-remove-review-licence.service.js +++ b/app/services/bill-runs/review/fetch-remove-review-licence.service.js @@ -40,6 +40,7 @@ async function _fetch (reviewLicenceId) { .withGraphFetched('region') .modifyGraph('region', (builder) => { builder.select([ + 'id', 'displayName' ]) }) diff --git a/app/services/bill-runs/review/fetch-review-licence.service.js b/app/services/bill-runs/review/fetch-review-licence.service.js index 4dd3c8aa8a..6b3d34642c 100644 --- a/app/services/bill-runs/review/fetch-review-licence.service.js +++ b/app/services/bill-runs/review/fetch-review-licence.service.js @@ -43,6 +43,7 @@ async function _fetch (reviewLicenceId) { .withGraphFetched('region') .modifyGraph('region', (builder) => { builder.select([ + 'id', 'displayName' ]) }) @@ -69,6 +70,7 @@ async function _fetch (reviewLicenceId) { .modifyGraph('returnLog', (builder) => { builder .select([ + 'id', ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), ref('metadata:nald.periodStartMonth').castInt().as('periodStartMonth'), ref('metadata:nald.periodEndDay').castInt().as('periodEndDay'), From 818b6da1f925fdf760ddd108a6a2d2efe32e5d20 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 18:01:08 +0000 Subject: [PATCH 097/147] Fix FetchReviewLicenceService - Remove unnecessary order by - Fix incorrect field position - Fix wrong modifyGraph reference --- .../bill-runs/review/fetch-review-licence.service.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/services/bill-runs/review/fetch-review-licence.service.js b/app/services/bill-runs/review/fetch-review-licence.service.js index 6b3d34642c..78c86f8731 100644 --- a/app/services/bill-runs/review/fetch-review-licence.service.js +++ b/app/services/bill-runs/review/fetch-review-licence.service.js @@ -78,12 +78,11 @@ async function _fetch (reviewLicenceId) { ]) }) .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewReturns', (builder) => { + .modifyGraph('reviewChargeElements', (builder) => { builder .select([ - 'id' + 'reviewChargeElements.id' ]) - .orderBy('startDate', 'asc') }) }) .withGraphFetched('reviewChargeVersions') @@ -136,12 +135,12 @@ async function _fetch (reviewLicenceId) { builder .select([ 'id', - 'description', 'abstractionPeriodStartDay', 'abstractionPeriodStartMonth', 'abstractionPeriodEndDay', 'abstractionPeriodEndMonth', - 'authorisedAnnualQuantity' + 'authorisedAnnualQuantity', + 'description' ]) .withGraphFetched('purpose') .modifyGraph('purpose', (builder) => { From a8c2b1271472e8d5363f7116c7b70e3277034006 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 19:17:28 +0000 Subject: [PATCH 098/147] Housekeeping - Delete unused field in fetch --- .../bill-runs/review/fetch-review-charge-reference.service.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/bill-runs/review/fetch-review-charge-reference.service.js b/app/services/bill-runs/review/fetch-review-charge-reference.service.js index a2ad96e105..5fecb7ce45 100644 --- a/app/services/bill-runs/review/fetch-review-charge-reference.service.js +++ b/app/services/bill-runs/review/fetch-review-charge-reference.service.js @@ -85,7 +85,6 @@ async function _fetch (reviewChargeReferenceId) { .select([ 'id', 'volume', - 'chargeCategoryId', 'loss', ref('chargeReferences.additionalCharges:supportedSource.name').castText().as('supportedSourceName'), ref('chargeReferences.additionalCharges:isSupplyPublicWater').castText().as('waterCompanyCharge') From a3dcee4a2249803c2fe2fa958fca382b2f0128db Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 19:17:57 +0000 Subject: [PATCH 099/147] Housekeeping - Correct typo in docs --- test/support/helpers/address.helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/helpers/address.helper.js b/test/support/helpers/address.helper.js index 0f4bb90209..e6b80ea501 100644 --- a/test/support/helpers/address.helper.js +++ b/test/support/helpers/address.helper.js @@ -15,7 +15,7 @@ const { randomInteger } = require('../general.js') * - `address1` - ENVIRONMENT AGENCY * - `address2` - HORIZON HOUSE * - `address3` - DEANERY ROAD - * - `town` - BRISTOL + * - `address4` - BRISTOL * - `postcode` - BS1 5AH * - `country` - United Kingdom * - `dataSource` - wrls From c2b65f2886053c3d305d531dc324cbe51587a3c6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 19:18:23 +0000 Subject: [PATCH 100/147] Housekeeping - Correct mismatch in docs --- test/support/helpers/review-licence.helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/helpers/review-licence.helper.js b/test/support/helpers/review-licence.helper.js index bd493d8c1a..7b2548b771 100644 --- a/test/support/helpers/review-licence.helper.js +++ b/test/support/helpers/review-licence.helper.js @@ -16,7 +16,7 @@ const ReviewLicenceModel = require('../../../app/models/review-licence.model.js' * - `billRunId` - [random UUID] * - `licenceId` - [random UUID] * - `licenceRef` - [randomly generated - 01/123] - * - `licenceHolder` - A LicenceHolder + * - `licenceHolder` - Licence Holder Ltd * - `progress` - false * - `status` - ready * - `issues` - null From c3f8565a6a6c0fe6cc1a0e1e2db7431a861b2c04 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 19:21:34 +0000 Subject: [PATCH 101/147] Housekeeping - Correct issues being null in helper --- test/support/helpers/review-licence.helper.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/support/helpers/review-licence.helper.js b/test/support/helpers/review-licence.helper.js index 7b2548b771..d5c7b4717b 100644 --- a/test/support/helpers/review-licence.helper.js +++ b/test/support/helpers/review-licence.helper.js @@ -19,7 +19,7 @@ const ReviewLicenceModel = require('../../../app/models/review-licence.model.js' * - `licenceHolder` - Licence Holder Ltd * - `progress` - false * - `status` - ready - * - `issues` - null + * - `issues` - '' * * @param {object} [data] - Any data you want to use instead of the defaults used here or in the database * @@ -51,7 +51,7 @@ function defaults (data = {}) { licenceHolder: 'Licence Holder Ltd', progress: false, status: 'ready', - issues: null + issues: '' } return { From 5ab5cee2bbae01d950b1e48a978ee2008e0b0497 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 19:24:02 +0000 Subject: [PATCH 102/147] Housekeeping - Correct wrong name in JSDocs --- app/validators/bill-runs/review/authorised.validator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/validators/bill-runs/review/authorised.validator.js b/app/validators/bill-runs/review/authorised.validator.js index d47994a724..2a40c10e96 100644 --- a/app/validators/bill-runs/review/authorised.validator.js +++ b/app/validators/bill-runs/review/authorised.validator.js @@ -2,7 +2,7 @@ /** * Validates data submitted for the review charge reference authorised page - * @module FactorsValidator + * @module AuthorisedValidator */ const Joi = require('joi') From dfe75f1939dbe57401943941d84da39c0cdcb893 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:20:22 +0000 Subject: [PATCH 103/147] Add fixture We have a number of large data objects we need to generate in order to test the various presenters and services used by bill runs review. Typical we declare these in the test files. But in this case we need to reuse the same data objects ion a number of places. So, we are taking advantage of the concept of a fixture file. We can declare these large objects in one place, and then grab them within the unit tests. We do them as functions rather than static objects to avoid any issues with one test updating the object causing later tests to fail. Each time a test calls a fixture function, it'll get its own copy of the data object. --- test/fixtures/bill-runs-review.fixture.js | 339 ++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 test/fixtures/bill-runs-review.fixture.js diff --git a/test/fixtures/bill-runs-review.fixture.js b/test/fixtures/bill-runs-review.fixture.js new file mode 100644 index 0000000000..d8151ff39b --- /dev/null +++ b/test/fixtures/bill-runs-review.fixture.js @@ -0,0 +1,339 @@ +'use strict' + +const BillingAccountModel = require('../../app/models/billing-account.model.js') + +/** + * Represents a complete response from `FetchRemoveReviewLicenceService` + * + * @returns {object} + */ +function removeReviewLicence () { + return { + id: 'bb779166-0576-4581-b504-edbc0227d763', + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + licenceRef: '1/11/11/*11/1111', + billRun: { + id: '287aeb25-cf11-429d-8c6f-f98f06db021d', + billRunNumber: 10001, + createdAt: new Date('2024-10-22'), + status: 'review', + toFinancialYearEnding: 2024, + region: { + id: '4ccf3c5b-ab4e-48e1-afa8-3b18b5d07fab', + displayName: 'Test Region' + } + } + } +} + +/** + * Represents a complete response from `FetchReviewChargeElementService` + * + * @returns {object} + */ +function reviewChargeElement () { + return { + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + amendedAllocated: 0, + issues: 'Aggregate', + status: 'review', + chargeElement: { + id: 'dd050414-9c58-4a40-a114-77853f2fe6d2', + abstractionPeriodStartDay: 1, + abstractionPeriodStartMonth: 4, + abstractionPeriodEndDay: 30, + abstractionPeriodEndMonth: 9, + authorisedAnnualQuantity: 9.092, + description: 'Spray Irrigation - Direct' + }, + reviewChargeReference: { + id: '6c70461b-3f83-47b1-9538-8305e82b34eb', + amendedAuthorisedVolume: 9.092, + reviewChargeElements: [ + { id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' } + ], + reviewChargeVersion: { + id: 'a71c386c-d9b8-4915-a508-74fb1508c071', + chargePeriodStartDate: new Date('2023-04-01'), + chargePeriodEndDate: new Date('2024-03-31'), + reviewLicence: { + id: 'bb779166-0576-4581-b504-edbc0227d763', + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + billRun: { + id: '287aeb25-cf11-429d-8c6f-f98f06db021d', + toFinancialYearEnding: 2024 + } + } + } + }, + reviewReturns: [ + { + id: 'e3f64190-6a58-40af-8648-23c71ad1726f', + allocated: 0, + description: 'Test Road. Points 1 and 2.', + endDate: new Date('2023-10-31'), + issues: '', + quantity: 0, + purposes: [ + { + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '400', description: 'Spray Irrigation - Direct' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + } + ], + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnReference: '11142960', + returnStatus: 'completed', + startDate: new Date('2022-11-01'), + underQuery: false, + returnLog: { + id: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + periodStartDay: 1, + periodStartMonth: 4, + periodEndDay: 30, + periodEndMonth: 9 + } + } + ] + } +} + +/** + * Represents a complete response from `FetchReviewChargeReferenceService` + * + * @returns {object} + */ +function reviewChargeReference () { + return { + id: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + abatementAgreement: 1, + aggregate: 0.333333333, + amendedAggregate: 0.333333333, + amendedAuthorisedVolume: 9.092, + amendedChargeAdjustment: 1, + canalAndRiverTrustAgreement: false, + chargeAdjustment: 1, + twoPartTariffAgreement: true, + winterDiscount: false, + reviewChargeVersion: { + id: 'a71c386c-d9b8-4915-a508-74fb1508c071', + chargePeriodStartDate: new Date('2023-04-01'), + chargePeriodEndDate: new Date('2024-03-31'), + reviewLicence: { + id: 'bb779166-0576-4581-b504-edbc0227d763', + billRun: { + id: '287aeb25-cf11-429d-8c6f-f98f06db021d', + toFinancialYearEnding: 2024 + }, + licence: { + id: '32416c67-f755-4c3f-8816-ecde0ee596bd', + waterUndertaker: false + } + } + }, + reviewChargeElements: [ + { + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + amendedAllocated: 0 + } + ], + chargeReference: { + id: 'fc493c81-5003-4dc0-9d48-4b5bf4af9c1e', + volume: 9.092, + chargeCategoryId: '9f194aa2-562d-4e89-a0ce-d4a31b5833b1', + loss: 'high', + supportedSourceName: null, + waterCompanyCharge: null, + chargeCategory: { + id: '9f194aa2-562d-4e89-a0ce-d4a31b5833b1', + reference: '4.6.5', + shortDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model' + } + } + } +} + +/** + * Represents a complete response from `FetchReviewLicenceService` + * + * @returns {object} + */ +function reviewLicence () { + return { + id: 'bb779166-0576-4581-b504-edbc0227d763', + billRunId: '287aeb25-cf11-429d-8c6f-f98f06db021d', + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + licenceRef: '1/11/11/*11/1111', + licenceHolder: 'Licence Holder Ltd', + status: 'review', + progress: false, + billRun: { + id: '287aeb25-cf11-429d-8c6f-f98f06db021d', + toFinancialYearEnding: 2024, + region: { + id: '4ccf3c5b-ab4e-48e1-afa8-3b18b5d07fab', + displayName: 'South West' + } + }, + reviewReturns: [ + { + id: 'e3f64190-6a58-40af-8648-23c71ad1726f', + allocated: 0, + description: 'Test Road. Points 1 and 2.', + endDate: new Date('2023-10-31'), + issues: '', + quantity: 0, + purposes: [ + { + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '400', description: 'Spray Irrigation - Direct' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + } + ], + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnReference: '11142960', + returnStatus: 'completed', + startDate: new Date('2022-11-01'), + underQuery: false, + returnLog: { + id: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + periodStartDay: 1, + periodStartMonth: 4, + periodEndDay: 30, + periodEndMonth: 9 + }, + reviewChargeElements: [ + { + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + reviewChargeReferenceId: '6c70461b-3f83-47b1-9538-8305e82b34eb', + chargeElementId: 'dd050414-9c58-4a40-a114-77853f2fe6d2', + allocated: 0, + chargeDatesOverlap: false, + issues: 'Aggregate', + status: 'review', + createdAt: new Date('2024-10-22'), + updatedAt: new Date('2024-10-22'), + amendedAllocated: 0 + } + ] + }, + { + id: '4864f643-5c16-5ca9-8512-f63e1d4e58be', + allocated: 0, + description: 'Lost Road. Points 1 and 2.', + endDate: new Date('2023-10-31'), + issues: '', + quantity: 0, + purposes: [ + { + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '420', description: 'Spray Irrigation - Storage' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + } + ], + returnId: 'v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnReference: '11142961', + returnStatus: 'completed', + startDate: new Date('2022-11-01'), + underQuery: false, + returnLog: { + id: 'v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + periodStartDay: 1, + periodStartMonth: 4, + periodEndDay: 30, + periodEndMonth: 9 + }, + reviewChargeElements: [] + } + ], + reviewChargeVersions: [ + { + id: 'a71c386c-d9b8-4915-a508-74fb1508c071', + chargePeriodEndDate: new Date('2024-03-31'), + chargePeriodStartDate: new Date('2023-04-01'), + reviewChargeReferences: [ + { + id: '6c70461b-3f83-47b1-9538-8305e82b34eb', + aggregate: 0.333333333, + amendedAuthorisedVolume: 9.092, + chargeAdjustment: 1, + chargeReference: { + id: 'fc493c81-5003-4dc0-9d48-4b5bf4af9c1e', + chargeCategory: { + id: '9f194aa2-562d-4e89-a0ce-d4a31b5833b1', + reference: '4.6.5', + shortDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model' + } + }, + reviewChargeElements: [ + { + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + amendedAllocated: 0, + issues: 'Aggregate', + status: 'review', + chargeElement: { + id: 'dd050414-9c58-4a40-a114-77853f2fe6d2', + description: 'Spray Irrigation - Direct', + abstractionPeriodStartDay: 1, + abstractionPeriodStartMonth: 4, + abstractionPeriodEndDay: 30, + abstractionPeriodEndMonth: 9, + authorisedAnnualQuantity: 9.092, + purpose: { + id: '4ad11971-be6a-4da5-af04-563c76205b0e', + description: 'Spray Irrigation - Direct' + } + }, + reviewReturns: [ + { + id: 'e3f64190-6a58-40af-8648-23c71ad1726f', + quantity: 0, + returnReference: '10030495', + returnStatus: 'completed' + } + ] + } + ] + } + ], + chargeVersion: { + id: '281a6820-4074-4ba8-92f1-7d1bfe63b426', + billingAccount: BillingAccountModel.fromJson({ + id: 'f041c128-bb4d-4f67-8f97-e33d71d50842', + accountNumber: 'E99999999A', + company: { + id: '838c9770-87a8-47b6-89a4-549c8e08ed2f', + name: 'Mr B Blobby Ltd', + type: 'organisation' + }, + billingAccountAddresses: [ + { + id: 'c95c0144-db2d-48fc-9bc0-e60126f762db', + company: null, + contact: null, + address: { + id: 'da502c5b-0214-49d5-9125-83c4ea1359e5', + address1: 'C/O Noel Edmonds', + address2: 'Crinkley Bottom', + address3: 'Cricket St Thomas', + address4: null, + address5: null, + address6: 'Somerset', + postcode: 'TA20 1KL', + country: 'United Kingdom' + } + } + ] + }) + } + } + ] + } +} + +module.exports = { + removeReviewLicence, + reviewChargeElement, + reviewChargeReference, + reviewLicence +} From cd99b63647da3e56e0d2a06a455883454fc62075 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:24:03 +0000 Subject: [PATCH 104/147] Move controller tests and update/tidy --- .../bill-runs-review.controller.test.js | 692 ++++++++++++++++-- test/controllers/bill-runs.controller.test.js | 580 +-------------- 2 files changed, 633 insertions(+), 639 deletions(-) diff --git a/test/controllers/bill-runs-review.controller.test.js b/test/controllers/bill-runs-review.controller.test.js index 4aaec29d24..99789c2898 100644 --- a/test/controllers/bill-runs-review.controller.test.js +++ b/test/controllers/bill-runs-review.controller.test.js @@ -5,26 +5,43 @@ const Lab = require('@hapi/lab') const Code = require('@hapi/code') const Sinon = require('sinon') -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { describe, it, before, beforeEach, afterEach } = exports.lab = Lab.script() const { expect } = Code // Test helpers const { postRequestOptions } = require('../support/general.js') // Things we need to stub +const AuthorisedService = require('../../app/services/bill-runs/review/authorised.service.js') +const EditService = require('../../app/services/bill-runs/review/edit.service.js') +const FactorsService = require('../../app/services/bill-runs/review/factors.service.js') +const PreviewService = require('../../app/services/bill-runs/review/preview.service.js') const ReviewBillRunService = require('../../app/services/bill-runs/review/review-bill-run.service.js') +const ReviewChargeElementService = require('../../app/services/bill-runs/review/review-charge-element.service.js') +const ReviewChargeReferenceService = require('../../app/services/bill-runs/review/review-charge-reference.service.js') +const ReviewLicenceService = require('../../app/services/bill-runs/review/review-licence.service.js') +const SubmitAuthorisedService = require('../../app/services/bill-runs/review/submit-authorised.service.js') +const SubmitEditService = require('../../app/services/bill-runs/review/submit-edit.service.js') +const SubmitFactorsService = require('../../app/services/bill-runs/review/submit-factors.service.js') +const SubmitRemoveService = require('../../app/services/bill-runs/review/submit-remove.service.js') const SubmitReviewBillRunService = require('../../app/services/bill-runs/review/submit-review-bill-run.service.js') +const RemoveService = require('../../app/services/bill-runs/review/remove.service.js') // For running our service const { init } = require('../../app/server.js') describe('Bill Runs Review controller', () => { let options + let path let server - // Create server before each test - beforeEach(async () => { + // Create server before running the tests + before(async () => { server = await init() + }) + + beforeEach(async () => { + // server = await init() // We silence any calls to server.logger.error made in the plugin to try and keep the test output as clean as // possible @@ -38,74 +55,649 @@ describe('Bill Runs Review controller', () => { Sinon.restore() }) - describe('/bill-runs/{id}/review', () => { + describe('/bill-runs/review/{billRunId}', () => { + beforeEach(() => { + path = '97db1a27-8308-4aba-b463-8a6af2558b28' + }) + describe('GET', () => { - let ReviewBillRunServiceStub + beforeEach(() => { + Sinon.stub(ReviewBillRunService, 'go').resolves({ + region: 'Southern (Test replica)', + status: 'review', + dateCreated: '6 November 2023', + financialYear: '2021 to 2022', + billRunType: 'two-part tariff', + numberOfLicencesDisplayed: 2, + numberOfLicencesToReview: 1, + totalNumberOfLicences: 2, + preparedLicences: [ + { + licenceId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', + licenceRef: '1/11/11/*1/1111', + licenceHolder: 'Big Farm Ltd', + status: 'review', + issue: 'Multiple Issues' + }, + { + licenceId: '9442527a-64f3-471a-a3e4-fa0683a3d505', + licenceRef: '2/22/22/*2/2222', + licenceHolder: 'Small Farm Ltd', + status: 'ready', + issue: 'Multiple Issues' + } + ], + filter: { + issues: undefined, + licenceHolder: undefined, + licenceStatus: undefined, + openFilter: false + } + }) + }) - describe('when a request is valid with no pagination', () => { - beforeEach(() => { - options = _getRequestOptions() - ReviewBillRunServiceStub = Sinon.stub(ReviewBillRunService, 'go').resolves(_reviewBillRunData()) + describe('when a request is valid', () => { + describe('with no pagination', () => { + beforeEach(() => { + options = _getRequestOptions(path) + }) + + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Southern (Test replica) two-part tariff bill run') + expect(response.payload).to.contain('Showing all 2 licences') + }) + }) + + describe('with pagination', () => { + beforeEach(() => { + options = _getRequestOptions(path, 'page=2') + }) + + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Southern (Test replica) two-part tariff bill run') + expect(response.payload).to.contain('Showing all 2 licences') + }) + }) + }) + }) + + describe('POST', () => { + beforeEach(async () => { + options = _postRequestOptions(path) + + Sinon.stub(SubmitReviewBillRunService, 'go').resolves() + }) + + describe('when a request is valid', () => { + it('redirects to the review licences page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal( + '/system/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28' + ) }) + }) + }) + }) + + describe('/bill-runs/review/charge-element/{reviewChargeElementId}/{elementIndex}', () => { + beforeEach(() => { + path = 'charge-element/a1840523-a04c-4c64-bff7-4a515e8ba1c1/1' + }) + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + + Sinon.stub(ReviewChargeElementService, 'go').resolves({ + authorisedVolume: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementCount: 1, + elementIndex: '1', + financialPeriod: '2023 to 2024', + issues: ['Aggregate'], + licenceId: '7c8a248c-b71e-463c-bea8-bc5e0a5d95e2', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Borehole in top field', + issues: [Array], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/10/*S/0084:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/10/*S/0084:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + reviewLicenceId: 'deaffa60-6488-4e54-a402-485d43aca1af', + status: 'review' + }) + }) + + describe('when a request is valid', () => { it('returns a 200 response', async () => { const response = await server.inject(options) - const ReviewBillRunServiceArgs = ReviewBillRunServiceStub.args[0] expect(response.statusCode).to.equal(200) - expect(ReviewBillRunServiceArgs[0]).to.equal('97db1a27-8308-4aba-b463-8a6af2558b28') - expect(ReviewBillRunServiceArgs[1]).to.equal(undefined) - expect(response.payload).to.contain('two-part tariff') - expect(response.payload).to.contain('Southern (Test replica)') - expect(response.payload).to.contain('Showing all 2 licences') + expect(response.payload).to.contain('Spray Irrigation - Direct') + expect(response.payload).to.contain('Element 1 of 1') + expect(response.payload).to.contain('Matched returns') }) }) + }) + }) - describe('when a request is valid with pagination', () => { - beforeEach(() => { - options = _getRequestOptions(null, 'page=2') - ReviewBillRunServiceStub = Sinon.stub(ReviewBillRunService, 'go').resolves(_reviewBillRunData()) + describe('/bill-runs/review/charge-element/{reviewChargeElementId}/{elementIndex}/edit', () => { + beforeEach(() => { + path = 'charge-element/a1840523-a04c-4c64-bff7-4a515e8ba1c1/1/edit' + }) + + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + }) + + describe('when a request is valid', () => { + beforeEach(async () => { + Sinon.stub(EditService, 'go').resolves({ + pageTitle: 'Set the billable returns quantity for this bill run', + authorisedQuantity: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementIndex: '1', + financialPeriod: '2023 to 2024', + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' + }) }) it('returns a 200 response', async () => { const response = await server.inject(options) - const ReviewBillRunServiceArgs = ReviewBillRunServiceStub.args[0] expect(response.statusCode).to.equal(200) - expect(ReviewBillRunServiceArgs[0]).to.equal('97db1a27-8308-4aba-b463-8a6af2558b28') - expect(ReviewBillRunServiceArgs[1]).to.equal('2') - expect(response.payload).to.contain('two-part tariff') - expect(response.payload).to.contain('Southern (Test replica)') - expect(response.payload).to.contain('Showing all 2 licences') + expect(response.payload).to.contain('Set the billable returns quantity for this bill run') + expect(response.payload).to.contain('Spray Irrigation - Direct') + expect(response.payload).to.contain('Billable returns') }) }) }) describe('POST', () => { beforeEach(async () => { - options = postRequestOptions('/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28') + options = _postRequestOptions(path) }) describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(SubmitReviewBillRunService, 'go').resolves() + beforeEach(async () => { + Sinon.stub(SubmitEditService, 'go').resolves({}) }) - it('redirects to the review licences page', async () => { + it('redirects to the Review charge element page', async () => { const response = await server.inject(options) expect(response.statusCode).to.equal(302) expect(response.headers.location).to.equal( - '/system/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28' + '/system/bill-runs/review/charge-element/a1840523-a04c-4c64-bff7-4a515e8ba1c1/1' ) }) }) + + describe('when a request is invalid', () => { + beforeEach(async () => { + Sinon.stub(SubmitEditService, 'go').resolves({ + customQuantitySelected: false, + customQuantityValue: undefined, + error: { + errorList: [{ href: '#quantityOptions-error', text: 'Select the billable quantity' }], + quantityOptionsErrorMessage: { text: 'Select the billable quantity' } + }, + pageTitle: 'Set the billable returns quantity for this bill run', + authorisedQuantity: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementIndex: '1', + financialPeriod: '2023 to 2024', + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' + }) + }) + + it('re-renders the page with an error message', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Set the billable returns quantity for this bill ru') + expect(response.payload).to.contain('There is a problem') + expect(response.payload).to.contain('Select the billable quantity') + }) + }) + }) + }) + + describe('/bill-runs/review/charge-reference/{reviewChargeReferenceId}', () => { + beforeEach(() => { + path = 'charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d' + }) + + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + + Sinon.stub(ReviewChargeReferenceService, 'go').resolves({ + additionalCharges: '', + adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + amendedAuthorisedVolume: 9.092, + canAmend: true, + chargeCategory: '4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '7c09753d-f606-4deb-a929-4bc8aa7acb8d', + reviewLicenceId: 'deaffa60-6488-4e54-a402-485d43aca1af', + totalBillableReturns: 0 + }) + }) + + describe('when a request is valid', () => { + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Charge reference 4.6.5') + expect(response.payload).to.contain('High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model') + expect(response.payload).to.contain('Reference details') + }) + }) + }) + }) + + describe('/bill-runs/review/charge-reference/{reviewChargeReferenceId}/authorised', () => { + beforeEach(() => { + path = 'charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d/authorised' + }) + + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + }) + + describe('when a request is valid', () => { + beforeEach(async () => { + Sinon.stub(AuthorisedService, 'go').resolves({ + amendedAuthorisedVolume: 9.092, + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '7c09753d-f606-4deb-a929-4bc8aa7acb8d', + totalBillableReturns: 0, + pageTitle: 'Set the authorised volume' + }) + }) + + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Set the authorised volume') + expect(response.payload).to.contain('High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model') + expect(response.payload).to.contain('Total billable returns') + }) + }) + }) + + describe('POST', () => { + beforeEach(async () => { + options = _postRequestOptions(path) + }) + + describe('when a request is valid', () => { + beforeEach(async () => { + Sinon.stub(SubmitAuthorisedService, 'go').resolves({}) + }) + + it('redirects to the Review charge reference page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal( + '/system/bill-runs/review/charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d' + ) + }) + }) + + describe('when a request is invalid', () => { + beforeEach(async () => { + Sinon.stub(SubmitAuthorisedService, 'go').resolves({ + amendedAuthorisedVolume: 'foo', + error: { text: 'The authorised volume must be a number' }, + pageTitle: 'Set the authorised volume', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '7c09753d-f606-4deb-a929-4bc8aa7acb8d', + totalBillableReturns: 0 + }) + }) + + it('re-renders the page with an error message', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Set the authorised volume') + expect(response.payload).to.contain('There is a problem') + expect(response.payload).to.contain('The authorised volume must be a number') + }) + }) + }) + }) + + describe('/bill-runs/review/charge-reference/{reviewChargeReferenceId}/factors', () => { + beforeEach(() => { + path = 'charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d/factors' + }) + + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + }) + + describe('when a request is valid', () => { + beforeEach(async () => { + Sinon.stub(FactorsService, 'go').resolves({ + amendedAggregate: 0.333333333, + amendedChargeAdjustment: 1, + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + otherAdjustments: ['Two part tariff agreement'], + reviewChargeReferenceId: '7c09753d-f606-4deb-a929-4bc8aa7acb8d', + pageTitle: 'Set the adjustment factors' + }) + }) + + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Set the adjustment factors') + expect(response.payload).to.contain('High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model') + }) + }) + }) + + describe('POST', () => { + beforeEach(async () => { + options = _postRequestOptions(path) + }) + + describe('when a request is valid', () => { + beforeEach(async () => { + Sinon.stub(SubmitFactorsService, 'go').resolves({}) + }) + + it('redirects to the Review charge reference page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal( + '/system/bill-runs/review/charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d' + ) + }) + }) + + describe('when a request is invalid', () => { + beforeEach(async () => { + Sinon.stub(SubmitFactorsService, 'go').resolves({ + amendedAggregate: 'foo', + amendedChargeAdjustment: '1', + error: { + errorList: [{ href: '#amended-aggregate', text: 'The aggregate factor must be a number' }], + amendedAggregate: { message: 'The aggregate factor must be a number' } + }, + pageTitle: 'Set the adjustment factors', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + otherAdjustments: ['Two part tariff agreement'], + reviewChargeReferenceId: '7c09753d-f606-4deb-a929-4bc8aa7acb8d' + }) + }) + + it('re-renders the page with an error message', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('Set the adjustment factors') + expect(response.payload).to.contain('There is a problem') + expect(response.payload).to.contain('The aggregate factor must be a number') + }) + }) + }) + }) + + describe('/bill-runs/review/charge-reference/{reviewChargeReferenceId}/preview', () => { + beforeEach(() => { + path = 'charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d/preview' + }) + + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + + Sinon.stub(PreviewService, 'go').resolves() + }) + + describe('when a request is valid', () => { + it('redirects to the Review charge reference page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal( + '/system/bill-runs/review/charge-reference/7c09753d-f606-4deb-a929-4bc8aa7acb8d' + ) + }) + }) + }) + }) + + describe('/bill-runs/review/licence/{reviewLicenceId}', () => { + beforeEach(() => { + path = 'licence/deaffa60-6488-4e54-a402-485d43aca1af' + }) + + describe('GET', () => { + beforeEach(async () => { + options = _getRequestOptions(path) + + Sinon.stub(ReviewLicenceService, 'go').resolves({ + billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', + chargeVersions: [{ + billingAccountDetails: [{ + billingAccountId: 'ee3f5562-26ad-4d58-9b59-5c388a13d7d0', + accountNumber: 'E99999999A', + accountName: 'Mr B Blobby', + contactName: null, + addressLines: [ + 'C/O Noel Edmonds', + 'Crinkley Bottom', + 'Cricket St Thomas', + 'Somerset', + 'TA20 1KL' + ] + }], + chargePeriod: '1 April 2023 to 31 March 2024', + chargeReferences: [{ + billableReturnsWarning: false, + chargeCategory: 'Charge reference 4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + id: '7c09753d-f606-4deb-a929-4bc8aa7acb8d', + chargeElements: [{ + billableReturns: '0 ML / 9.092 ML', + chargePeriods: ['1 April 2023 to 30 September 2023'], + returnVolumes: ['0 ML (11142960)'], + description: 'Spray Irrigation - Direct', + elementCount: 1, + elementIndex: 1, + status: 'review', + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + issues: ['Aggregate'], + purpose: 'Spray Irrigation - Direct' + }], + chargeReferenceLinkTitle: 'Change details', + totalBillableReturns: '0 ML / 9.092 ML' + }], + description: '1 charge reference with 1 two-part tariff charge element', + financialPeriod: '2023 to 2024' + }], + elementsInReview: true, + licenceHolder: 'Licence Holder Ltd', + licenceId: '7c8a248c-b71e-463c-bea8-bc5e0a5d95e2', + licenceRef: '1/11/10/*S/0084', + matchedReturns: [{ + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: ['Returns received late'], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/10/*S/0084:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/10/*S/0084:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + }], + pageTitle: 'Licence 13/43/028/S/045', + progress: false, + region: 'Southern (Test replica)', + reviewLicenceId: 'deaffa60-6488-4e54-a402-485d43aca1af', + status: 'review', + unmatchedReturns: [] + }) + }) + + describe('when a request is valid', () => { + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('1/11/10/*S/0084') + expect(response.payload).to.contain('two-part tariff') + expect(response.payload).to.contain('Test Road. Points 1 and 2.') + }) + }) + }) + + describe('POST', () => { + beforeEach(async () => { + options = _postRequestOptions(path) + }) + + describe('when a request is valid', () => { + it('redirects to the Review licence page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal('/system/bill-runs/review/licence/deaffa60-6488-4e54-a402-485d43aca1af') + }) + }) + }) + }) + + describe('/bill-runs/review/licence/{reviewLicenceId}/remove', () => { + beforeEach(() => { + path = 'licence/deaffa60-6488-4e54-a402-485d43aca1af/remove' + }) + + describe('GET', () => { + beforeEach(() => { + options = _getRequestOptions(path) + + Sinon.stub(RemoveService, 'go').resolves({ + billRunNumber: 12345, + billRunStatus: 'review', + dateCreated: '3 May 2024', + financialYearPeriod: '2022 to 2023', + licenceRef: '01/123/ABC', + pageTitle: "You're about to remove 01/123/ABC from the bill run", + region: 'Test region', + reviewLicenceId: '70703eac-cab6-4eff-906d-2832fe27b646' + }) + }) + + describe('when a request is valid', () => { + it('returns a 200 response', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(200) + expect(response.payload).to.contain('You're about to remove 01/123/ABC from the bill run') + }) + }) + }) + + describe('POST', () => { + beforeEach(() => { + options = _postRequestOptions(path) + }) + + describe('when there are still licences to review in the bill run', () => { + beforeEach(() => { + options = _postRequestOptions(path) + + Sinon.stub(SubmitRemoveService, 'go').resolves({ + billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', + empty: false + }) + }) + + describe('when a request is valid', () => { + it('redirects to the Review bill run page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal('/system/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28') + }) + }) + }) + + describe('when there are no licences left to review in the bill run', () => { + beforeEach(() => { + options = _postRequestOptions(path) + + Sinon.stub(SubmitRemoveService, 'go').resolves({ + billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', + empty: true + }) + }) + + describe('when a request is valid', () => { + it('redirects to the Bill runs page', async () => { + const response = await server.inject(options) + + expect(response.statusCode).to.equal(302) + expect(response.headers.location).to.equal('/system/bill-runs') + }) + }) + }) }) }) }) function _getRequestOptions (path, query = null) { - const root = '/bill-runs/review/97db1a27-8308-4aba-b463-8a6af2558b28' + const root = '/bill-runs/review' const rootPath = path ? `${root}/${path}` : root const url = query ? `${rootPath}?${query}` : rootPath @@ -119,37 +711,9 @@ function _getRequestOptions (path, query = null) { } } -function _reviewBillRunData () { - return { - region: 'Southern (Test replica)', - status: 'review', - dateCreated: '6 November 2023', - financialYear: '2021 to 2022', - billRunType: 'two-part tariff', - numberOfLicencesDisplayed: 2, - numberOfLicencesToReview: 1, - totalNumberOfLicences: 2, - preparedLicences: [ - { - licenceId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - licenceRef: '1/11/11/*1/1111', - licenceHolder: 'Big Farm Ltd', - status: 'review', - issue: 'Multiple Issues' - }, - { - licenceId: '9442527a-64f3-471a-a3e4-fa0683a3d505', - licenceRef: '2/22/22/*2/2222', - licenceHolder: 'Small Farm Ltd', - status: 'ready', - issue: 'Multiple Issues' - } - ], - filter: { - issues: undefined, - licenceHolder: undefined, - licenceStatus: undefined, - openFilter: false - } - } +function _postRequestOptions (path) { + const root = '/bill-runs/review' + const rootPath = path ? `${root}/${path}` : root + + return postRequestOptions(rootPath) } diff --git a/test/controllers/bill-runs.controller.test.js b/test/controllers/bill-runs.controller.test.js index 4d687e16b9..34c6be786a 100644 --- a/test/controllers/bill-runs.controller.test.js +++ b/test/controllers/bill-runs.controller.test.js @@ -5,32 +5,19 @@ const Lab = require('@hapi/lab') const Code = require('@hapi/code') const Sinon = require('sinon') -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { describe, it, before, beforeEach, afterEach } = exports.lab = Lab.script() const { expect } = Code // Test helpers const { postRequestOptions } = require('../support/general.js') // Things we need to stub -const AmendAdjustmentFactorService = require('../../app/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js') -const AmendAuthorisedVolumeService = require('../../app/services/bill-runs/two-part-tariff/amend-authorised-volume.service.js') -const AmendBillableReturnsService = require('../../app/services/bill-runs/two-part-tariff/amend-billable-returns.service.js') const Boom = require('@hapi/boom') -const CalculateChargeService = require('../../app/services/bill-runs/two-part-tariff/calculate-charge.service.js') const CancelBillRunService = require('../../app/services/bill-runs/cancel-bill-run.service.js') -const ChargeReferenceDetailsService = require('../../app/services/bill-runs/two-part-tariff/charge-reference-details.service.js') const GenerateBillRunService = require('../../app/services/bill-runs/two-part-tariff/generate-bill-run.service.js') const IndexBillRunsService = require('../../app/services/bill-runs/index-bill-runs.service.js') -const MatchDetailsService = require('../../app/services/bill-runs/two-part-tariff/match-details.service.js') -const RemoveBillRunLicenceService = require('../../app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') -const ReviewLicenceService = require('../../app/services/bill-runs/two-part-tariff/review-licence.service.js') const SendBillRunService = require('../../app/services/bill-runs/send-bill-run.service.js') -const SubmitAmendedAdjustmentFactorService = require('../../app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js') -const SubmitAmendedAuthorisedVolumeService = require('../../app/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js') -const SubmitAmendedBillableReturnsService = require('../../app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') const SubmitCancelBillRunService = require('../../app/services/bill-runs/submit-cancel-bill-run.service.js') -const SubmitRemoveBillRunLicenceService = require('../../app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') -const SubmitReviewLicenceService = require('../../app/services/bill-runs/two-part-tariff/submit-review-licence.service.js') const SubmitSendBillRunService = require('../../app/services/bill-runs/submit-send-bill-run.service.js') const ViewBillRunService = require('../../app/services/bill-runs/view-bill-run.service.js') @@ -41,10 +28,12 @@ describe('Bill Runs controller', () => { let options let server - // Create server before each test - beforeEach(async () => { + // Create server before running the tests + before(async () => { server = await init() + }) + beforeEach(async () => { // We silence any calls to server.logger.error made in the plugin to try and keep the test output as clean as // possible Sinon.stub(server.logger, 'error') @@ -216,426 +205,6 @@ describe('Bill Runs controller', () => { }) }) - describe('/bill-runs/{id}/remove/{licenceId}', () => { - const licenceId = '949aab20-d3fc-4726-aace-6bd2def6a146' - - describe('GET /bill-runs/{id}/remove/{licenceId}', () => { - beforeEach(async () => { - options = _getRequestOptions(`remove/${licenceId}`) - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(RemoveBillRunLicenceService, 'go').resolves({ - pageTitle: "You're about to remove 01/123/ABC from the bill run", - backLink: `../review/${licenceId}`, - billRunNumber: 12345, - billRunStatus: 'review', - dateCreated: '3 May 2024', - financialYear: '2022 to 2023', - licenceRef: '01/123/ABC', - region: 'Test region' - }) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('You're about to remove 01/123/ABC from the bill run') - expect(response.payload).to.contain(`../review/${licenceId}`) - expect(response.payload).to.contain('12345') - expect(response.payload).to.contain('review') - expect(response.payload).to.contain('3 May 2024') - expect(response.payload).to.contain('2022 to 2023') - expect(response.payload).to.contain('01/123/ABC') - expect(response.payload).to.contain('Test region') - }) - }) - }) - - describe('POST /bill-runs/{id}/remove/{licenceId}', () => { - beforeEach(() => { - options = _postRequestOptions(`remove/${licenceId}`) - }) - - describe('when a request is valid and licences still remain in the bill run', () => { - beforeEach(() => { - Sinon.stub(SubmitRemoveBillRunLicenceService, 'go').resolves(false) - }) - - it('redirects to the Review licences page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal('/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review') - }) - }) - - describe('when a request is valid and NO licences remain in the bill run', () => { - beforeEach(() => { - Sinon.stub(SubmitRemoveBillRunLicenceService, 'go').resolves(true) - }) - - it('redirects to the Bill runs page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal('/system/bill-runs') - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}', () => { - describe('GET', () => { - beforeEach(async () => { - options = _getRequestOptions('review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e') - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(ReviewLicenceService, 'go').resolves(_licenceReviewData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('1/11/10/*S/0084') - expect(response.payload).to.contain('two-part tariff') - expect(response.payload).to.contain('Test Road. Points 1 and 2.') - }) - }) - }) - - describe('POST', () => { - beforeEach(async () => { - options = _postRequestOptions('review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e') - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(SubmitReviewLicenceService, 'go').resolves() - }) - - it('redirects to the review licence page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal('/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e') - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}', () => { - describe('GET', () => { - beforeEach(async () => { - options = _getRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2') - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(ChargeReferenceDetailsService, 'go').resolves(_chargeReferenceData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('4.6.24') - expect(response.payload).to.contain('Total billable returns') - expect(response.payload).to.contain('Aggregate factor (0.5)') - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-adjustment-factor', () => { - describe('GET', () => { - beforeEach(async () => { - options = _getRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2/amend-adjustment-factor') - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(AmendAdjustmentFactorService, 'go').resolves(_chargeReferenceData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('High loss, non-tidal, restricted water, greater than 85 up to and including 120 ML/yr') - expect(response.payload).to.contain('Set the adjustment factors') - expect(response.payload).to.contain('Aggregate factor') - }) - }) - }) - - describe('POST', () => { - beforeEach(() => { - options = _postRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2/amend-adjustment-factor' - ) - }) - - describe('when a request is valid', () => { - beforeEach(async () => { - Sinon.stub(SubmitAmendedAdjustmentFactorService, 'go').resolves(_chargeReferenceData()) - }) - - it('redirects to the charge reference details page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - ) - }) - }) - - describe('when a request is invalid', () => { - beforeEach(async () => { - Sinon.stub(SubmitAmendedAdjustmentFactorService, 'go').resolves(_chargeReferenceData(true)) - }) - - it('re-renders the page with an error message', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('The aggregate factor must be a number') - expect(response.payload).to.contain('There is a problem') - }) - }) - - describe('when the request fails', () => { - describe('because the sending service threw an error', () => { - beforeEach(async () => { - Sinon.stub(Boom, 'badImplementation').returns(new Boom.Boom('Bang', { statusCode: 500 })) - Sinon.stub(SubmitAmendedAdjustmentFactorService, 'go').rejects() - }) - - it('returns the error page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Sorry, there is a problem with the service') - }) - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}/charge-reference-details/{reviewChargeReferenceId}/amend-authorised-volume', () => { - describe('GET', () => { - beforeEach(async () => { - options = _getRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2/amend-authorised-volume') - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(AmendAuthorisedVolumeService, 'go').resolves(_authorisedVolumeData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('High loss, non-tidal, restricted water, greater than 85 up to and including 120 ML/yr') - expect(response.payload).to.contain('Set the authorised volume') - expect(response.payload).to.contain('Total billable returns') - }) - }) - }) - - describe('POST', () => { - beforeEach(() => { - options = _postRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2/amend-authorised-volume' - ) - }) - - describe('when a request is valid', () => { - beforeEach(async () => { - Sinon.stub(SubmitAmendedAuthorisedVolumeService, 'go').resolves(_chargeReferenceData()) - }) - - it('redirects to the charge reference details page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/charge-reference-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - ) - }) - }) - - describe('when a request is invalid', () => { - beforeEach(async () => { - Sinon.stub(SubmitAmendedAuthorisedVolumeService, 'go').resolves(_authorisedVolumeData(true)) - }) - - it('re-renders the page with an error message', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('The authorised volume must be a number') - expect(response.payload).to.contain('There is a problem') - }) - }) - - describe('when the request fails', () => { - describe('because the sending service threw an error', () => { - beforeEach(async () => { - Sinon.stub(Boom, 'badImplementation').returns(new Boom.Boom('Bang', { statusCode: 500 })) - Sinon.stub(SubmitAmendedAuthorisedVolumeService, 'go').rejects() - }) - - it('returns the error page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Sorry, there is a problem with the service') - }) - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}', () => { - describe('GET', () => { - beforeEach(async () => { - options = _getRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/match-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - ) - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(MatchDetailsService, 'go').resolves(_chargeElementDetails()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Charge period 1 April 2022 to 31 March 2023') - expect(response.payload).to.contain('Financial year 2022 to 2023') - expect(response.payload).to.contain('River Test and tributaries near Fullerton Grange, Andover') - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}/match-details/{reviewChargeElementId}/amend-billable-returns', () => { - describe('GET', () => { - beforeEach(async () => { - options = _getRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/match-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2/amend-billable-returns' - ) - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(AmendBillableReturnsService, 'go').resolves(_billableReturnData()) - }) - - it('returns a 200 response', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Spray irrigation - storage, Abstraction from borehole at Chipping Norton') - expect(response.payload).to.contain('Financial year 2022 to 2023') - expect(response.payload).to.contain('Authorised 40ML') - }) - }) - }) - - describe('POST', () => { - beforeEach(() => { - options = _postRequestOptions( - 'review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/match-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2/amend-billable-returns' - ) - }) - - describe('when a request is valid', () => { - beforeEach(async () => { - Sinon.stub(SubmitAmendedBillableReturnsService, 'go').resolves(_matchDetailsData()) - }) - - it('redirects to the match details page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - '/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review/cc4bbb18-0d6a-4254-ac2c-7409de814d7e/match-details/9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - ) - }) - }) - - describe('when a request is invalid', () => { - beforeEach(async () => { - Sinon.stub(SubmitAmendedBillableReturnsService, 'go').resolves(_billableReturnData(true)) - }) - - it('re-renders the page with an error message', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Select the billable quantity') - expect(response.payload).to.contain('There is a problem') - }) - }) - - describe('when the request fails', () => { - describe('because the sending service threw an error', () => { - beforeEach(async () => { - Sinon.stub(Boom, 'badImplementation').returns(new Boom.Boom('Bang', { statusCode: 500 })) - Sinon.stub(SubmitAmendedBillableReturnsService, 'go').rejects() - }) - - it('returns the error page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(200) - expect(response.payload).to.contain('Sorry, there is a problem with the service') - }) - }) - }) - }) - }) - - describe('/bill-runs/{id}/review/{licenceId}/preview-charge/{reviewChargeReferenceId}', () => { - describe('GET', () => { - const licenceId = '87cb11cf-1e5e-448d-8050-29f4e681b416' - const reviewChargeReferenceId = '7c09753d-f606-4deb-a929-4bc8aa7acb8d' - - beforeEach(async () => { - options = _getRequestOptions(`review/${licenceId}/preview-charge/${reviewChargeReferenceId}`) - }) - - describe('when a request is valid', () => { - beforeEach(() => { - Sinon.stub(CalculateChargeService, 'go').resolves() - }) - - it('redirects to the review charge reference details page', async () => { - const response = await server.inject(options) - - expect(response.statusCode).to.equal(302) - expect(response.headers.location).to.equal( - `/system/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28/review/${licenceId}/charge-reference-details/${reviewChargeReferenceId}` - ) - }) - }) - }) - }) - describe('/bill-runs/{id}/send', () => { describe('GET', () => { beforeEach(async () => { @@ -735,97 +304,6 @@ describe('Bill Runs controller', () => { }) }) -function _authorisedVolumeData (error = false) { - const pageData = { - billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', - financialYear: '2022 to 2023', - chargePeriod: '1 April 2022 to 31 March 2023', - chargeReference: { - id: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - description: 'High loss, non-tidal, restricted water, greater than 85 up to and including 120 ML/yr', - authorisedVolume: 150, - totalBillableReturns: 140 - }, - chargeCategory: { - minVolume: 10, - maxVolume: 170 - } - } - - if (error) { - pageData.error = { authorisedVolume: 'The authorised volume must be a number' } - } - - return pageData -} - -function _billableReturnData (error = false) { - const pageDate = { - chargeElement: { - description: 'Spray irrigation - storage, Abstraction from borehole at Chipping Norton', - dates: '25 July 2022 to 29 December 2022' - }, - billRun: { - financialYear: '2022 to 2023' - }, - chargeVersion: { - chargePeriod: '1 April 2022 to 31 March 2023' - }, - authorisedQuantity: 40 - } - - if (error) { - pageDate.error = { message: 'Select the billable quantity' } - } - - return pageDate -} - -function _chargeElementDetails () { - return { - billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', - financialYear: '2022 to 2023', - chargePeriod: '1 April 2022 to 31 March 2023', - chargeElement: { - chargeElementId: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - description: 'River Test and tributaries near Fullerton Grange, Andover', - dates: '1 April 2022 to 31 October 2022', - status: 'Ready', - billableVolume: 10, - authorisedVolume: 10, - issues: [] - }, - matchedReturns: {} - } -} - -function _chargeReferenceData (error = false) { - const pageData = { - billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', - financialYear: '2022 to 2023', - chargePeriod: '1 April 2022 to 31 March 2023', - chargeReference: { - reference: '4.6.24', - description: 'High loss, non-tidal, restricted water, greater than 85 up to and including 120 ML/yr', - totalBillableReturns: 5, - authorisedVolume: 10, - adjustments: ['Aggregate factor (0.5)'] - } - } - - if (error) { - pageData.error = { - aggregateFactorElement: { - text: 'The aggregate factor must be a number' - }, - chargeAdjustmentElement: null - } - pageData.inputtedAggregateValue = '10' - } - - return pageData -} - function _getRequestOptions (path) { const root = '/bill-runs/97db1a27-8308-4aba-b463-8a6af2558b28' const url = path ? `${root}/${path}` : root @@ -847,54 +325,6 @@ function _postRequestOptions (path) { return postRequestOptions(url) } -function _licenceReviewData () { - return { - billRunId: '97db1a27-8308-4aba-b463-8a6af2558b28', - region: 'Southern (Test replica)', - licence: { - licenceId: '7c8a248c-b71e-463c-bea8-bc5e0a5d95e2', - licenceRef: '1/11/10/*S/0084', - status: 'review', - licenceHolder: 'Licence Holder Ltd' - }, - chargePeriodDates: ['1 April 2022 to 31 March 2023'], - matchedReturns: [ - { - returnId: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - reference: '11142960', - dates: '1 November 2021 to 31 October 2022', - status: 'completed', - description: 'Test Road. Points 1 and 2.', - purpose: 'Spray Irrigation - Anti Frost', - total: '0 ML / 0 ML', - issues: ['Returns received late'] - } - ], - unmatchedReturns: [], - chargeData: [] - } -} - -function _matchDetailsData () { - return { - billRunId: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023', - chargePeriod: '1 April 2022 to 5 June 2022', - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - showBanner: true, - chargeElement: { - chargeElementId: 'b4d70c89-de1b-4f68-a47f-832b338ac044', - description: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - status: 'ready', - billableVolume: 0, - authorisedVolume: 200, - issues: [] - }, - matchedReturns: [] - } -} - function _multiGroupBillRun () { return { billsCount: '2 Annual bills', From 1e3eeaa014fc66ff2e579cad2cff78cc2a9acd1e Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:24:27 +0000 Subject: [PATCH 105/147] Add tests for our new base-review presenter --- .../review/base-review.presenter.test.js | 304 ++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 test/presenters/bill-runs/review/base-review.presenter.test.js diff --git a/test/presenters/bill-runs/review/base-review.presenter.test.js b/test/presenters/bill-runs/review/base-review.presenter.test.js new file mode 100644 index 0000000000..568c3ef572 --- /dev/null +++ b/test/presenters/bill-runs/review/base-review.presenter.test.js @@ -0,0 +1,304 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const ReturnLogHelper = require('../../../support/helpers/return-log.helper.js') + +// Thing under test +const BaseReviewPresenter = require('../../../../app/presenters/bill-runs/review/base-review.presenter.js') + +describe('Bill Runs Review - Base Review presenter', () => { + describe('#calculateTotalBillableReturns()', () => { + const reviewChargeElements = [ + { amendedAllocated: 11.513736 }, + { amendedAllocated: 1.92708 }, + { amendedAllocated: 23.022753 }, + { amendedAllocated: 0.636794 }, + { amendedAllocated: 26.400139 } + ] + + it('returns the sum of "amendedAllocated" for the review charge elements passed in', () => { + const result = BaseReviewPresenter.calculateTotalBillableReturns(reviewChargeElements) + + expect(result).to.equal(63.500502) + }) + }) + + describe('#determineReturnLink()', () => { + const returnId = ReturnLogHelper.generateReturnLogId() + + let reviewReturn + + describe('when the review return has a status of "due"', () => { + beforeEach(() => { + reviewReturn = { returnId, returnStatus: 'due' } + }) + + it('returns the link to edit the return', () => { + const result = BaseReviewPresenter.determineReturnLink(reviewReturn) + + expect(result).to.equal(`/return/internal?returnId=${returnId}`) + }) + }) + + describe('when the review return has a status of "received"', () => { + beforeEach(() => { + reviewReturn = { returnId, returnStatus: 'received' } + }) + + it('returns the link to edit the return', () => { + const result = BaseReviewPresenter.determineReturnLink(reviewReturn) + + expect(result).to.equal(`/return/internal?returnId=${returnId}`) + }) + }) + + describe('when the review return has any other status', () => { + beforeEach(() => { + reviewReturn = { returnId, returnStatus: 'completed' } + }) + + it('returns the link to view the return', () => { + const result = BaseReviewPresenter.determineReturnLink(reviewReturn) + + expect(result).to.equal(`/returns/return?id=${returnId}`) + }) + }) + }) + + describe('#formatAdditionalCharges()', () => { + let chargeReference + + describe('when the charge reference has no additional charges', () => { + beforeEach(() => { + chargeReference = { supportedSourceName: null, waterCompanyCharge: null } + }) + + it('returns an empty array', () => { + const result = BaseReviewPresenter.formatAdditionalCharges(chargeReference) + + expect(result).to.be.empty() + }) + }) + + describe('when the charge reference has a supported source name', () => { + beforeEach(() => { + chargeReference = { supportedSourceName: 'Foo source', waterCompanyCharge: null } + }) + + it('returns an array containing the charge formatted for display', () => { + const result = BaseReviewPresenter.formatAdditionalCharges(chargeReference) + + expect(result).to.equal(['Supported source Foo source']) + }) + }) + + describe('when the charge reference has a water company charge', () => { + beforeEach(() => { + chargeReference = { supportedSourceName: null, waterCompanyCharge: true } + }) + + it('returns an array containing the charge formatted for display', () => { + const result = BaseReviewPresenter.formatAdditionalCharges(chargeReference) + + expect(result).to.equal(['Public Water Supply']) + }) + }) + + describe('when the charge reference has both charges', () => { + beforeEach(() => { + chargeReference = { supportedSourceName: 'Foo source', waterCompanyCharge: true } + }) + + it('returns an array containing the charges formatted for display', () => { + const result = BaseReviewPresenter.formatAdditionalCharges(chargeReference) + + expect(result).to.equal(['Supported source Foo source', 'Public Water Supply']) + }) + }) + }) + + describe('#formatChargePeriod()', () => { + const reviewChargeVersion = { + chargePeriodStartDate: new Date('2024-04-01'), + chargePeriodEndDate: new Date('2024-09-30') + } + + it("returns the review charge version's charge period formatted for display", () => { + const result = BaseReviewPresenter.formatChargePeriod(reviewChargeVersion) + + expect(result).to.equal('1 April 2024 to 30 September 2024') + }) + }) + + describe('#formatChargePeriods()', () => { + const chargeElement = { + abstractionPeriodStartDay: 1, + abstractionPeriodStartMonth: 1, + abstractionPeriodEndDay: 31, + abstractionPeriodEndMonth: 12 + } + + let reviewChargeElement + + describe('when no charge period is provided (it will be extracted via linked records)', () => { + beforeEach(() => { + reviewChargeElement = { + chargeElement, + reviewChargeReference: { + reviewChargeVersion: { + chargePeriodStartDate: new Date('2023-05-24'), + chargePeriodEndDate: new Date('2024-03-31') + } + } + } + }) + + it("will return the review element's charge periods formatted for display", () => { + const result = BaseReviewPresenter.formatChargePeriods(reviewChargeElement) + + expect(result).to.equal(['24 May 2023 to 31 December 2023', '1 January 2024 to 31 March 2024']) + }) + }) + + describe('when a charge period is provided', () => { + const chargePeriod = { startDate: new Date('2023-05-24'), endDate: new Date('2024-03-31') } + + beforeEach(() => { + reviewChargeElement = { chargeElement } + }) + + it("will return the review element's charge periods formatted for display", () => { + const result = BaseReviewPresenter.formatChargePeriods(reviewChargeElement, chargePeriod) + + expect(result).to.equal(['24 May 2023 to 31 December 2023', '1 January 2024 to 31 March 2024']) + }) + }) + }) + + describe('#formatIssues()', () => { + let issues + + describe('when "issues" is an empty string', () => { + beforeEach(() => { + issues = '' + }) + + it('returns an empty array', () => { + const result = BaseReviewPresenter.formatIssues(issues) + + expect(result).to.be.empty() + }) + }) + + describe('when "issues" is a single value', () => { + beforeEach(() => { + issues = 'Aggregate' + }) + + it('returns an array containing the one value', () => { + const result = BaseReviewPresenter.formatIssues(issues) + + expect(result).to.equal(['Aggregate']) + }) + }) + + describe('when "issues" contains multiple values', () => { + beforeEach(() => { + issues = 'Aggregate, No returns received' + }) + + it('returns an array containing all values', () => { + const result = BaseReviewPresenter.formatIssues(issues) + + expect(result).to.equal(['Aggregate', 'No returns received']) + }) + }) + }) + + describe('#formatReturnStatus()', () => { + let reviewReturn + + describe("when the review return's status is 'due'", () => { + beforeEach(() => { + reviewReturn = { returnStatus: 'due', underQuery: false } + }) + + it('returns "overdue"', () => { + const result = BaseReviewPresenter.formatReturnStatus(reviewReturn) + + expect(result).to.equal('overdue') + }) + }) + + describe("when the review return is 'under query'", () => { + beforeEach(() => { + reviewReturn = { returnStatus: 'completed', underQuery: true } + }) + + it('returns "query"', () => { + const result = BaseReviewPresenter.formatReturnStatus(reviewReturn) + + expect(result).to.equal('query') + }) + }) + + describe("when the review return is not 'under query' and the status is not 'due'", () => { + beforeEach(() => { + reviewReturn = { returnStatus: 'completed', underQuery: false } + }) + + it('returns whatever is the status of the review return', () => { + const result = BaseReviewPresenter.formatReturnStatus(reviewReturn) + + expect(result).to.equal('completed') + }) + }) + }) + + describe('#formatReturnTotals()', () => { + let reviewReturn + + describe("when the review return's status is 'due'", () => { + beforeEach(() => { + reviewReturn = { allocated: 10.1, quantity: 15, returnStatus: 'due' } + }) + + it('returns "/"', () => { + const result = BaseReviewPresenter.formatReturnTotals(reviewReturn) + + expect(result).to.equal('/') + }) + }) + + describe("when the review return's status is 'received'", () => { + beforeEach(() => { + reviewReturn = { allocated: 10.1, quantity: 15, returnStatus: 'received' } + }) + + it('returns "/"', () => { + const result = BaseReviewPresenter.formatReturnTotals(reviewReturn) + + expect(result).to.equal('/') + }) + }) + + describe('when the review return has any other status', () => { + beforeEach(() => { + reviewReturn = { allocated: 10.1, quantity: 15, returnStatus: 'completed' } + }) + + it('returns "10.1 ML / 15 ML"', () => { + const result = BaseReviewPresenter.formatReturnTotals(reviewReturn) + + expect(result).to.equal('10.1 ML / 15 ML') + }) + }) + }) +}) From 8f06ff4423363d4de2b9f3f524d07e3ddde1ff7a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:24:50 +0000 Subject: [PATCH 106/147] Move, rename & refactor authorised presenter test --- .../review/authorised.presenter.test.js | 37 +++++++ .../amend-authorised-volume.presenter.test.js | 102 ------------------ 2 files changed, 37 insertions(+), 102 deletions(-) create mode 100644 test/presenters/bill-runs/review/authorised.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.test.js diff --git a/test/presenters/bill-runs/review/authorised.presenter.test.js b/test/presenters/bill-runs/review/authorised.presenter.test.js new file mode 100644 index 0000000000..725c3ac7e7 --- /dev/null +++ b/test/presenters/bill-runs/review/authorised.presenter.test.js @@ -0,0 +1,37 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const AuthorisedPresenter = require('../../../../app/presenters/bill-runs/review/authorised.presenter.js') + +describe('Bill Runs Review - Authorised presenter', () => { + let reviewChargeReference + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + }) + + describe('when provided with the result of fetch review charge reference service', () => { + it('correctly presents the data', () => { + const result = AuthorisedPresenter.go(reviewChargeReference) + + expect(result).to.equal({ + amendedAuthorisedVolume: 9.092, + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + totalBillableReturns: 0 + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.test.js deleted file mode 100644 index 58bd524134..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.test.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const AmendAuthorisedVolumePresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js') - -describe('Amend Authorised Volume presenter', () => { - const licenceId = '5aa8e752-1a5c-4b01-9112-d92a543b70d1' - let reviewChargeReference - let billRun - - describe('when there is data to be presented for the amend authorised volume page', () => { - beforeEach(() => { - billRun = _billRun() - reviewChargeReference = _reviewChargeReference() - }) - - it('correctly presents the data', () => { - const result = AmendAuthorisedVolumePresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result).to.equal({ - billRunId: '6620135b-0ecf-4fd4-924e-371f950c0526', - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - financialYear: '2022 to 2023', - chargePeriod: '1 September 2022 to 31 March 2023', - chargeReference: { - id: '6b3d11f2-d361-4eaa-bce2-5561283bd023', - description: 'Medium loss, non-tidal, greater than 83 up to and including 142 ML/yr', - authorisedVolume: 25.5, - totalBillableReturns: 15 - }, - chargeCategory: { - minVolume: 83, - maxVolume: 142 - } - }) - }) - - describe('the "totalBillableReturns" property', () => { - describe('when there are multiple reviewChargeElements', () => { - beforeEach(() => { - reviewChargeReference.reviewChargeElements.push({ - amendedAllocated: 17 - }) - }) - - it('sums the amendedAllocated volumes up', () => { - const result = AmendAuthorisedVolumePresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.totalBillableReturns).to.equal(32) - }) - }) - - describe('when there are no reviewChargeElements', () => { - beforeEach(() => { - reviewChargeReference.reviewChargeElements = [] - }) - - it('returns a total of 0', () => { - const result = AmendAuthorisedVolumePresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.totalBillableReturns).to.equal(0) - }) - }) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeReference () { - return { - id: '6b3d11f2-d361-4eaa-bce2-5561283bd023', - amendedAuthorisedVolume: 25.5, - chargeReference: { - chargeCategoryId: 'b4354db6-6699-4987-b4c8-d53ac2bf2250', - chargeCategory: { - shortDescription: 'Medium loss, non-tidal, greater than 83 up to and including 142 ML/yr', - minVolume: 83, - maxVolume: 142 - } - }, - reviewChargeElements: [{ - amendedAllocated: 15 - }], - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-09-01'), - chargePeriodEndDate: new Date('2023-03-31') - } - } -} From afaaca2967386e061920bbc85584cd5c17b08155 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:25:33 +0000 Subject: [PATCH 107/147] Move, rename & refactor edit presenter test --- .../bill-runs/review/edit.presenter.test.js | 67 +++++++++++++ .../amend-billable-returns.presenter.test.js | 93 ------------------- 2 files changed, 67 insertions(+), 93 deletions(-) create mode 100644 test/presenters/bill-runs/review/edit.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.test.js diff --git a/test/presenters/bill-runs/review/edit.presenter.test.js b/test/presenters/bill-runs/review/edit.presenter.test.js new file mode 100644 index 0000000000..9dc4b6907f --- /dev/null +++ b/test/presenters/bill-runs/review/edit.presenter.test.js @@ -0,0 +1,67 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const EditPresenter = require('../../../../app/presenters/bill-runs/review/edit.presenter.js') + +describe('Bill Runs Review - Edit presenter', () => { + const elementIndex = 1 + + let reviewChargeElement + + beforeEach(() => { + reviewChargeElement = BillRunsReviewFixture.reviewChargeElement() + }) + + describe('when provided with the result of fetch review charge element service', () => { + it('correctly presents the data', () => { + const result = EditPresenter.go(reviewChargeElement, elementIndex) + + expect(result).to.equal({ + authorisedQuantity: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementIndex: 1, + financialPeriod: '2023 to 2024', + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' + }) + }) + }) + + describe('the "authorisedQuantity" property', () => { + describe("when the linked review charge reference's authorised volume is less than the element's", () => { + beforeEach(() => { + reviewChargeElement.reviewChargeReference.amendedAuthorisedVolume = 5 + }) + + it("returns the charge reference's lower authorised volume", () => { + const result = EditPresenter.go(reviewChargeElement) + + expect(result.authorisedQuantity).to.equal(5) + }) + }) + + describe("when the linked review charge reference's authorised volume is greater than the element's", () => { + beforeEach(() => { + reviewChargeElement.reviewChargeReference.amendedAuthorisedVolume = 15 + }) + + it("returns the charge element's lower authorised volume", () => { + const result = EditPresenter.go(reviewChargeElement) + + expect(result.authorisedQuantity).to.equal(9.092) + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.test.js deleted file mode 100644 index 17e354ff4c..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.test.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const AmendBillableReturnsPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js') - -describe('Amend Billable Returns presenter', () => { - const licenceId = '5aa8e752-1a5c-4b01-9112-d92a543b70d1' - let reviewChargeElement - let billRun - - describe('when there is data to be presented for the amend billable returns page', () => { - beforeEach(() => { - billRun = _billRun() - reviewChargeElement = _reviewChargeElementData() - }) - - it('correctly presents the data', async () => { - const result = AmendBillableReturnsPresenter.go(billRun, reviewChargeElement, licenceId) - - expect(result).to.equal({ - chargeElement: { - description: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - reviewChargeElementId: 'b4d70c89-de1b-4f68-a47f-832b338ac044' - }, - billRun: { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023' - }, - chargeVersion: { - chargePeriod: '1 April 2022 to 5 June 2022' - }, - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - authorisedQuantity: 200 - }) - }) - - describe('when the charge reference has a lower authorised volume than the element', () => { - beforeEach(() => { - reviewChargeElement.reviewChargeReference.amendedAuthorisedVolume = 150 - }) - - it('displays the lower volume from the two', () => { - const result = AmendBillableReturnsPresenter.go(billRun, reviewChargeElement, licenceId) - - expect(result.authorisedQuantity).to.equal(150) - }) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeElementData () { - return { - id: 'b4d70c89-de1b-4f68-a47f-832b338ac044', - reviewChargeReferenceId: '9e5d87d7-073e-420e-b12d-73ca220dd8ef', - chargeElementId: 'b345f1f1-496b-4049-a647-6bcd123dcf68', - allocated: 0, - status: 'ready', - createdAt: new Date('2024-04-02'), - updatedAt: new Date('2024-04-02'), - chargeElement: { - description: 'Trickle Irrigation - Direct', - abstractionPeriodStartDay: 1, - abstractionPeriodStartMonth: 4, - abstractionPeriodEndDay: 31, - abstractionPeriodEndMonth: 3, - authorisedAnnualQuantity: 200 - }, - reviewChargeReference: { - id: '9e5d87d7-073e-420e-b12d-73ca220dd8ef', - amendedAuthorisedVolume: 250, - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-05') - } - } - } -} From c7b289942b2332f60017b684de1344d67ab2c5ae Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:25:50 +0000 Subject: [PATCH 108/147] Move, rename & refactor factors presenter test --- .../review/factors.presenter.test.js | 129 ++++++++++++++ .../amend-adjustment-factor.presenter.test.js | 167 ------------------ 2 files changed, 129 insertions(+), 167 deletions(-) create mode 100644 test/presenters/bill-runs/review/factors.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.test.js diff --git a/test/presenters/bill-runs/review/factors.presenter.test.js b/test/presenters/bill-runs/review/factors.presenter.test.js new file mode 100644 index 0000000000..18e5597071 --- /dev/null +++ b/test/presenters/bill-runs/review/factors.presenter.test.js @@ -0,0 +1,129 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const FactorsPresenter = require('../../../../app/presenters/bill-runs/review/factors.presenter.js') + +describe('Bill Runs Review - Factors presenter', () => { + let reviewChargeReference + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + }) + + describe('when provided with the result of fetch review charge reference service', () => { + it('correctly presents the data', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result).to.equal({ + amendedAggregate: 0.333333333, + amendedChargeAdjustment: 1, + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + otherAdjustments: ['Two part tariff agreement'], + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023' + }) + }) + }) + + describe('the "otherAdjustments" property', () => { + beforeEach(() => { + // Our fixture has this as true by default. We set it false so it doesn't interfere with the following tests + reviewChargeReference.twoPartTariffAgreement = false + }) + + describe('when the charge reference has an abatement agreement', () => { + beforeEach(() => { + reviewChargeReference.abatementAgreement = 0.3 + }) + + it('adds the abatement agreement to the otherAdjustments property', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal(['Abatement agreement (0.3)']) + }) + }) + + describe('when the charge reference has a winter discount', () => { + beforeEach(() => { + reviewChargeReference.winterDiscount = true + }) + + it('adds the winter discount to the otherAdjustments property', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal(['Winter discount']) + }) + }) + + describe('when the charge reference has a two part tariff agreement', () => { + beforeEach(() => { + reviewChargeReference.twoPartTariffAgreement = true + }) + + it('adds the two part tariff agreement to the otherAdjustments property', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal(['Two part tariff agreement']) + }) + }) + + describe('when the charge reference has a canal and river trust agreement', () => { + beforeEach(() => { + reviewChargeReference.canalAndRiverTrustAgreement = true + }) + + it('adds the canal and river trust agreement to the otherAdjustments property', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal(['Canal and River trust agreement']) + }) + }) + + describe('when the charge reference has a supported source', () => { + beforeEach(() => { + reviewChargeReference.chargeReference.supportedSourceName = 'Thames' + }) + + it('adds the supported source to the otherAdjustments property', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal(['Supported source Thames']) + }) + }) + + describe('when the charge reference has a public water supply', () => { + beforeEach(() => { + reviewChargeReference.chargeReference.waterCompanyCharge = true + }) + + it('adds the public water supply to the otherAdjustments property', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal(['Public Water Supply']) + }) + }) + + describe('when the charge reference has no other adjustments', () => { + beforeEach(() => { + reviewChargeReference.twoPartTariffAgreement = false + }) + + it('sets the otherAdjustments property as empty', () => { + const result = FactorsPresenter.go(reviewChargeReference) + + expect(result.otherAdjustments).to.equal([]) + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.test.js deleted file mode 100644 index 9e8824f4be..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.test.js +++ /dev/null @@ -1,167 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const AmendAdjustmentFactorPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js') - -describe('Amend Adjustment Factor presenter', () => { - const licenceId = '5aa8e752-1a5c-4b01-9112-d92a543b70d1' - let reviewChargeReference - let billRun - - describe('when there is data to be presented for the amend adjustment factor page', () => { - beforeEach(() => { - billRun = _billRun() - reviewChargeReference = _reviewChargeReference() - }) - - it('correctly presents the data', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result).to.equal({ - billRunId: '6620135b-0ecf-4fd4-924e-371f950c0526', - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - financialYear: '2022 to 2023', - chargePeriod: '1 September 2022 to 31 March 2023', - chargeReference: { - id: 'e93fa3c6-195f-48eb-a03f-f87db7218f2d', - description: 'High loss, non-tidal, greater than 50 up to and including 85 ML/yr', - aggregateFactor: 1, - chargeAdjustment: 1, - otherAdjustments: [] - } - }) - }) - - describe('the "otherAdjustments" property', () => { - describe('when the charge reference has a abatement agreement', () => { - beforeEach(() => { - reviewChargeReference.abatementAgreement = 0.3 - }) - - it('adds the abatement agreement to the otherAdjustments property', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal(['Abatement agreement (0.3)']) - }) - }) - - describe('when the charge reference has a winter discount', () => { - beforeEach(() => { - reviewChargeReference.winterDiscount = true - }) - - it('adds the winter discount to the otherAdjustments property', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal(['Winter discount']) - }) - }) - - describe('when the charge reference has a two part tariff agreement', () => { - beforeEach(() => { - reviewChargeReference.twoPartTariffAgreement = true - }) - - it('adds the two part tariff agreement to the otherAdjustments property', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal(['Two part tariff agreement']) - }) - }) - - describe('when the charge reference has a canal and river trust agreement', () => { - beforeEach(() => { - reviewChargeReference.canalAndRiverTrustAgreement = true - }) - - it('adds the canal and river trust agreement to the otherAdjustments property', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal(['Canal and River trust agreement']) - }) - }) - - describe('when the charge reference has a supported source', () => { - beforeEach(() => { - reviewChargeReference.chargeReference.supportedSourceName = 'Thames' - }) - - it('adds the supported source to the otherAdjustments property', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal(['Supported source Thames']) - }) - }) - - describe('when the charge reference has a public water supply', () => { - beforeEach(() => { - reviewChargeReference.chargeReference.waterCompanyCharge = true - }) - - it('adds the public water supply to the otherAdjustments property', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal(['Public Water Supply']) - }) - }) - - describe('when the charge reference has no other adjustments', () => { - it('sets the otherAdjustments property as empty', () => { - const result = AmendAdjustmentFactorPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.otherAdjustments).to.equal([]) - }) - }) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeReference () { - return { - id: 'e93fa3c6-195f-48eb-a03f-f87db7218f2d', - reviewChargeVersionId: 'ad4d0543-e129-429b-ab36-39d0804637b7', - chargeReferenceId: 'c61dfa06-e8e9-413e-93d8-0aedbf4d8638', - aggregate: 1.25, - createdAt: new Date('2024-05-02'), - updatedAt: new Date('2024-05-02'), - amendedAggregate: 1, - chargeAdjustment: 1, - amendedChargeAdjustment: 1, - abatementAgreement: 1, - winterDiscount: false, - twoPartTariffAgreement: false, - canalAndRiverTrustAgreement: false, - authorisedVolume: 60, - amendedAuthorisedVolume: 60, - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-09-01'), - chargePeriodEndDate: new Date('2023-03-31') - }, - chargeReference: { - volume: 60, - chargeCategoryId: '65e80b7f-13fb-4d27-b739-20f0adf36b54', - supportedSourceName: null, - waterCompanyCharge: null, - chargeCategory: { - reference: '4.6.13', - shortDescription: 'High loss, non-tidal, greater than 50 up to and including 85 ML/yr' - } - }, - reviewChargeElements: [] - } -} From fabfe1cdee5e934c376fa3bd2a6ebf84ae0316c8 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:26:16 +0000 Subject: [PATCH 109/147] Move, rename & refactor review chg ref presenter test --- .../review-charge-reference.presenter.test.js | 133 +++++++++ ...charge-reference-details.presenter.test.js | 276 ------------------ 2 files changed, 133 insertions(+), 276 deletions(-) create mode 100644 test/presenters/bill-runs/review/review-charge-reference.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.test.js diff --git a/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js b/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js new file mode 100644 index 0000000000..c9566b691e --- /dev/null +++ b/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js @@ -0,0 +1,133 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const ReviewChargeReferencePresenter = require('../../../../app/presenters/bill-runs/review/review-charge-reference.presenter.js') + +describe('Bill Runs Review - Review Charge Reference presenter', () => { + let reviewChargeReference + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + }) + + describe('when provided with the result of fetch review charge reference service', () => { + it('correctly presents the data', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result).to.equal({ + additionalCharges: '', + adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + amendedAuthorisedVolume: 9.092, + canAmend: true, + chargeCategory: '4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + totalBillableReturns: 0 + }) + }) + }) + + describe('the "adjustments" property', () => { + beforeEach(() => { + // Our fixture has these set by default. We set unset them so they don't interfere with the following tests + reviewChargeReference.aggregate = 1 + reviewChargeReference.amendedAggregate = 1 + reviewChargeReference.twoPartTariffAgreement = false + }) + + describe('when the charge reference has an aggregate factor', () => { + beforeEach(() => { + reviewChargeReference.aggregate = 0.5 + reviewChargeReference.amendedAggregate = 0.5 + }) + + it('adds the aggregate factor to the adjustments property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal(['Aggregate factor (0.5)']) + }) + }) + + describe('when the charge reference has a charge adjustment factor', () => { + beforeEach(() => { + reviewChargeReference.amendedChargeAdjustment = 0.7 + reviewChargeReference.chargeAdjustment = 0.7 + }) + + it('adds the charge adjustment factor to the adjustments property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal(['Charge adjustment (0.7)']) + }) + }) + + describe('when the charge reference has a abatement agreement', () => { + beforeEach(() => { + reviewChargeReference.abatementAgreement = 0.3 + }) + + it('adds the abatement agreement to the adjustments property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal(['Abatement agreement (0.3)']) + }) + }) + + describe('when the charge reference has a winter discount', () => { + beforeEach(() => { + reviewChargeReference.winterDiscount = true + }) + + it('adds the winter discount to the adjustments property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal(['Winter discount']) + }) + }) + + describe('when the charge reference has a two part tariff agreement', () => { + beforeEach(() => { + reviewChargeReference.twoPartTariffAgreement = true + }) + + it('adds the two part tariff agreement to the adjustments property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal(['Two part tariff agreement']) + }) + }) + + describe('when the charge reference has a canal and river trust agreement', () => { + beforeEach(() => { + reviewChargeReference.canalAndRiverTrustAgreement = true + }) + + it('adds the canal and river trust agreement to the adjustments property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal(['Canal and River trust agreement']) + }) + }) + + describe('when the charge reference has no adjustments', () => { + it('sets the adjustments property as empty', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal([]) + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.test.js deleted file mode 100644 index d125ee494d..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.test.js +++ /dev/null @@ -1,276 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const ChargeReferenceDetailsPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/charge-reference-details.presenter.js') - -describe('Charge Reference Details presenter', () => { - describe('when there is data to be presented for the charge reference details page', () => { - const billRun = _billRun() - const licenceId = '5aa8e752-1a5c-4b01-9112-d92a543b70d1' - - let reviewChargeReference - - beforeEach(() => { - reviewChargeReference = _reviewChargeReferenceData() - }) - - it('correctly presents the data', async () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result).to.equal({ - billRunId: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023', - chargePeriod: '1 April 2022 to 31 March 2023', - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - chargeReference: { - id: '89eebffa-28a2-489d-b93a-c0f02a2bdbdd', - reference: '4.6.12', - description: 'High loss, non-tidal, restricted water, greater than 15 up to and including 50 ML/yr, Tier 2 model', - totalBillableReturns: 0.00018, - authorisedVolume: 32, - adjustments: [], - additionalCharges: '' - }, - hasAggregateOrChargeFactor: false - }) - }) - - describe('the "adjustments" property', () => { - describe('when the charge reference has an aggregate factor', () => { - beforeEach(() => { - reviewChargeReference.amendedAggregate = 0.5 - reviewChargeReference.aggregate = 0.5 - }) - - it('adds the aggregate factor to the adjustments property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal(['Aggregate factor (0.5)']) - }) - - it('sets the "hasAggregateOrChargeFactor" property to true', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.hasAggregateOrChargeFactor).to.equal(true) - }) - - describe('when the source aggregate factor is different to the amendedAggregate factor', () => { - beforeEach(() => { - reviewChargeReference.aggregate = 0.5 - reviewChargeReference.amendedAggregate = 1 - }) - - it('sets the "hasAggregateOrChargeFactor" property to true', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.hasAggregateOrChargeFactor).to.equal(true) - }) - }) - }) - - describe('when the charge reference has a charge adjustment factor', () => { - beforeEach(() => { - reviewChargeReference.amendedChargeAdjustment = 0.7 - reviewChargeReference.chargeAdjustment = 0.7 - }) - - it('adds the charge adjustment factor to the adjustments property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal(['Charge adjustment (0.7)']) - }) - - it('sets the "hasAggregateOrChargeFactor" property to true', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.hasAggregateOrChargeFactor).to.equal(true) - }) - - describe('when the source charge adjustment factor is different to the amendedChargeAdjustment factor', () => { - beforeEach(() => { - reviewChargeReference.chargeAdjustment = 0.5 - reviewChargeReference.amendedChargeAdjustment = 1 - }) - - it('sets the "hasAggregateOrChargeFactor" property to true', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.hasAggregateOrChargeFactor).to.equal(true) - }) - }) - }) - - describe('when the charge reference has a abatement agreement', () => { - beforeEach(() => { - reviewChargeReference.abatementAgreement = 0.3 - }) - - it('adds the abatement agreement to the adjustments property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal(['Abatement agreement (0.3)']) - }) - }) - - describe('when the charge reference has a winter discount', () => { - beforeEach(() => { - reviewChargeReference.winterDiscount = true - }) - - it('adds the winter discount to the adjustments property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal(['Winter discount']) - }) - }) - - describe('when the charge reference has a two part tariff agreement', () => { - beforeEach(() => { - reviewChargeReference.twoPartTariffAgreement = true - }) - - it('adds the two part tariff agreement to the adjustments property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal(['Two part tariff agreement']) - }) - }) - - describe('when the charge reference has a canal and river trust agreement', () => { - beforeEach(() => { - reviewChargeReference.canalAndRiverTrustAgreement = true - }) - - it('adds the canal and river trust agreement to the adjustments property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal(['Canal and River trust agreement']) - }) - }) - - describe('when the charge reference has no adjustments', () => { - it('sets the adjustments property as empty', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.adjustments).to.equal([]) - }) - - it('sets "hasAggregateOrChargeFactor" property to false', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.hasAggregateOrChargeFactor).to.equal(false) - }) - }) - }) - - describe('the "additionalCharges" property', () => { - describe('when the charge reference has a support source charge', () => { - beforeEach(() => { - reviewChargeReference.chargeReference.supportedSourceName = 'Thames' - }) - - it('adds the supported source charge to the "additionalCharges" property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.additionalCharges).to.equal('Supported source Thames') - }) - }) - - describe('when the charge reference has a water company charge', () => { - beforeEach(() => { - reviewChargeReference.chargeReference.waterCompanyCharge = true - }) - - it('adds the water company charge to the "additionalCharges" property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.additionalCharges).to.equal('Public Water Supply') - }) - - describe('and a support source charge', () => { - beforeEach(() => { - reviewChargeReference.chargeReference.supportedSourceName = 'Thames' - }) - - it('adds the both charges to the "additionalCharges" property', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.additionalCharges).to.equal('Supported source Thames, Public Water Supply') - }) - }) - }) - - describe('when the charge reference has no extra charges', () => { - it('sets the "additionalCharges" property to empty', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.additionalCharges).to.equal('') - }) - }) - }) - - describe('the "totalBillableReturns" property', () => { - describe('when there are multiple charge elements on the charge reference', () => { - beforeEach(() => { - reviewChargeReference.reviewChargeElements = [{ amendedAllocated: 1 }, { amendedAllocated: 2 }] - }) - - it('adds the "amendedAllocated" property on the charge elements', () => { - const result = ChargeReferenceDetailsPresenter.go(billRun, reviewChargeReference, licenceId) - - expect(result.chargeReference.totalBillableReturns).to.equal(3) - }) - }) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeReferenceData () { - return { - id: '89eebffa-28a2-489d-b93a-c0f02a2bdbdd', - reviewChargeVersionId: '4940eaca-8cf1-410b-8a89-faf1faa8081b', - chargeReferenceId: '4e7f1824-3680-4df0-806f-c6d651ba4771', - aggregate: 1, - createdAt: new Date('2022-03-31'), - updatedAt: new Date('2024-05-01'), - amendedAggregate: 1, - chargeAdjustment: 1, - amendedChargeAdjustment: 1, - abatementAgreement: 1, - winterDiscount: false, - twoPartTariffAgreement: false, - canalAndRiverTrustAgreement: false, - authorisedVolume: 32, - amendedAuthorisedVolume: 32, - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2023-03-31') - }, - reviewChargeElements: [{ amendedAllocated: 0.00018 }], - chargeReference: { - volume: 32, - chargeCategoryId: 'c037ad9a-d3b4-4b1b-8ac9-1cd2b46d152f', - supportedSourceName: null, - waterCompanyCharge: null, - chargeCategory: { - reference: '4.6.12', - shortDescription: 'High loss, non-tidal, restricted water, greater than 15 up to and including 50 ML/yr, Tier 2 model' - } - } - } -} From fa8ee96ee09c6a1f66d580d88924965db00465f6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:26:40 +0000 Subject: [PATCH 110/147] Move, rename & refactor review chg elmnt presenter test --- .../review-charge-element.presenter.test.js | 70 ++++++++++ .../match-details.presenter.test.js | 122 ------------------ 2 files changed, 70 insertions(+), 122 deletions(-) create mode 100644 test/presenters/bill-runs/review/review-charge-element.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/match-details.presenter.test.js diff --git a/test/presenters/bill-runs/review/review-charge-element.presenter.test.js b/test/presenters/bill-runs/review/review-charge-element.presenter.test.js new file mode 100644 index 0000000000..54dd22a55c --- /dev/null +++ b/test/presenters/bill-runs/review/review-charge-element.presenter.test.js @@ -0,0 +1,70 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const ReviewChargeElementPresenter = require('../../../../app/presenters/bill-runs/review/review-charge-element.presenter.js') + +describe('Bill Runs Review - Review Charge Element presenter', () => { + const elementIndex = 1 + + let reviewChargeElement + + beforeEach(() => { + reviewChargeElement = BillRunsReviewFixture.reviewChargeElement() + }) + + describe('when provided with a ReviewChargeElement', () => { + it('correctly presents the data', () => { + const result = ReviewChargeElementPresenter.go(reviewChargeElement, elementIndex) + + expect(result).to.equal({ + authorisedVolume: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementCount: 1, + elementIndex: 1, + financialPeriod: '2023 to 2024', + issues: ['Aggregate'], + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + status: 'review' + }) + }) + }) + + describe('the "matchedReturns" property', () => { + describe('the "purpose" property', () => { + it("returns the matched return's tertiary purpose description", () => { + const result = ReviewChargeElementPresenter.go(reviewChargeElement, elementIndex) + + expect(result.matchedReturns[0].purpose).to.equal('Spray Irrigation - Direct') + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/match-details.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/match-details.presenter.test.js deleted file mode 100644 index bae41f8c6e..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/match-details.presenter.test.js +++ /dev/null @@ -1,122 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const MatchDetailsPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/match-details.presenter.js') - -describe('Match Details presenter', () => { - describe('when there is data to be presented for the view match details page', () => { - const billRun = _billRun() - const reviewChargeElement = _reviewChargeElementData() - const licenceId = '5aa8e752-1a5c-4b01-9112-d92a543b70d1' - - it('correctly presents the data', async () => { - const result = MatchDetailsPresenter.go(billRun, reviewChargeElement, licenceId) - - expect(result).to.equal({ - billRunId: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023', - chargePeriod: '1 April 2022 to 5 June 2022', - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - chargeElement: { - chargeElementId: 'b4d70c89-de1b-4f68-a47f-832b338ac044', - description: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - status: 'ready', - billableVolume: 0, - authorisedVolume: 200, - issues: [] - }, - matchedReturns: [ - { - returnId: 'v1:1:01/57/14/1646:15584914:2022-04-01:2023-03-31', - reference: '10031343', - dates: '1 April 2022 to 6 May 2022', - purpose: 'Spray Irrigation - Direct', - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - returnStatus: 'completed', - returnTotal: '0 ML / 0 ML', - issues: [''], - returnLink: '/returns/return?id=v1:1:01/57/14/1646:15584914:2022-04-01:2023-03-31', - absPeriod: '1 April to 31 March' - } - ] - }) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeElementData () { - return { - id: 'b4d70c89-de1b-4f68-a47f-832b338ac044', - reviewChargeReferenceId: '9e5d87d7-073e-420e-b12d-73ca220dd8ef', - chargeElementId: 'b345f1f1-496b-4049-a647-6bcd123dcf68', - allocated: 10, - amendedAllocated: 0, - chargeDatesOverlap: false, - issues: null, - status: 'ready', - createdAt: new Date('2024-04-02'), - updatedAt: new Date('2024-04-02'), - reviewReturns: [ - { - id: 'c4cdbfa9-4528-4776-b62f-fa667b797717', - reviewLicenceId: '674ffa02-51be-4caa-b25e-cc1fea1ac057', - returnId: 'v1:1:01/57/14/1646:15584914:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: [{ - tertiary: { code: '400', description: 'Spray Irrigation - Direct' } - }], - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date('2022-04-01'), - endDate: new Date('2022-05-06'), - issues: null, - createdAt: new Date('2024-04-02'), - updatedAt: new Date('2024-04-02'), - returnLog: { - periodEndDay: 31, - periodEndMonth: 3, - periodStartDay: 1, - periodStartMonth: 4 - } - } - ], - chargeElement: { - description: 'Trickle Irrigation - Direct', - abstractionPeriodStartDay: 1, - abstractionPeriodStartMonth: 4, - abstractionPeriodEndDay: 31, - abstractionPeriodEndMonth: 3, - authorisedAnnualQuantity: 200 - }, - reviewChargeReference: { - id: '9e5d87d7-073e-420e-b12d-73ca220dd8ef', - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-05') - } - } - } -} From 5be548e6b3cea1b927b0fc2a1dc20696c7beab1f Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:27:21 +0000 Subject: [PATCH 111/147] Move, rename & refactor remove presenter test --- .../bill-runs/review/remove.presenter.test.js | 38 ++++++++++++++++++ .../remove-bill-run-licence.presenter.test.js | 39 ------------------- 2 files changed, 38 insertions(+), 39 deletions(-) create mode 100644 test/presenters/bill-runs/review/remove.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.test.js diff --git a/test/presenters/bill-runs/review/remove.presenter.test.js b/test/presenters/bill-runs/review/remove.presenter.test.js new file mode 100644 index 0000000000..0302481be8 --- /dev/null +++ b/test/presenters/bill-runs/review/remove.presenter.test.js @@ -0,0 +1,38 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const RemovePresenter = require('../../../../app/presenters/bill-runs/review/remove.presenter.js') + +describe('Bill Runs Review - Remove presenter', () => { + let removeReviewLicence + + beforeEach(() => { + removeReviewLicence = BillRunsReviewFixture.removeReviewLicence() + }) + + describe('when provided with the result of fetch remove review licence service', () => { + it('correctly presents the data', () => { + const result = RemovePresenter.go(removeReviewLicence) + + expect(result).to.equal({ + billRunNumber: 10001, + billRunStatus: 'review', + dateCreated: '22 October 2024', + financialYearPeriod: '2023 to 2024', + pageTitle: "You're about to remove 1/11/11/*11/1111 from the bill run", + region: 'Test Region', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763' + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.test.js deleted file mode 100644 index 75b2e5ae82..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.test.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const RemoveBillRunLicencePresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/remove-bill-run-licence.presenter.js') - -describe('Cancel Bill Run presenter', () => { - describe('when provided with bill run and licence data', () => { - const billRun = { - billRunNumber: 12345, - createdAt: new Date('2024-05-03'), - region: 'Test Region', - status: 'review', - toFinancialYearEnding: 2023 - } - const licenceId = '85a8e2d7-b73f-45a1-b5fd-ba5632b43442' - const licenceRef = '01/123/ABC' - - it('correctly presents the data', () => { - const result = RemoveBillRunLicencePresenter.go(billRun, licenceId, licenceRef) - - expect(result).to.equal({ - pageTitle: "You're about to remove 01/123/ABC from the bill run", - backLink: `../review/${licenceId}`, - billRunNumber: billRun.billRunNumber, - billRunStatus: billRun.status, - dateCreated: '3 May 2024', - financialYear: '2022 to 2023', - region: billRun.region - }) - }) - }) -}) From a276e6e8ba513c9c897634864aee8c2c1891fa42 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:27:54 +0000 Subject: [PATCH 112/147] Move & refactor review licence presenter test --- .../review/review-licence.presenter.test.js | 201 ++++++++ .../review-licence.presenter.test.js | 467 ------------------ 2 files changed, 201 insertions(+), 467 deletions(-) create mode 100644 test/presenters/bill-runs/review/review-licence.presenter.test.js delete mode 100644 test/presenters/bill-runs/two-part-tariff/review-licence.presenter.test.js diff --git a/test/presenters/bill-runs/review/review-licence.presenter.test.js b/test/presenters/bill-runs/review/review-licence.presenter.test.js new file mode 100644 index 0000000000..919212c8b4 --- /dev/null +++ b/test/presenters/bill-runs/review/review-licence.presenter.test.js @@ -0,0 +1,201 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Thing under test +const ReviewLicencePresenter = require('../../../../app/presenters/bill-runs/review/review-licence.presenter.js') + +describe('Bill Runs Review - Review Licence presenter', () => { + let reviewLicence + + beforeEach(() => { + reviewLicence = BillRunsReviewFixture.reviewLicence() + }) + + describe('when provided with the result of fetch review licence service', () => { + it('correctly presents the data', async () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result).to.equal({ + billRunId: '287aeb25-cf11-429d-8c6f-f98f06db021d', + chargeVersions: [ + { + billingAccountDetails: { + billingAccountId: 'f041c128-bb4d-4f67-8f97-e33d71d50842', + accountNumber: 'E99999999A', + accountName: 'Mr B Blobby Ltd', + contactName: null, + addressLines: [ + 'C/O Noel Edmonds', + 'Crinkley Bottom', + 'Cricket St Thomas', + 'Somerset', + 'TA20 1KL', + 'United Kingdom' + ] + }, + chargePeriod: '1 April 2023 to 31 March 2024', + chargeReferences: [ + { + billableReturnsWarning: false, + chargeCategory: 'Charge reference 4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + id: '6c70461b-3f83-47b1-9538-8305e82b34eb', + chargeElements: [ + { + billableReturns: '0 ML / 9.092 ML', + chargePeriods: ['1 April 2023 to 30 September 2023'], + returnVolumes: ['0 ML (10030495)'], + description: 'Spray Irrigation - Direct', + elementCount: 1, + elementIndex: 1, + status: 'review', + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + issues: ['Aggregate'], + purpose: 'Spray Irrigation - Direct' + } + ], + chargeReferenceLinkTitle: 'Change details', + totalBillableReturns: '0 ML / 9.092 ML' + } + ], + description: '1 charge reference with 1 two-part tariff charge element', + financialPeriod: '2023 to 2024' + } + ], + elementsInReview: true, + licenceHolder: 'Licence Holder Ltd', + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + licenceRef: '1/11/11/*11/1111', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + pageTitle: 'Licence 1/11/11/*11/1111', + progress: false, + region: 'South West', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + status: 'review', + unmatchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Lost Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Storage', + reference: '11142961', + returnId: 'v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ] + }) + }) + + describe('the "chargeVersions" property', () => { + describe('the "chargeReferences" property', () => { + describe('the "chargeReferenceLinkTitle" property', () => { + describe('when a review charge reference has an aggregate (not equal to 1)', () => { + beforeEach(() => { + reviewLicence.reviewChargeVersions[0].reviewChargeReferences[0].aggregate = 0.5 + reviewLicence.reviewChargeVersions[0].reviewChargeReferences[0].chargeAdjustment = 1 + }) + + it('returns "Change details"', () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result.chargeVersions[0].chargeReferences[0].chargeReferenceLinkTitle).to.equal('Change details') + }) + }) + + describe('when a review charge reference has a chargeAdjustment (not equal to 1)', () => { + beforeEach(() => { + reviewLicence.reviewChargeVersions[0].reviewChargeReferences[0].aggregate = 1 + reviewLicence.reviewChargeVersions[0].reviewChargeReferences[0].chargeAdjustment = 0.5 + }) + + it('returns "Change details"', () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result.chargeVersions[0].chargeReferences[0].chargeReferenceLinkTitle).to.equal('Change details') + }) + }) + + describe('when a review charge reference neither an aggregate or charge adjustment (both equal 1)', () => { + beforeEach(() => { + reviewLicence.reviewChargeVersions[0].reviewChargeReferences[0].aggregate = 1 + reviewLicence.reviewChargeVersions[0].reviewChargeReferences[0].chargeAdjustment = 1 + }) + + it('returns "View details"', () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result.chargeVersions[0].chargeReferences[0].chargeReferenceLinkTitle).to.equal('View details') + }) + }) + }) + + describe('the "billableReturnsWarning" property', () => { + describe("when the sum allocated to a charge reference's charge elements is less than its authorised volume", () => { + it('returns false', () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result.chargeVersions[0].chargeReferences[0].billableReturnsWarning).to.equal(false) + }) + }) + + describe("when the sum allocated to a charge reference's charge elements equal to its authorised volume", () => { + beforeEach(() => { + reviewLicence + .reviewChargeVersions[0] + .reviewChargeReferences[0] + .reviewChargeElements[0] + .amendedAllocated = 9.092 + }) + + it('returns false', () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result.chargeVersions[0].chargeReferences[0].billableReturnsWarning).to.equal(false) + }) + }) + + describe("when the sum allocated to a charge reference's charge elements is greater than its authorised volume", () => { + beforeEach(() => { + reviewLicence + .reviewChargeVersions[0] + .reviewChargeReferences[0] + .reviewChargeElements[0] + .amendedAllocated = 10 + }) + + it('returns true', () => { + const result = ReviewLicencePresenter.go(reviewLicence) + + expect(result.chargeVersions[0].chargeReferences[0].billableReturnsWarning).to.equal(true) + }) + }) + }) + }) + }) + }) +}) diff --git a/test/presenters/bill-runs/two-part-tariff/review-licence.presenter.test.js b/test/presenters/bill-runs/two-part-tariff/review-licence.presenter.test.js deleted file mode 100644 index 87fef7ee9c..0000000000 --- a/test/presenters/bill-runs/two-part-tariff/review-licence.presenter.test.js +++ /dev/null @@ -1,467 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillingAccountModel = require('../../../../app/models/billing-account.model.js') - -// Thing under test -const ReviewLicencePresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/review-licence.presenter.js') - -describe('Review Licence presenter', () => { - let billRun - let licence - - describe('when there is data to be presented for the review licence page', () => { - beforeEach(() => { - billRun = _billRun() - licence = _licenceData() - }) - - it('correctly presents the data', async () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result).to.equal({ - billRunId: '6620135b-0ecf-4fd4-924e-371f950c0526', - region: 'Anglian', - licence: { - licenceId: '786f0d83-eaf7-43c3-9de5-ec59e3de05ee', - licenceRef: '01/49/80/4608', - progress: false, - status: 'ready', - licenceHolder: 'Licence Holder Ltd' - }, - elementsInReview: false, - matchedReturns: [ - { - returnId: 'v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - reference: '10031343', - dates: '1 April 2022 to 6 May 2022', - returnStatus: 'completed', - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - purpose: 'Site description', - returnTotal: '0 ML / 0 ML', - issues: [''], - returnLink: '/returns/return?id=v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - absPeriod: '1 April to 31 March' - } - ], - unmatchedReturns: [ - { - dates: '1 April 2022 to 6 May 2022', - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - issues: [''], - purpose: 'Site description', - reference: '10031343', - returnId: 'v2:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnLink: '/returns/return?id=v2:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnStatus: 'completed', - returnTotal: '0 / 0 ML', - absPeriod: '1 April to 31 March' - } - ], - chargeData: [ - { - financialYear: '2022 to 2023', - chargePeriodDate: '1 April 2022 to 5 June 2022', - chargeElementCount: 1, - billingAccountDetails: { - billingAccountId: 'a17ae69b-8074-4d27-80bf-074f4c79a05a', - accountNumber: 'E88896464A', - accountName: 'Furland Farm', - contactName: null, - addressLines: [ - 'Furland Farm', - 'Furland', - 'Crewkerne', - 'Somerset', - 'TA18 7TT', - 'England' - ] - }, - chargeReferences: [ - { - chargeCategory: 'Charge reference 4.6.7', - chargeDescription: 'High loss, non-tidal, greater than 15 up to and including 50 ML/yr', - totalBillableReturns: '0 ML / 200 ML', - billableReturnsWarning: false, - id: 'b2af5935-4b65-4dce-9f75-9073798f6375', - chargeReferenceLink: { linkName: 'View details' }, - chargeElements: [ - { - elementNumber: 'Element 1 of 1', - elementStatus: 'ready', - elementDescription: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - purpose: 'Make-up or top up water', - issues: [''], - billableReturns: '0 ML / 200 ML', - returnVolume: ['0 ML (10031343)'], - reviewChargeElementId: '8bc0cd32-400e-4a45-9dd7-fbce3d486031' - } - ] - } - ] - } - ] - }) - }) - - describe('the "issues" property', () => { - describe('when the charge element has multiple issues', () => { - beforeEach(() => { - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].reviewChargeElements[0].issues = 'Over abstraction, no returns' - }) - - it('correctly splits the issues into an array', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].chargeElements[0].issues).to.equal(['Over abstraction', 'no returns']) - }) - }) - - describe('when the matched returns has multiple issues', () => { - beforeEach(() => { - licence[0].reviewReturns[0].issues = 'Over abstraction, no returns' - }) - - it('correctly splits the issues into an array', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.matchedReturns[0].issues).to.equal(['Over abstraction', 'no returns']) - }) - }) - - describe('when the unmatched returns has multiple issues', () => { - beforeEach(() => { - licence[0].reviewReturns[1].issues = 'Over abstraction, no returns' - }) - - it('correctly splits the issues into an array', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.unmatchedReturns[0].issues).to.equal(['Over abstraction', 'no returns']) - }) - }) - }) - - describe('the "returnStatus" property', () => { - describe('when a return has a status of "due"', () => { - beforeEach(() => { - licence[0].reviewReturns[0].returnStatus = 'due' - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].reviewChargeElements[0].reviewReturns[0].returnStatus = 'due' - }) - - it('changes the status text to "overdue"', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.matchedReturns[0].returnStatus).to.equal('overdue') - }) - - it('formats the returns total correctly', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.matchedReturns[0].returnTotal).to.equal('/') - }) - - it('formats the charge elements return total correctly', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].chargeElements[0].returnVolume).to.equal(['overdue (10031343)']) - }) - - it('formats the returns link correctly', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.matchedReturns[0].returnLink).to.equal('/return/internal?returnId=v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31') - }) - }) - }) - - describe('the "underQuery" property', () => { - describe('when a return is under query', () => { - beforeEach(() => { - licence[0].reviewReturns[0].underQuery = true - }) - - it('changes the returns status to be "under query"', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.matchedReturns[0].returnStatus).to.equal('query') - }) - }) - }) - - describe('the "adjustment" properties', () => { - describe('when a review charge reference has an aggregate', () => { - beforeEach(() => { - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].aggregate = 0.5 - }) - - it('changes the chargeReferenceLink to "Change details"', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].chargeReferenceLink.linkName).to.equal('Change details') - }) - }) - - describe('when a review charge reference has a charge factor adjustment', () => { - beforeEach(() => { - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].chargeAdjustment = 0.5 - }) - - it('changes the chargeReferenceLink to "Change details"', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].chargeReferenceLink.linkName).to.equal('Change details') - }) - }) - - describe('when a review charge reference has an aggregate and charge factor adjustment', () => { - beforeEach(() => { - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].aggregate = 0.5 - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].chargeAdjustment = 0.5 - }) - - it('changes the chargeReferenceLink to "Change details"', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].chargeReferenceLink.linkName).to.equal('Change details') - }) - }) - - describe('when a review charge reference does not have an aggregate or charge factor adjustment', () => { - it('changes the chargeReferenceLink to "View details"', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].chargeReferenceLink.linkName).to.equal('View details') - }) - }) - }) - - describe('the "billableReturnsWarning" property', () => { - describe('when a review charge reference has an authorised volume greater than the sum of its charge element quantities', () => { - it('sets the "billableReturnsWarning" to false', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].billableReturnsWarning).to.equal(false) - }) - }) - - describe('when a review charge reference has an authorised volume less than the sum of its charge element quantities', () => { - beforeEach(() => { - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].amendedAuthorisedVolume = 10 - licence[0].reviewChargeVersions[0].reviewChargeReferences[0].reviewChargeElements[0].amendedAllocated = 50 - }) - - it('sets the "billableReturnsWarning" to true', () => { - const result = ReviewLicencePresenter.go(billRun, licence) - - expect(result.chargeData[0].chargeReferences[0].billableReturnsWarning).to.equal(true) - }) - }) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023, - region: { - displayName: 'Anglian' - } - } -} - -function _licenceData () { - const billingAccountDetails = BillingAccountModel.fromJson({ - id: 'a17ae69b-8074-4d27-80bf-074f4c79a05a', - accountNumber: 'E88896464A', - company: { - id: 'e44491db-2b33-4473-9c3a-b57aceabb6e8', - name: 'Furland Farm', - type: 'organisation' - }, - billingAccountAddresses: [ - { - id: 'eb5cb54a-0b51-4e4a-8472-dab993eb6157', - billingAccountId: 'a17ae69b-8074-4d27-80bf-074f4c79a05a', - addressId: 'cc32fefd-7f3e-4581-b437-78a3fae66d4b', - startDate: new Date('2016-05-20'), - endDate: null, - companyId: null, - contactId: null, - company: null, - contact: null, - address: { - id: 'cc32fefd-7f3e-4581-b437-78a3fae66d4b', - address1: 'Furland Farm', - address2: 'Furland', - address3: null, - address4: null, - address5: 'Crewkerne', - address6: 'Somerset', - postcode: 'TA18 7TT', - country: 'England' - } - } - ] - }) - - return [{ - id: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - billRunId: '82772a06-c8ce-45f7-8504-dd20ea8824e4', - licenceId: '786f0d83-eaf7-43c3-9de5-ec59e3de05ee', - licenceRef: '01/49/80/4608', - licenceHolder: 'Licence Holder Ltd', - issues: '', - status: 'ready', - progress: false, - hasReviewStatus: false, - reviewReturns: [{ - id: '2264f443-5c16-4ca9-8522-f63e2d4e38be', - reviewLicenceId: '78a99c1c-26d3-4163-ab58-084cd78594ab', - returnId: 'v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: [{ - tertiary: { - description: 'Site description' - } - }], - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date(' 2022-04-01'), - endDate: new Date('2022-05-06'), - issues: '', - reviewChargeElements: [{ - id: 'e840f418-ca6b-4d96-9f36-bf684c78590f', - reviewChargeReferenceId: '7759e0f9-5763-4b94-8d45-0621aea3edc1', - chargeElementId: 'b1cd4f98-ad96-4901-9e21-4432f032492a', - allocated: 0, - chargeDatesOverlap: false, - issues: '', - status: 'ready' - }], - returnLog: { - periodStartDay: 1, - periodStartMonth: 4, - periodEndDay: 31, - periodEndMonth: 3 - } - }, - { - id: '4864f643-5c16-5ca9-8512-f63e1d4e58be', - reviewLicenceId: '78a99c1c-26d3-4163-ab58-084cd78594ab', - returnId: 'v2:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: [{ - tertiary: { - description: 'Site description' - } - }], - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date(' 2022-04-01'), - endDate: new Date('2022-05-06'), - issues: '', - reviewChargeElements: [], - returnLog: { - periodStartDay: 1, - periodStartMonth: 4, - periodEndDay: 31, - periodEndMonth: 3 - } - }], - reviewChargeVersions: [{ - id: '3de5634a-da26-4241-87e9-7248a4b83a69', - reviewLicenceId: 'd9e78306-bf65-4020-b279-5ae471cea4e6', - chargeVersionId: 'd103bb54-1819-4e77-b3d9-bc8913454e06', - changeReason: 'Strategic review of charges (SRoC)', - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-05'), - reviewChargeReferences: [{ - id: 'b2af5935-4b65-4dce-9f75-9073798f6375', - reviewChargeVersionId: 'bd16e7b0-c2a3-4258-b873-b965fd74cdf5', - chargeReferenceId: '82ce8695-5841-41b0-a1e7-d016407adad4', - aggregate: 1, - authorisedVolume: 200, - amendedAuthorisedVolume: 200, - chargeAdjustment: 1, - createdAt: new Date('2024-03-18'), - updatedAt: new Date('2024-03-18'), - chargeReference: { - chargeCategoryId: 'f100dc23-c6a7-4efa-af4f-80618260b32e', - chargeCategory: { - reference: '4.6.7', - shortDescription: 'High loss, non-tidal, greater than 15 up to and including 50 ML/yr' - } - }, - reviewChargeElements: [{ - id: '8bc0cd32-400e-4a45-9dd7-fbce3d486031', - reviewChargeReferenceId: '2210bb45-1efc-4e69-85cb-c8cc6e75c4fd', - chargeElementId: 'b1001716-cfb4-43c6-91f0-1863f4529223', - allocated: 10, - amendedAllocated: 0, - chargeDatesOverlap: false, - issues: '', - status: 'ready', - chargeElement: { - description: 'Trickle Irrigation - Direct', - abstractionPeriodStartDay: 1, - abstractionPeriodStartMonth: 4, - abstractionPeriodEndDay: 31, - abstractionPeriodEndMonth: 3, - authorisedAnnualQuantity: 200, - purpose: { - description: 'Make-up or top up water' - } - }, - reviewReturns: [{ - id: '2264f443-5c16-4ca9-8522-f63e2d4e38be', - reviewLicenceId: '78a99c1c-26d3-4163-ab58-084cd78594ab', - returnId: 'v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: {}, - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date(' 2022-04-01'), - endDate: new Date('2022-05-06'), - issues: '' - }] - }] - }], - chargeVersion: { - billingAccountId: '67d7cacb-5d10-4a08-b7f8-e6ce98cbf4c8' - }, - billingAccountDetails - }] - }] -} From d6967d77bc552508235d5730a99041d26ff7a4e9 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:28:25 +0000 Subject: [PATCH 113/147] Update review bill run presenter test --- .../bill-runs/review/review-bill-run.presenter.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/presenters/bill-runs/review/review-bill-run.presenter.test.js b/test/presenters/bill-runs/review/review-bill-run.presenter.test.js index 5112850f21..7d082f6f07 100644 --- a/test/presenters/bill-runs/review/review-bill-run.presenter.test.js +++ b/test/presenters/bill-runs/review/review-bill-run.presenter.test.js @@ -10,7 +10,7 @@ const { expect } = Code // Thing under test const ReviewBillRunPresenter = require('../../../../app/presenters/bill-runs/review/review-bill-run.presenter.js') -describe('Review Bill Run presenter', () => { +describe('Bill Runs Review - Review Bill Run presenter', () => { describe('when there is data to be presented for review', () => { let filterIssues let filterLicenceHolderNumber @@ -192,7 +192,7 @@ function _testLicences () { return [ // Licence with no issues { - licenceId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', + id: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', licenceRef: '1/11/11/*11/1111', licenceHolder: 'Big Farm Ltd', issues: '', @@ -201,7 +201,7 @@ function _testLicences () { }, // Licence with a single issue { - licenceId: '395bdc01-605b-44f5-9d90-5836cc013799', + id: '395bdc01-605b-44f5-9d90-5836cc013799', licenceRef: '2/22/22/*S2/2222', licenceHolder: 'Bob Bobbles', issues: 'Abstraction outside period', @@ -210,7 +210,7 @@ function _testLicences () { }, // Licence with multiple issues { - licenceId: 'fdae33da-9195-4b97-976a-9791bc4f6b66', + id: 'fdae33da-9195-4b97-976a-9791bc4f6b66', licenceRef: '3/33/33/*3/3333', licenceHolder: 'Farmer Palmer', issues: 'Abstraction outside period, Over abstraction, Overlap of charge dates', From 6e8796b459d2c12d38fa487884cb7b9e15da41f8 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:29:00 +0000 Subject: [PATCH 114/147] Move, rename & refactor factors validator test --- .../review/factors.validator.test.js | 155 ++++++++++++++ .../adjustment-factor.validator.test.js | 194 ------------------ 2 files changed, 155 insertions(+), 194 deletions(-) create mode 100644 test/validators/bill-runs/review/factors.validator.test.js delete mode 100644 test/validators/bill-runs/two-part-tariff/adjustment-factor.validator.test.js diff --git a/test/validators/bill-runs/review/factors.validator.test.js b/test/validators/bill-runs/review/factors.validator.test.js new file mode 100644 index 0000000000..b563bbf378 --- /dev/null +++ b/test/validators/bill-runs/review/factors.validator.test.js @@ -0,0 +1,155 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, beforeEach } = exports.lab = Lab.script() +const { expect } = Code + +// Thing under test +const FactorsValidator = require('../../../../app/validators/bill-runs/review/factors.validator.js') + +describe('Bill Runs Review - Factors validator', () => { + let payload + + describe('when valid data is provided', () => { + beforeEach(() => { + payload = { amendedAggregate: 0.5, amendedChargeAdjustment: 0.5 } + }) + + it('confirms the data is valid', () => { + const result = FactorsValidator.go(payload) + + expect(result.value).to.exist() + expect(result.error).not.to.exist() + }) + }) + + describe('when invalid data is provided', () => { + describe('because nothing was entered', () => { + beforeEach(() => { + // NOTE: Confirmed in manual testing. Payload mya have no properties, but it itself is never undefined + payload = {} + }) + + it('fails the validation with the messages "Enter an aggregate factor" and "Enter a charge factor"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Enter an aggregate factor') + expect(result.error.details[1].message).to.equal('Enter a charge factor') + }) + }) + + describe('and the aggregate factor is the issue', () => { + beforeEach(() => { + payload = { amendedChargeAdjustment: 0.5 } + }) + + describe('because nothing was entered', () => { + it('fails the validation with the message "Enter a aggregate factor"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Enter an aggregate factor') + }) + }) + + describe('because the user entered text', () => { + beforeEach(() => { + payload.amendedAggregate = 'Hello World' + }) + + it('fails the validation with the message "The aggregate factor must be a number"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('The aggregate factor must be a number') + }) + }) + + describe('because the user entered too many decimal places', () => { + beforeEach(() => { + payload.amendedAggregate = 0.1234567890123456 + }) + + it('fails the validation with the message "The aggregate factor must not have more than 15 decimal places"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal( + 'The aggregate factor must not have more than 15 decimal places' + ) + }) + }) + + describe('because the user entered a value less than 0', () => { + beforeEach(() => { + payload.amendedAggregate = -1 + }) + + it('fails the validation with the message "The aggregate factor must be greater than 0"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('The aggregate factor must be greater than 0') + }) + }) + }) + + describe('and the charge factor is the issue', () => { + beforeEach(() => { + payload = { amendedAggregate: 0.5 } + }) + + describe('because nothing was entered', () => { + it('fails the validation with the message "Enter a charge factor"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('Enter a charge factor') + }) + }) + + describe('because the user entered text', () => { + beforeEach(() => { + payload.amendedChargeAdjustment = 'Hello World' + }) + + it('fails the validation with the message "The charge factor must be a number"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('The charge factor must be a number') + }) + }) + + describe('because the user entered too many decimal places', () => { + beforeEach(() => { + payload.amendedChargeAdjustment = 0.5555555555555555 + }) + + it('fails the validation with the message "The charge factor must not have more than 15 decimal places"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('The charge factor must not have more than 15 decimal places') + }) + }) + + describe('because the user entered a value less than 0', () => { + beforeEach(() => { + payload.amendedChargeAdjustment = -1 + }) + + it('fails the validation with the message "The charge factor must be greater than 0"', () => { + const result = FactorsValidator.go(payload) + + expect(result.error).to.exist() + expect(result.error.details[0].message).to.equal('The charge factor must be greater than 0') + }) + }) + }) + }) +}) diff --git a/test/validators/bill-runs/two-part-tariff/adjustment-factor.validator.test.js b/test/validators/bill-runs/two-part-tariff/adjustment-factor.validator.test.js deleted file mode 100644 index fbf7be2133..0000000000 --- a/test/validators/bill-runs/two-part-tariff/adjustment-factor.validator.test.js +++ /dev/null @@ -1,194 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Thing under test -const AdjustmentFactorValidator = require('../../../../app/validators/bill-runs/two-part-tariff/adjustment-factor.validator.js') - -describe('Adjustment Factor validator', () => { - const maxNumberOfDecimals = 15 - - let payload - let validationType - - describe('when a valid payload is provided', () => { - describe('because there is a valid aggregate factor', () => { - beforeEach(() => { - payload = { - amendedAggregateFactor: 0.5 - } - - validationType = 'aggregate' - }) - - it('confirms the payload is valid', () => { - const result = AdjustmentFactorValidator.go(payload.amendedAggregateFactor, maxNumberOfDecimals, validationType) - - expect(result.error).not.to.exist() - }) - }) - - describe('because there is a valid charge factor', () => { - beforeEach(() => { - payload = { - amendedChargeAdjustment: 0.5 - } - - validationType = 'charge' - }) - - it('confirms the payload is valid', () => { - const result = AdjustmentFactorValidator.go( - payload.amendedChargeAdjustment, - maxNumberOfDecimals, - validationType - ) - - expect(result.error).not.to.exist() - }) - }) - }) - - describe('when an invalid payload is provided for the aggregate factor', () => { - describe('because nothing was entered', () => { - beforeEach(() => { - payload = undefined - - validationType = 'aggregate' - }) - - it('fails the validation with the message "Enter a aggregate factor"', () => { - const result = AdjustmentFactorValidator.go(payload, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('Enter a aggregate factor') - }) - }) - - describe('because the user entered text', () => { - beforeEach(() => { - payload = { - amendedAggregateFactor: 'Hello World' - } - - validationType = 'aggregate' - }) - - it('fails the validation with the message "The aggregate factor must be a number"', () => { - const result = AdjustmentFactorValidator.go(payload.amendedAggregateFactor, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('The aggregate factor must be a number') - }) - }) - - describe('because the user entered too many decimal places', () => { - beforeEach(() => { - payload = { - amendedAggregateFactor: 0.1234567890123456 - } - - validationType = 'aggregate' - }) - - it('fails the validation with the message "The aggregate factor must not have more than 15 decimal places"', () => { - const result = AdjustmentFactorValidator.go(payload.amendedAggregateFactor, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal( - 'The aggregate factor must not have more than 15 decimal places' - ) - }) - }) - - describe('because the user entered a value less than 0', () => { - beforeEach(() => { - payload = { - amendedAggregateFactor: -1 - } - - validationType = 'aggregate' - }) - - it('fails the validation with the message "The aggregate factor must be greater than 0"', () => { - const result = AdjustmentFactorValidator.go(payload.amendedAggregateFactor, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('The aggregate factor must be greater than 0') - }) - }) - }) - - describe('when an invalid payload is provided for the charge factor', () => { - describe('because nothing was entered', () => { - beforeEach(() => { - payload = undefined - - validationType = 'charge' - }) - - it('fails the validation with the message "Enter a charge factor"', () => { - const result = AdjustmentFactorValidator.go(payload, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('Enter a charge factor') - }) - }) - - describe('because the user entered text', () => { - beforeEach(() => { - payload = { - amendedChargeFactor: 'Hello World' - } - - validationType = 'charge' - }) - - it('fails the validation with the message "The charge factor must be a number"', () => { - const result = AdjustmentFactorValidator.go(payload.amendedChargeFactor, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('The charge factor must be a number') - }) - }) - - describe('because the user entered too many decimal places', () => { - beforeEach(() => { - payload = { - amendedChargeFactor: 0.5555555555555555 - } - - validationType = 'charge' - }) - - it('fails the validation with the message "The charge factor must not have more than 15 decimal places"', () => { - const result = AdjustmentFactorValidator.go(payload.amendedChargeFactor, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('The charge factor must not have more than 15 decimal places') - }) - }) - - describe('because the user entered a value less than 0', () => { - beforeEach(() => { - payload = { - amendedChargeFactor: -1 - } - - validationType = 'charge' - }) - - it('fails the validation with the message "The charge factor must be greater than 0"', () => { - const result = AdjustmentFactorValidator.go(payload.amendedChargeFactor, maxNumberOfDecimals, validationType) - - expect(result.error).to.exist() - expect(result.error.details[0].message).to.equal('The charge factor must be greater than 0') - }) - }) - }) -}) From e872f5b109350d344c0ed2ff9aecf76f34dc948a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:29:28 +0000 Subject: [PATCH 115/147] Move & refactor authorised validator test --- .../authorised.validator.test.js} | 53 +++++++------------ 1 file changed, 19 insertions(+), 34 deletions(-) rename test/validators/bill-runs/{two-part-tariff/authorised-volume.validator.test.js => review/authorised.validator.test.js} (57%) diff --git a/test/validators/bill-runs/two-part-tariff/authorised-volume.validator.test.js b/test/validators/bill-runs/review/authorised.validator.test.js similarity index 57% rename from test/validators/bill-runs/two-part-tariff/authorised-volume.validator.test.js rename to test/validators/bill-runs/review/authorised.validator.test.js index b8164521ce..1185d9ed42 100644 --- a/test/validators/bill-runs/two-part-tariff/authorised-volume.validator.test.js +++ b/test/validators/bill-runs/review/authorised.validator.test.js @@ -8,38 +8,32 @@ const { describe, it, beforeEach } = exports.lab = Lab.script() const { expect } = Code // Thing under test -const AuthorisedVolumeValidator = require('../../../../app/validators/bill-runs/two-part-tariff/authorised-volume.validator.js') +const AuthorisedValidator = require('../../../../app/validators/bill-runs/review/authorised.validator.js') -describe('Authorised Volume validator', () => { +describe('Bill Runs Review - Authorised validator', () => { let payload - describe('when a valid payload is provided', () => { - describe('because the user entered an authorised volume', () => { - beforeEach(() => { - payload = { - authorisedVolume: '10', - totalBillableReturns: '5' - } - }) + describe('when valid data is provided', () => { + beforeEach(() => { + payload = { amendedAuthorisedVolume: '10', totalBillableReturns: '5' } + }) - it('confirms the payload is valid', () => { - const result = AuthorisedVolumeValidator.go(payload) + it('confirms the data is valid', () => { + const result = AuthorisedValidator.go(payload) - expect(result.error).not.to.exist() - }) + expect(result.value).to.exist() + expect(result.error).not.to.exist() }) }) - describe('when an invalid payload is provided', () => { + describe('when invalid data is provided', () => { describe('because the user did not enter an authorised volume', () => { beforeEach(() => { - payload = { - totalBillableReturns: '5' - } + payload = { totalBillableReturns: '5' } }) it('fails the validation with the message "Enter an authorised volume"', () => { - const result = AuthorisedVolumeValidator.go(payload) + const result = AuthorisedValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('Enter an authorised volume') @@ -48,14 +42,11 @@ describe('Authorised Volume validator', () => { describe('because the user entered text', () => { beforeEach(() => { - payload = { - authorisedVolume: 'Hello World', - totalBillableReturns: '5' - } + payload = { amendedAuthorisedVolume: 'Hello World', totalBillableReturns: '5' } }) it('fails the validation with the message "The authorised volume must be a number"', () => { - const result = AuthorisedVolumeValidator.go(payload) + const result = AuthorisedValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The authorised volume must be a number') @@ -64,14 +55,11 @@ describe('Authorised Volume validator', () => { describe('because the user entered a number less than the totalBillableReturns', () => { beforeEach(() => { - payload = { - authorisedVolume: '5', - totalBillableReturns: '6' - } + payload = { amendedAuthorisedVolume: '5', totalBillableReturns: '6' } }) it('fails the validation with the message "The authorised volume must be greater than 6"', () => { - const result = AuthorisedVolumeValidator.go(payload) + const result = AuthorisedValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The authorised volume must be greater than 6') @@ -80,14 +68,11 @@ describe('Authorised Volume validator', () => { describe('because the user entered too many decimal places', () => { beforeEach(() => { - payload = { - authorisedVolume: '15.1234567', - totalBillableReturns: '5' - } + payload = { amendedAuthorisedVolume: '15.1234567', totalBillableReturns: '5' } }) it('fails the validation with the message "The authorised volume must not have more than 6 decimal places"', () => { - const result = AuthorisedVolumeValidator.go(payload) + const result = AuthorisedValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The authorised volume must not have more than 6 decimal places') From 4ffb4299127dc105eee77299e680b6712bcc5464 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:30:02 +0000 Subject: [PATCH 116/147] Move, rename & refactor edit validator test --- .../edit.validator.test.js} | 75 ++++++------------- 1 file changed, 24 insertions(+), 51 deletions(-) rename test/validators/bill-runs/{two-part-tariff/billable-returns.validator.test.js => review/edit.validator.test.js} (58%) diff --git a/test/validators/bill-runs/two-part-tariff/billable-returns.validator.test.js b/test/validators/bill-runs/review/edit.validator.test.js similarity index 58% rename from test/validators/bill-runs/two-part-tariff/billable-returns.validator.test.js rename to test/validators/bill-runs/review/edit.validator.test.js index 0b9b71ec94..4bd022d983 100644 --- a/test/validators/bill-runs/two-part-tariff/billable-returns.validator.test.js +++ b/test/validators/bill-runs/review/edit.validator.test.js @@ -8,54 +8,46 @@ const { describe, it, beforeEach } = exports.lab = Lab.script() const { expect } = Code // Thing under test -const BillableReturnsValidator = require('../../../../app/validators/bill-runs/two-part-tariff/billable-returns.validator.js') +const EditValidator = require('../../../../app/validators/bill-runs/review/edit.validator.js') -describe('Billable Returns validator', () => { +describe('Bill Runs Review - Edit validator', () => { let payload - describe('when a valid payload is provided', () => { + describe('when valid data is provided', () => { describe('because the user selected the authorised volume option', () => { beforeEach(() => { - payload = { - 'quantity-options': 25, - authorisedVolume: 30 - } + payload = { quantityOptions: 25, authorisedVolume: 30 } }) - it('confirms the payload is valid', () => { - const result = BillableReturnsValidator.go(payload) + it('confirms the data is valid', () => { + const result = EditValidator.go(payload) + expect(result.value).to.exist() expect(result.error).not.to.exist() }) }) - describe('because the user entered a valid volume (less than the authorised volume but greater than 0)', () => { + describe('because the user entered a valid custom volume (less than the authorised volume but greater than 0)', () => { beforeEach(() => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: 12, - authorisedVolume: 30 - } + payload = { quantityOptions: 'customQuantity', customQuantity: 12, authorisedVolume: 30 } }) - it('confirms the payload is valid', () => { - const result = BillableReturnsValidator.go(payload) + it('confirms the data is valid', () => { + const result = EditValidator.go(payload) expect(result.error).not.to.exist() }) }) }) - describe('when an invalid payload is provided', () => { + describe('when invalid data is provided', () => { describe('because the user did not select an option', () => { beforeEach(() => { - payload = { - authorisedVolume: 30 - } + payload = { authorisedVolume: 30 } }) it('fails the validation with the message "Select the billable quantity"', () => { - const result = BillableReturnsValidator.go(payload) + const result = EditValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('Select the billable quantity') @@ -65,14 +57,11 @@ describe('Billable Returns validator', () => { describe('because the user selected to enter a custom quantity', () => { describe('but entered no value', () => { beforeEach(() => { - payload = { - 'quantity-options': 'customQuantity', - authorisedVolume: 25 - } + payload = { quantityOptions: 'customQuantity', authorisedVolume: 25 } }) it('fails validation with the message "Enter the billable quantity"', () => { - const result = BillableReturnsValidator.go(payload) + const result = EditValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('Enter the billable quantity') @@ -81,15 +70,11 @@ describe('Billable Returns validator', () => { describe('but entered text', () => { beforeEach(() => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: 'Hello world', - authorisedVolume: 25 - } + payload = { quantityOptions: 'customQuantity', customQuantity: 'Hello world', authorisedVolume: 25 } }) it('fails validation with the message "The quantity must be a number"', () => { - const result = BillableReturnsValidator.go(payload) + const result = EditValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The quantity must be a number') @@ -98,15 +83,11 @@ describe('Billable Returns validator', () => { describe('but entered a number with more than 6 decimal places', () => { beforeEach(() => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: 12.3456789, - authorisedVolume: 25 - } + payload = { quantityOptions: 'customQuantity', customQuantity: 12.3456789, authorisedVolume: 25 } }) it('fails validation with the message "The quantity must contain no more than 6 decimal places"', () => { - const result = BillableReturnsValidator.go(payload) + const result = EditValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The quantity must contain no more than 6 decimal places') @@ -115,15 +96,11 @@ describe('Billable Returns validator', () => { describe('but entered a number less than 0', () => { beforeEach(() => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: -0.1, - authorisedVolume: 25 - } + payload = { quantityOptions: 'customQuantity', customQuantity: -0.1, authorisedVolume: 25 } }) it('fails validation with the message "The quantity must be zero or higher"', () => { - const result = BillableReturnsValidator.go(payload) + const result = EditValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The quantity must be zero or higher') @@ -132,15 +109,11 @@ describe('Billable Returns validator', () => { describe('but entered a number greater than the authorised annual quantity', () => { beforeEach(() => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: 40, - authorisedVolume: 25 - } + payload = { quantityOptions: 'customQuantity', customQuantity: 40, authorisedVolume: 25 } }) it('fails validation with the message "The quantity must be the same as or less than the authorised amount"', () => { - const result = BillableReturnsValidator.go(payload) + const result = EditValidator.go(payload) expect(result.error).to.exist() expect(result.error.details[0].message).to.equal('The quantity must be the same as or less than the authorised amount') From c355e92a9685dac991c47834d71b2cfe3734a0b6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:30:27 +0000 Subject: [PATCH 117/147] Move, rename & refactor authorised service test --- .../review/authorised.service.test.js | 48 ++++++++++++ .../amend-authorised-volume.service.test.js | 78 ------------------- 2 files changed, 48 insertions(+), 78 deletions(-) create mode 100644 test/services/bill-runs/review/authorised.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/amend-authorised-volume.service.test.js diff --git a/test/services/bill-runs/review/authorised.service.test.js b/test/services/bill-runs/review/authorised.service.test.js new file mode 100644 index 0000000000..8e02639e90 --- /dev/null +++ b/test/services/bill-runs/review/authorised.service.test.js @@ -0,0 +1,48 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') + +// Thing under test +const AuthorisedService = require('../../../../app/services/bill-runs/review/authorised.service.js') + +describe('Bill Runs Review - Authorised Service', () => { + let reviewChargeReference + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + it('returns page data for the view', async () => { + const result = await AuthorisedService.go(reviewChargeReference.id) + + expect(result).to.equal({ + pageTitle: 'Set the authorised volume', + amendedAuthorisedVolume: 9.092, + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + totalBillableReturns: 0 + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/amend-authorised-volume.service.test.js b/test/services/bill-runs/two-part-tariff/amend-authorised-volume.service.test.js deleted file mode 100644 index 623c99df66..0000000000 --- a/test/services/bill-runs/two-part-tariff/amend-authorised-volume.service.test.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Things we need to stub -const FetchAuthorisedVolumeService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js') - -// Thing under test -const AmendAuthorisedVolumeService = require('../../../../app/services/bill-runs/two-part-tariff/amend-authorised-volume.service.js') - -describe('Amend Authorised Volume Service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when given a billRun, licence, and a reviewChargeReferenceId', () => { - const reviewChargeReferenceId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - beforeEach(() => { - Sinon.stub(FetchAuthorisedVolumeService, 'go').resolves({ - billRun: _billRun(), - reviewChargeReference: _reviewChargeReferenceData() - }) - }) - - it('will fetch the charge reference data and return it once formatted by the presenter', async () => { - const result = await AmendAuthorisedVolumeService.go(billRunId, licenceId, reviewChargeReferenceId) - - // NOTE: The service mainly just regurgitates what the AmendAuthorisedVolumePresenter returns. So, we don't - // diligently check each property of the result because we know this will have been covered by the - // AmendAuthorisedVolumePresenter tests - expect(FetchAuthorisedVolumeService.go.called).to.be.true() - expect(result.billRunId).to.equal('cc4bbb18-0d6a-4254-ac2c-7409de814d7e') - expect(result.licenceId).to.equal('9a8a148d-b71e-463c-bea8-bc5e0a5d95e2') - expect(result.financialYear).to.equal('2022 to 2023') - expect(result.chargeReference.description).to.equal( - 'Medium loss, non-tidal, greater than 83 up to and including 142 ML/yr' - ) - }) - }) -}) - -function _billRun () { - return { - id: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeReferenceData () { - return { - id: '6b3d11f2-d361-4eaa-bce2-5561283bd023', - amendedAuthorisedVolume: 25.5, - chargeReference: { - chargeCategoryId: 'b4354db6-6699-4987-b4c8-d53ac2bf2250', - chargeCategory: { - shortDescription: 'Medium loss, non-tidal, greater than 83 up to and including 142 ML/yr', - minVolume: 83, - maxVolume: 142 - } - }, - reviewChargeElements: [{ - amendedAllocated: 15 - }], - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-01') - } - } -} From 15bb0e9652ddc9521487c9961da68b8d02dcb4f1 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:30:52 +0000 Subject: [PATCH 118/147] Move, rename & refactor edit service test --- .../bill-runs/review/edit.service.test.js | 52 +++++++++++++++++++ .../amend-billable-returns.service.test.js | 45 ---------------- 2 files changed, 52 insertions(+), 45 deletions(-) create mode 100644 test/services/bill-runs/review/edit.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/amend-billable-returns.service.test.js diff --git a/test/services/bill-runs/review/edit.service.test.js b/test/services/bill-runs/review/edit.service.test.js new file mode 100644 index 0000000000..91f7f8f98d --- /dev/null +++ b/test/services/bill-runs/review/edit.service.test.js @@ -0,0 +1,52 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeElementService = require('../../../../app/services/bill-runs/review/fetch-review-charge-element.service.js') + +// Thing under test +const EditService = require('../../../../app/services/bill-runs/review/edit.service.js') + +describe('Bill Runs Review - Edit Service', () => { + const elementIndex = 1 + + let reviewChargeElement + + beforeEach(() => { + reviewChargeElement = BillRunsReviewFixture.reviewChargeElement() + + Sinon.stub(FetchReviewChargeElementService, 'go').resolves(reviewChargeElement) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + it('returns page data for the view', async () => { + const result = await EditService.go(reviewChargeElement.id, elementIndex) + + expect(result).to.equal({ + pageTitle: 'Set the billable returns quantity for this bill run', + authorisedQuantity: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementIndex: 1, + financialPeriod: '2023 to 2024', + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/amend-billable-returns.service.test.js b/test/services/bill-runs/two-part-tariff/amend-billable-returns.service.test.js deleted file mode 100644 index e36f8aad72..0000000000 --- a/test/services/bill-runs/two-part-tariff/amend-billable-returns.service.test.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Things we need to stub -const AmendBillableReturnsPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js') -const FetchMatchDetailsService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-match-details.service.js') - -// Thing under test -const AmendBillableReturnsService = require('../../../../app/services/bill-runs/two-part-tariff/amend-billable-returns.service.js') - -describe('Amend Billable Returns Service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when given a billRun, licence and chargeElement ID', () => { - const reviewChargeElementId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - beforeEach(() => { - Sinon.stub(FetchMatchDetailsService, 'go').resolves({ - billRun: 'bill run data', - reviewChargeElement: 'charge element details' - }) - - Sinon.stub(AmendBillableReturnsPresenter, 'go').resolves('page data') - }) - - it('will fetch the charge element data and return it once formatted by the presenter', async () => { - const result = await AmendBillableReturnsService.go(billRunId, licenceId, reviewChargeElementId) - - expect(FetchMatchDetailsService.go.called).to.be.true() - expect(AmendBillableReturnsPresenter.go.called).to.be.true() - expect(result).to.equal('page data') - }) - }) -}) From 09fb5c457a69576c8a6bb39f9429c308fe2739fb Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:31:26 +0000 Subject: [PATCH 119/147] Move, rename & refactor factors service test --- .../bill-runs/review/factors.service.test.js | 49 ++++++++++ .../amend-adjustment-factor.service.test.js | 91 ------------------- 2 files changed, 49 insertions(+), 91 deletions(-) create mode 100644 test/services/bill-runs/review/factors.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.test.js diff --git a/test/services/bill-runs/review/factors.service.test.js b/test/services/bill-runs/review/factors.service.test.js new file mode 100644 index 0000000000..6d611995f6 --- /dev/null +++ b/test/services/bill-runs/review/factors.service.test.js @@ -0,0 +1,49 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') + +// Thing under test +const FactorsService = require('../../../../app/services/bill-runs/review/factors.service.js') + +describe('Bill Runs Review - Factors Service', () => { + let reviewChargeReference + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + it('returns page data for the view', async () => { + const result = await FactorsService.go(reviewChargeReference.id) + + expect(result).to.equal({ + pageTitle: 'Set the adjustment factors', + amendedAggregate: 0.333333333, + amendedChargeAdjustment: 1, + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + otherAdjustments: ['Two part tariff agreement'], + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023' + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.test.js b/test/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.test.js deleted file mode 100644 index 2e8e7e7636..0000000000 --- a/test/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.test.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Things we need to stub -const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js') - -// Thing under test -const AmendAdjustmentFactorService = require('../../../../app/services/bill-runs/two-part-tariff/amend-adjustment-factor.service.js') - -describe('Amend Adjustment Factor Service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when given a billRun, licence and a reviewChargeReferenceId', () => { - const reviewChargeReferenceId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - beforeEach(() => { - Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves({ - billRun: _billRun(), - reviewChargeReference: _reviewChargeReferenceData() - }) - }) - - it('will fetch the charge reference data and return it once formatted by the presenter', async () => { - const result = await AmendAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReferenceId) - - // NOTE: The service mainly just regurgitates what the AmendAdjustmentFactorPresenter returns. So, we don't - // diligently check each property of the result because we know this will have been covered by the - // AmendAdjustmentFactorPresenter - expect(FetchReviewChargeReferenceService.go.called).to.be.true() - expect(result.billRunId).to.equal('cc4bbb18-0d6a-4254-ac2c-7409de814d7e') - expect(result.licenceId).to.equal('9a8a148d-b71e-463c-bea8-bc5e0a5d95e2') - expect(result.financialYear).to.equal('2022 to 2023') - expect(result.chargeReference.description).to.equal( - 'High loss, non-tidal, restricted water, greater than 15 up to and including 50 ML/yr, Tier 2 model' - ) - }) - }) -}) - -function _billRun () { - return { - id: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeReferenceData () { - return { - id: '89eebffa-28a2-489d-b93a-c0f02a2bdbdd', - reviewChargeVersionId: '4940eaca-8cf1-410b-8a89-faf1faa8081b', - chargeReferenceId: '4e7f1824-3680-4df0-806f-c6d651ba4771', - aggregate: 1, - createdAt: new Date('2024-05-01'), - updatedAt: new Date('2024-05-01'), - amendedAggregate: 1, - chargeAdjustment: 1, - amendedChargeAdjustment: 1, - abatementAgreement: 1, - winterDiscount: false, - twoPartTariffAgreement: true, - canalAndRiverTrustAgreement: false, - authorisedVolume: 32, - amendedAuthorisedVolume: 32, - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2023-03-31') - }, - chargeReference: { - volume: 32, - chargeCategoryId: 'c037ad9a-d3b4-4b1b-8ac9-1cd2b46d152f', - supportedSourceName: null, - waterCompanyCharge: null, - chargeCategory: { - reference: '4.6.12', - shortDescription: 'High loss, non-tidal, restricted water, greater than 15 up to and including 50 ML/yr, Tier 2 model' - } - }, - reviewChargeElements: [{ amendedAllocated: 0.00018 }] - } -} From 2291c946e37b33b7cdd98219013235e109c772ec Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:31:48 +0000 Subject: [PATCH 120/147] Move, rename & refactor preview service test --- .../bill-runs/review/preview.service.test.js | 130 +++++++++++++ .../calculate-charge.service.test.js | 181 ------------------ 2 files changed, 130 insertions(+), 181 deletions(-) create mode 100644 test/services/bill-runs/review/preview.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/calculate-charge.service.test.js diff --git a/test/services/bill-runs/review/preview.service.test.js b/test/services/bill-runs/review/preview.service.test.js new file mode 100644 index 0000000000..d96565629f --- /dev/null +++ b/test/services/bill-runs/review/preview.service.test.js @@ -0,0 +1,130 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const CalculateChargeRequest = require('../../../../app/requests/charging-module/calculate-charge.request.js') +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') + +// Thing under test +const PreviewService = require('../../../../app/services/bill-runs/review/preview.service.js') + +describe('Bill Runs Review - Preview service', () => { + let reviewChargeReference + let yarStub + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('for a review charge reference with a total allocation that is greater than zero', () => { + beforeEach(() => { + reviewChargeReference.reviewChargeElements[0].amendedAllocated = 9.092 + + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + }) + + describe('and the request to the Charging Module API succeeds', () => { + beforeEach(async () => { + Sinon.stub(CalculateChargeRequest, 'send').resolves({ + succeeded: true, + response: { + info: { + gitCommit: '273604040a47e0977b0579a0fef0f09726d95e39', + dockerTag: 'ghcr.io/defra/sroc-charging-module-api:v0.19.0' + }, + statusCode: 200, + body: { + calculation: { + chargeValue: 2000, + baseCharge: 12000, + waterCompanyChargeValue: 0, + supportedSourceValue: 0, + winterOnlyFactor: null, + section130Factor: null, + section127Factor: 0.5, + compensationChargePercent: null + } + } + } + }) + }) + + it('adds a flash message stating the example charge returned by the Charging Module API', async () => { + await PreviewService.go(reviewChargeReference.id, yarStub) + + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(yarStub.flash.called).to.be.true() + expect(flashType).to.equal('charge') + expect(bannerMessage).to.equal('Based on this information the example charge is £20.00') + }) + }) + + describe('and the request to the Charging Module API fails', () => { + beforeEach(async () => { + Sinon.stub(CalculateChargeRequest, 'send').resolves({ + succeeded: false, + response: { + info: { gitCommit: undefined, dockerTag: undefined }, + statusCode: 422, + body: { + statusCode: 422, + error: 'Unprocessable Entity', + message: '"section127Agreement" must be [true]' + } + } + }) + }) + + it('adds a flash message stating the charge could not be calculated', async () => { + await PreviewService.go(reviewChargeReference.id, yarStub) + + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(yarStub.flash.called).to.be.true() + expect(flashType).to.equal('charge') + expect(bannerMessage).to.equal('Could not calculate a charge. "section127Agreement" must be [true].') + }) + }) + }) + + describe('for a review charge reference with a total allocation that is 0', () => { + let calculateChargeRequestStub + + beforeEach(() => { + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + + calculateChargeRequestStub = Sinon.stub(CalculateChargeRequest, 'send').resolves() + }) + + it('adds a flash message stating the example charge is £0.00 and skips calling the Charging Module API', async () => { + await PreviewService.go(reviewChargeReference.id, yarStub) + + expect(calculateChargeRequestStub.called).to.be.false() + + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(yarStub.flash.called).to.be.true() + expect(flashType).to.equal('charge') + expect(bannerMessage).to.equal('Based on this information the example charge is £0.00') + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/calculate-charge.service.test.js b/test/services/bill-runs/two-part-tariff/calculate-charge.service.test.js deleted file mode 100644 index 7cf73f9786..0000000000 --- a/test/services/bill-runs/two-part-tariff/calculate-charge.service.test.js +++ /dev/null @@ -1,181 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const ChargeCategoryHelper = require('../../../support/helpers/charge-category.helper.js') -const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') -const LicenceHelper = require('../../../support/helpers/licence.helper.js') -const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') - -// Things we need to stub -const CalculateChargeRequest = require('../../../../app/requests/charging-module/calculate-charge.request.js') - -// Thing under test -const CalculateChargeService = require('../../../../app/services/bill-runs/two-part-tariff/calculate-charge.service.js') - -describe('Calculate Charge service', () => { - let calculateChargeRequestStub - let chargeCategoryReference - let licenceId - let reviewChargeReferenceId - let yarStub - - beforeEach(async () => { - const testLicence = await LicenceHelper.add({ waterUndertaker: true }) - - licenceId = testLicence.id - - const testChargeCategory = ChargeCategoryHelper.select() - - chargeCategoryReference = testChargeCategory.reference - - const { id: chargeReferenceId } = await ChargeReferenceHelper.add({ - additionalCharges: { isSupplyPublicWater: true, supportedSource: { name: 'TestSource' } }, - chargeCategoryId: testChargeCategory.id - }) - - const { id: reviewChargeVersionId } = await ReviewChargeVersionHelper.add({ - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2023-03-31') - }) - - const testReviewChargeReference = await ReviewChargeReferenceHelper.add({ - reviewChargeVersionId, - chargeReferenceId - }) - - reviewChargeReferenceId = testReviewChargeReference.id - - await ReviewChargeElementHelper.add({ reviewChargeReferenceId, amendedAllocated: 25 }) - await ReviewChargeElementHelper.add({ reviewChargeReferenceId, amendedAllocated: 25 }) - - yarStub = { flash: Sinon.stub() } - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when the charge can be successfully calculated', () => { - beforeEach(async () => { - calculateChargeRequestStub = Sinon.stub(CalculateChargeRequest, 'send').resolves(_calculateChargeRequestStub()) - }) - - it('sends a valid transaction to the charging module to calculate the charge', async () => { - await CalculateChargeService.go(licenceId, reviewChargeReferenceId, yarStub) - - const [testTransactionData] = calculateChargeRequestStub.args[0] - - expect(testTransactionData).to.equal({ - abatementFactor: 1, - actualVolume: 50, - adjustmentFactor: 1, - aggregateProportion: 1, - authorisedDays: 0, - authorisedVolume: 50, - billableDays: 0, - chargeCategoryCode: chargeCategoryReference, - compensationCharge: false, - credit: false, - loss: 'low', - periodStart: '01-APR-2022', - periodEnd: '31-MAR-2023', - ruleset: 'sroc', - section127Agreement: true, - section130Agreement: false, - supportedSource: true, - supportedSourceName: 'TestSource', - twoPartTariff: true, - waterCompanyCharge: true, - waterUndertaker: true, - winterOnly: false - }) - }) - - it('will generate a banner message to display the example charge', async () => { - await CalculateChargeService.go(licenceId, reviewChargeReferenceId, yarStub) - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(yarStub.flash.called).to.be.true() - expect(flashType).to.equal('charge') - expect(bannerMessage).to.equal('Based on this information the example charge is £256.48.') - }) - }) - - describe('when the charge is not calculated because the request to calculate the charge fails', () => { - beforeEach(async () => { - calculateChargeRequestStub = Sinon.stub(CalculateChargeRequest, 'send').resolves({ succeeded: false }) - }) - - it('sends a valid transaction to the charging module to calculate the charge', async () => { - await CalculateChargeService.go(licenceId, reviewChargeReferenceId, yarStub) - - const [testTransactionData] = calculateChargeRequestStub.args[0] - - expect(testTransactionData).to.equal({ - abatementFactor: 1, - actualVolume: 50, - adjustmentFactor: 1, - aggregateProportion: 1, - authorisedDays: 0, - authorisedVolume: 50, - billableDays: 0, - chargeCategoryCode: chargeCategoryReference, - compensationCharge: false, - credit: false, - loss: 'low', - periodStart: '01-APR-2022', - periodEnd: '31-MAR-2023', - ruleset: 'sroc', - section127Agreement: true, - section130Agreement: false, - supportedSource: true, - supportedSourceName: 'TestSource', - twoPartTariff: true, - waterCompanyCharge: true, - waterUndertaker: true, - winterOnly: false - }) - }) - - it('will not generate a banner message', async () => { - await CalculateChargeService.go(licenceId, reviewChargeReferenceId, yarStub) - - expect(yarStub.flash.called).to.be.false() - }) - }) -}) - -function _calculateChargeRequestStub () { - return { - succeeded: true, - response: { - info: { - gitCommit: '273604040a47e0977b0579a0fef0f09726d95e39', - dockerTag: 'ghcr.io/defra/sroc-charging-module-api:v0.19.0' - }, - statusCode: 200, - body: { - calculation: { - chargeValue: 25648, - baseCharge: 51300, - waterCompanyChargeValue: 800, - supportedSourceValue: 3500, - winterOnlyFactor: null, - section130Factor: null, - section127Factor: 0.5, - compensationChargePercent: null - } - } - } - } -} From 61bf653885f1f15cbedbf239d2ebf84bad687d92 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:32:15 +0000 Subject: [PATCH 121/147] Move, rename & refactor remove review licence service test --- .../remove-review-licence.service.test.js} | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) rename test/services/bill-runs/{two-part-tariff/remove-review-data.service.test.js => review/remove-review-licence.service.test.js} (79%) diff --git a/test/services/bill-runs/two-part-tariff/remove-review-data.service.test.js b/test/services/bill-runs/review/remove-review-licence.service.test.js similarity index 79% rename from test/services/bill-runs/two-part-tariff/remove-review-data.service.test.js rename to test/services/bill-runs/review/remove-review-licence.service.test.js index cf32a98abb..f7d5ddfb7e 100644 --- a/test/services/bill-runs/two-part-tariff/remove-review-data.service.test.js +++ b/test/services/bill-runs/review/remove-review-licence.service.test.js @@ -22,25 +22,23 @@ const ReviewReturnHelper = require('../../../support/helpers/review-return.helpe const ReviewReturnModel = require('../../../../app/models/review-return.model.js') // Thing under test -const RemoveReviewDataService = require('../../../../app/services/bill-runs/two-part-tariff/remove-review-data.service.js') - -describe('Remove Review Data service', () => { - describe('when called with a valid billRunId & licenceId', () => { - const billRunId = 'f54005c6-66bc-43d7-a7e8-d162e6ebc317' - const licenceId = '41f1ad1d-0f25-4b2f-bc0a-4b38131db12a' +const RemoveReviewLicenceService = require('../../../../app/services/bill-runs/review/remove-review-licence.service.js') +describe('Bill Runs Review - Remove Review Licence service', () => { + describe('when called', () => { let reviewChargeElementId let reviewChargeElementReturnId let reviewChargeReferenceId let reviewChargeVersionId + let reviewLicence let reviewReturnId beforeEach(async () => { - const { id: reviewLicenceId } = await ReviewLicenceHelper.add({ billRunId, licenceId }) - const reviewReturn = await ReviewReturnHelper.add({ reviewLicenceId }) + reviewLicence = await ReviewLicenceHelper.add() + const reviewReturn = await ReviewReturnHelper.add({ reviewLicenceId: reviewLicence.id }) reviewReturnId = reviewReturn.id - const reviewChargeVersion = await ReviewChargeVersionHelper.add({ reviewLicenceId }) + const reviewChargeVersion = await ReviewChargeVersionHelper.add({ reviewLicenceId: reviewLicence.id }) reviewChargeVersionId = reviewChargeVersion.id const reviewChargeReference = await ReviewChargeReferenceHelper.add({ reviewChargeVersionId }) @@ -54,10 +52,10 @@ describe('Remove Review Data service', () => { reviewChargeElementReturnId = reviewChargeElementReturn.id }) - it('will remove the records relating to the licence from the review tables', async () => { - await RemoveReviewDataService.go(billRunId, licenceId) + it('will remove the records relating to the review licence from the review tables', async () => { + await RemoveReviewLicenceService.go(reviewLicence.id) - expect(await ReviewLicenceModel.query().where('licenceId', licenceId)).to.be.empty() + expect(await ReviewLicenceModel.query().findById(reviewLicence.id)).to.be.undefined() expect(await ReviewReturnModel.query().findById(reviewReturnId)).to.be.undefined() expect(await ReviewChargeVersionModel.query().findById(reviewChargeVersionId)).to.be.undefined() expect(await ReviewChargeReferenceModel.query().findById(reviewChargeReferenceId)).to.be.undefined() From 8293a5f221f571b0671e45abae75420642cec165 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:32:50 +0000 Subject: [PATCH 122/147] Move, rename & refactor review chg ref service test --- .../review-charge-reference.service.test.js | 131 ++++++++++++++++++ .../charge-reference-details.service.test.js | 99 ------------- 2 files changed, 131 insertions(+), 99 deletions(-) create mode 100644 test/services/bill-runs/review/review-charge-reference.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/charge-reference-details.service.test.js diff --git a/test/services/bill-runs/review/review-charge-reference.service.test.js b/test/services/bill-runs/review/review-charge-reference.service.test.js new file mode 100644 index 0000000000..f8ff472ff4 --- /dev/null +++ b/test/services/bill-runs/review/review-charge-reference.service.test.js @@ -0,0 +1,131 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') + +// Thing under test +const ReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/review-charge-reference.service.js') + +describe('Bill Runs Review - Review Charge Reference Service', () => { + let reviewChargeReference + let yarStub + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('and there is a banner flash message to display', () => { + beforeEach(() => { + const stub = Sinon.stub() + + stub.withArgs('banner').returns(['The authorised volume for this licence have been updated']) + stub.withArgs('charge').returns([undefined]) + + yarStub = { flash: stub } + }) + + it('returns page data for the view', async () => { + const result = await ReviewChargeReferenceService.go(reviewChargeReference.id, yarStub) + + expect(result).to.equal({ + pageTitle: 'Review charge reference', + bannerMessage: 'The authorised volume for this licence have been updated', + chargeMessage: undefined, + additionalCharges: '', + adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + amendedAuthorisedVolume: 9.092, + canAmend: true, + chargeCategory: '4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + totalBillableReturns: 0 + }) + }) + }) + + describe('and there is a charge flash message to display', () => { + beforeEach(() => { + const stub = Sinon.stub() + + stub.withArgs('banner').returns([undefined]) + stub.withArgs('charge').returns(['Based on this information the example charge is £256.48.']) + + yarStub = { flash: stub } + }) + + it('returns page data for the view', async () => { + const result = await ReviewChargeReferenceService.go(reviewChargeReference.id, yarStub) + + expect(result).to.equal({ + pageTitle: 'Review charge reference', + bannerMessage: undefined, + chargeMessage: 'Based on this information the example charge is £256.48.', + additionalCharges: '', + adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + amendedAuthorisedVolume: 9.092, + canAmend: true, + chargeCategory: '4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + totalBillableReturns: 0 + }) + }) + }) + + describe('and there is no flash message to display', () => { + beforeEach(() => { + const stub = Sinon.stub() + + stub.withArgs('banner').returns([undefined]) + stub.withArgs('charge').returns([undefined]) + + yarStub = { flash: stub } + }) + + it('returns page data for the view', async () => { + const result = await ReviewChargeReferenceService.go(reviewChargeReference.id, yarStub) + + expect(result).to.equal({ + pageTitle: 'Review charge reference', + bannerMessage: undefined, + chargeMessage: undefined, + additionalCharges: '', + adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + amendedAuthorisedVolume: 9.092, + canAmend: true, + chargeCategory: '4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + totalBillableReturns: 0 + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/charge-reference-details.service.test.js b/test/services/bill-runs/two-part-tariff/charge-reference-details.service.test.js deleted file mode 100644 index d03372cdbd..0000000000 --- a/test/services/bill-runs/two-part-tariff/charge-reference-details.service.test.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Things we need to stub -const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js') - -// Thing under test -const ChargeReferenceDetailsService = require('../../../../app/services/bill-runs/two-part-tariff/charge-reference-details.service.js') - -describe('Charge Reference Details Service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when given a billRun, licence and chargeReference ID', () => { - const reviewChargeReferenceId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - let yarStub - - beforeEach(() => { - Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves({ - billRun: _billRun(), - reviewChargeReference: _reviewChargeReferenceData() - }) - - yarStub = { - flash: Sinon.stub() - .onFirstCall().returns(['Adjustment updated']) - .onSecondCall().returns(['Based on this information the example charge is £256.48.']) - } - }) - - it('will fetch the charge reference data and return it once formatted by the presenter', async () => { - const result = await ChargeReferenceDetailsService.go(billRunId, licenceId, reviewChargeReferenceId, yarStub) - - expect(result.bannerMessage).to.equal('Adjustment updated') - expect(result.chargeMessage).to.equal('Based on this information the example charge is £256.48.') - - // NOTE: The service mainly just regurgitates what the ChargeReferencePresenter returns. So, we don't diligently - // check each property of the result because we know this will have been covered by the ChargeReferencePresenter - expect(FetchReviewChargeReferenceService.go.called).to.be.true() - expect(result.billRunId).to.equal('cc4bbb18-0d6a-4254-ac2c-7409de814d7e') - expect(result.licenceId).to.equal('9a8a148d-b71e-463c-bea8-bc5e0a5d95e2') - expect(result.financialYear).to.equal('2022 to 2023') - expect(result.chargeReference.reference).to.equal('4.6.12') - }) - }) -}) - -function _billRun () { - return { - id: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeReferenceData () { - return { - id: '89eebffa-28a2-489d-b93a-c0f02a2bdbdd', - reviewChargeVersionId: '4940eaca-8cf1-410b-8a89-faf1faa8081b', - chargeReferenceId: '4e7f1824-3680-4df0-806f-c6d651ba4771', - aggregate: 1, - createdAt: new Date('2024-05-01'), - updatedAt: new Date('2024-05-01'), - amendedAggregate: 1, - chargeAdjustment: 1, - amendedChargeAdjustment: 1, - abatementAgreement: 1, - winterDiscount: false, - twoPartTariffAgreement: true, - canalAndRiverTrustAgreement: false, - authorisedVolume: 32, - amendedAuthorisedVolume: 32, - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2023-03-31') - }, - chargeReference: { - volume: 32, - chargeCategoryId: 'c037ad9a-d3b4-4b1b-8ac9-1cd2b46d152f', - supportedSourceName: null, - waterCompanyCharge: null, - chargeCategory: { - reference: '4.6.12', - shortDescription: 'High loss, non-tidal, restricted water, greater than 15 up to and including 50 ML/yr, Tier 2 model' - } - }, - reviewChargeElements: [{ amendedAllocated: 0.00018 }] - } -} From bd5cbb260956222e38c482b3247863a8b9470433 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:33:16 +0000 Subject: [PATCH 123/147] Move, rename & refactor review chg elmnt service test --- .../review-charge-element.service.test.js | 121 +++++++++++++++++ .../match-details.service.test.js | 122 ------------------ 2 files changed, 121 insertions(+), 122 deletions(-) create mode 100644 test/services/bill-runs/review/review-charge-element.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/match-details.service.test.js diff --git a/test/services/bill-runs/review/review-charge-element.service.test.js b/test/services/bill-runs/review/review-charge-element.service.test.js new file mode 100644 index 0000000000..634c890293 --- /dev/null +++ b/test/services/bill-runs/review/review-charge-element.service.test.js @@ -0,0 +1,121 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeElementService = require('../../../../app/services/bill-runs/review/fetch-review-charge-element.service.js') + +// Thing under test +const ReviewChargeElementService = require('../../../../app/services/bill-runs/review/review-charge-element.service.js') + +describe('Bill Runs Review - Review Charge Element Service', () => { + const elementIndex = 1 + + let reviewChargeElement + let yarStub + + beforeEach(() => { + reviewChargeElement = BillRunsReviewFixture.reviewChargeElement() + + Sinon.stub(FetchReviewChargeElementService, 'go').resolves(reviewChargeElement) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('and there is a flash message to display', () => { + beforeEach(() => { + yarStub = { flash: Sinon.stub().withArgs('banner').returns(['The billable returns for this licence have been updated']) } + }) + + it('returns page data for the view', async () => { + const result = await ReviewChargeElementService.go(reviewChargeElement.id, elementIndex, yarStub) + + expect(result).to.equal({ + bannerMessage: 'The billable returns for this licence have been updated', + pageTitle: 'Review charge element', + authorisedVolume: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementCount: 1, + elementIndex: 1, + financialPeriod: '2023 to 2024', + issues: ['Aggregate'], + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + status: 'review' + }) + }) + }) + + describe('and there is no flash message to display', () => { + beforeEach(() => { + yarStub = { flash: Sinon.stub().withArgs('banner').returns([undefined]) } + }) + + it('returns page data for the view', async () => { + const result = await ReviewChargeElementService.go(reviewChargeElement.id, elementIndex, yarStub) + + expect(result).to.equal({ + bannerMessage: undefined, + pageTitle: 'Review charge element', + authorisedVolume: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementCount: 1, + elementIndex: 1, + financialPeriod: '2023 to 2024', + issues: ['Aggregate'], + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + status: 'review' + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/match-details.service.test.js b/test/services/bill-runs/two-part-tariff/match-details.service.test.js deleted file mode 100644 index efae73e4db..0000000000 --- a/test/services/bill-runs/two-part-tariff/match-details.service.test.js +++ /dev/null @@ -1,122 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Things we need to stub -const FetchMatchDetailsService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-match-details.service.js') - -// Thing under test -const MatchDetailsService = require('../../../../app/services/bill-runs/two-part-tariff/match-details.service.js') - -describe('Match Details Service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when given a billRun, licence and chargeElement ID', () => { - const reviewChargeElementId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - let yarStub - - beforeEach(() => { - Sinon.stub(FetchMatchDetailsService, 'go').resolves({ - billRun: _billRun(), - reviewChargeElement: _reviewChargeElementData() - }) - - yarStub = { flash: Sinon.stub().returns(['The billable returns for this licence have been updated']) } - }) - - it('will fetch the charge element data and return it once formatted by the presenter', async () => { - const result = await MatchDetailsService.go(billRunId, licenceId, reviewChargeElementId, yarStub) - - expect(result.bannerMessage).to.equal('The billable returns for this licence have been updated') - - // NOTE: The service mainly just regurgitates what the MatchDetailsPresenter returns. So, we don't diligently - // check each property of the result because we know this will have been covered by the MatchDetailsPresenter - - expect(FetchMatchDetailsService.go.called).to.be.true() - expect(result.billRunId).to.equal('6620135b-0ecf-4fd4-924e-371f950c0526') - expect(result.licenceId).to.equal('9a8a148d-b71e-463c-bea8-bc5e0a5d95e2') - expect(result.chargeElement.chargeElementId).to.equal('b4d70c89-de1b-4f68-a47f-832b338ac044') - expect(result.chargeElement.billableVolume).to.equal(0) - }) - }) -}) - -function _billRun () { - return { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023 - } -} - -function _reviewChargeElementData () { - return { - id: 'b4d70c89-de1b-4f68-a47f-832b338ac044', - reviewChargeReferenceId: '9e5d87d7-073e-420e-b12d-73ca220dd8ef', - chargeElementId: 'b345f1f1-496b-4049-a647-6bcd123dcf68', - allocated: 10, - amendedAllocated: 0, - chargeDatesOverlap: false, - issues: null, - status: 'ready', - createdAt: new Date('2024-04-02'), - updatedAt: new Date('2024-04-02'), - reviewReturns: [ - { - id: 'c4cdbfa9-4528-4776-b62f-fa667b797717', - reviewLicenceId: '674ffa02-51be-4caa-b25e-cc1fea1ac057', - returnId: 'v1:1:01/57/14/1646:15584914:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: [{ - tertiary: { code: '400', description: 'Spray Irrigation - Direct' } - }], - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date('2022-04-01'), - endDate: new Date('2022-05-06'), - issues: null, - createdAt: new Date('2024-04-02'), - updatedAt: new Date('2024-04-02'), - returnLog: { - periodEndDay: 31, - periodEndMonth: 3, - periodStartDay: 1, - periodStartMonth: 4 - } - } - ], - chargeElement: { - description: 'Trickle Irrigation - Direct', - abstractionPeriodStartDay: 1, - abstractionPeriodStartMonth: 4, - abstractionPeriodEndDay: 31, - abstractionPeriodEndMonth: 3, - authorisedAnnualQuantity: 200 - }, - reviewChargeReference: { - id: '9e5d87d7-073e-420e-b12d-73ca220dd8ef', - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-05') - } - } - } -} From 965633b33339b86a796b6189b31347ea83ebb4d6 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:33:43 +0000 Subject: [PATCH 124/147] Move, rename & refactor remove service test --- .../bill-runs/review/remove.service.test.js | 48 +++++++++++++++++ .../remove-bill-run-licence.service.test.js | 53 ------------------- 2 files changed, 48 insertions(+), 53 deletions(-) create mode 100644 test/services/bill-runs/review/remove.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.test.js diff --git a/test/services/bill-runs/review/remove.service.test.js b/test/services/bill-runs/review/remove.service.test.js new file mode 100644 index 0000000000..79e50e65d1 --- /dev/null +++ b/test/services/bill-runs/review/remove.service.test.js @@ -0,0 +1,48 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchRemoveReviewLicenceService = require('../../../../app/services/bill-runs/review/fetch-remove-review-licence.service.js') + +// Thing under test +const RemoveService = require('../../../../app/services/bill-runs/review/remove.service.js') + +describe('Bill Runs Review - Remove service', () => { + let removeReviewLicence + + beforeEach(() => { + removeReviewLicence = BillRunsReviewFixture.removeReviewLicence() + + Sinon.stub(FetchRemoveReviewLicenceService, 'go').resolves(removeReviewLicence) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + it('returns page data for the view', async () => { + const result = await RemoveService.go(removeReviewLicence.id) + + expect(result).to.equal({ + billRunNumber: 10001, + billRunStatus: 'review', + dateCreated: '22 October 2024', + financialYearPeriod: '2023 to 2024', + pageTitle: "You're about to remove 1/11/11/*11/1111 from the bill run", + region: 'Test Region', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763' + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.test.js b/test/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.test.js deleted file mode 100644 index ac726bfd7e..0000000000 --- a/test/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.test.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') - -const { describe, it, beforeEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') -const LicenceHelper = require('../../../support/helpers/licence.helper.js') -const RegionHelper = require('../../../support/helpers/region.helper.js') - -// Thing under test -const RemoveBillRunLicenceService = require('../../../../app/services/bill-runs/two-part-tariff/remove-bill-run-licence.service.js') - -describe('Remove Bill Run Licence service', () => { - let billRunId - let licence - let region - - beforeEach(async () => { - region = RegionHelper.select() - const billRun = await BillRunHelper.add({ - billRunNumber: 12345, - createdAt: new Date('2024-05-03'), - regionId: region.id, - status: 'review', - toFinancialYearEnding: 2023 - }) - - billRunId = billRun.id - - licence = await LicenceHelper.add() - }) - - describe('when called with a valid billRunId & licenceId', () => { - it('will fetch the data and format it for use in the Remove bill run licence confirmation page', async () => { - const result = await RemoveBillRunLicenceService.go(billRunId, licence.id) - - expect(result).to.equal({ - pageTitle: `You're about to remove ${licence.licenceRef} from the bill run`, - backLink: `../review/${licence.id}`, - billRunNumber: 12345, - billRunStatus: 'review', - dateCreated: '3 May 2024', - financialYear: '2022 to 2023', - region: region.displayName - }) - }) - }) -}) From 3b1815106b5e5d1b02592fddc215b198d803ee39 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:34:03 +0000 Subject: [PATCH 125/147] Move, rename & refactor review licence service test --- .../review/review-licence.service.test.js | 230 ++++++++++++++++ .../review-licence.service.test.js | 248 ------------------ 2 files changed, 230 insertions(+), 248 deletions(-) create mode 100644 test/services/bill-runs/review/review-licence.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/review-licence.service.test.js diff --git a/test/services/bill-runs/review/review-licence.service.test.js b/test/services/bill-runs/review/review-licence.service.test.js new file mode 100644 index 0000000000..eb40b3aba5 --- /dev/null +++ b/test/services/bill-runs/review/review-licence.service.test.js @@ -0,0 +1,230 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewLicenceService = require('../../../../app/services/bill-runs/review/fetch-review-licence.service.js') + +// Thing under test +const ReviewLicenceService = require('../../../../app/services/bill-runs/review/review-licence.service.js') + +describe('Bill Runs Review - Review Licence Service', () => { + let reviewLicence + + let yarStub + + beforeEach(() => { + reviewLicence = BillRunsReviewFixture.reviewLicence() + + Sinon.stub(FetchReviewLicenceService, 'go').resolves(reviewLicence) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('and there is a flash message to display', () => { + beforeEach(() => { + yarStub = { flash: Sinon.stub().withArgs('banner').returns(['This licence has been marked.']) } + }) + + it('returns page data for the view', async () => { + const result = await ReviewLicenceService.go(reviewLicence.id, yarStub) + + expect(result).to.equal({ + bannerMessage: 'This licence has been marked.', + billRunId: '287aeb25-cf11-429d-8c6f-f98f06db021d', + chargeVersions: [ + { + billingAccountDetails: { + billingAccountId: 'f041c128-bb4d-4f67-8f97-e33d71d50842', + accountNumber: 'E99999999A', + accountName: 'Mr B Blobby Ltd', + contactName: null, + addressLines: [ + 'C/O Noel Edmonds', + 'Crinkley Bottom', + 'Cricket St Thomas', + 'Somerset', + 'TA20 1KL', + 'United Kingdom' + ] + }, + chargePeriod: '1 April 2023 to 31 March 2024', + chargeReferences: [ + { + billableReturnsWarning: false, + chargeCategory: 'Charge reference 4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + id: '6c70461b-3f83-47b1-9538-8305e82b34eb', + chargeElements: [ + { + billableReturns: '0 ML / 9.092 ML', + chargePeriods: ['1 April 2023 to 30 September 2023'], + returnVolumes: ['0 ML (10030495)'], + description: 'Spray Irrigation - Direct', + elementCount: 1, + elementIndex: 1, + status: 'review', + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + issues: ['Aggregate'], + purpose: 'Spray Irrigation - Direct' + } + ], + chargeReferenceLinkTitle: 'Change details', + totalBillableReturns: '0 ML / 9.092 ML' + } + ], + description: '1 charge reference with 1 two-part tariff charge element', + financialPeriod: '2023 to 2024' + } + ], + elementsInReview: true, + licenceHolder: 'Licence Holder Ltd', + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + licenceRef: '1/11/11/*11/1111', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + pageTitle: 'Licence 1/11/11/*11/1111', + progress: false, + region: 'South West', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + status: 'review', + unmatchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Lost Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Storage', + reference: '11142961', + returnId: 'v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ] + }) + }) + }) + + describe('and there is no flash message to display', () => { + beforeEach(() => { + yarStub = { flash: Sinon.stub().withArgs('banner').returns([undefined]) } + }) + + it('returns page data for the view', async () => { + const result = await ReviewLicenceService.go(reviewLicence.id, yarStub) + + expect(result).to.equal({ + bannerMessage: undefined, + billRunId: '287aeb25-cf11-429d-8c6f-f98f06db021d', + chargeVersions: [ + { + billingAccountDetails: { + billingAccountId: 'f041c128-bb4d-4f67-8f97-e33d71d50842', + accountNumber: 'E99999999A', + accountName: 'Mr B Blobby Ltd', + contactName: null, + addressLines: [ + 'C/O Noel Edmonds', + 'Crinkley Bottom', + 'Cricket St Thomas', + 'Somerset', + 'TA20 1KL', + 'United Kingdom' + ] + }, + chargePeriod: '1 April 2023 to 31 March 2024', + chargeReferences: [ + { + billableReturnsWarning: false, + chargeCategory: 'Charge reference 4.6.5', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + id: '6c70461b-3f83-47b1-9538-8305e82b34eb', + chargeElements: [ + { + billableReturns: '0 ML / 9.092 ML', + chargePeriods: ['1 April 2023 to 30 September 2023'], + returnVolumes: ['0 ML (10030495)'], + description: 'Spray Irrigation - Direct', + elementCount: 1, + elementIndex: 1, + status: 'review', + id: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1', + issues: ['Aggregate'], + purpose: 'Spray Irrigation - Direct' + } + ], + chargeReferenceLinkTitle: 'Change details', + totalBillableReturns: '0 ML / 9.092 ML' + } + ], + description: '1 charge reference with 1 two-part tariff charge element', + financialPeriod: '2023 to 2024' + } + ], + elementsInReview: true, + licenceHolder: 'Licence Holder Ltd', + licenceId: '32416c67-f755-4c3f-8816-ecde0ee596bd', + licenceRef: '1/11/11/*11/1111', + matchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Test Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Direct', + reference: '11142960', + returnId: 'v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142960:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ], + pageTitle: 'Licence 1/11/11/*11/1111', + progress: false, + region: 'South West', + reviewLicenceId: 'bb779166-0576-4581-b504-edbc0227d763', + status: 'review', + unmatchedReturns: [ + { + abstractionPeriod: '1 April to 30 September', + description: 'Lost Road. Points 1 and 2.', + issues: [], + purpose: 'Spray Irrigation - Storage', + reference: '11142961', + returnId: 'v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnLink: '/returns/return?id=v1:5:1/11/11/*11/1111:11142961:2022-11-01:2023-10-31', + returnPeriod: '1 November 2022 to 31 October 2023', + returnStatus: 'completed', + returnTotal: '0 ML / 0 ML' + } + ] + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/review-licence.service.test.js b/test/services/bill-runs/two-part-tariff/review-licence.service.test.js deleted file mode 100644 index 5803036faa..0000000000 --- a/test/services/bill-runs/two-part-tariff/review-licence.service.test.js +++ /dev/null @@ -1,248 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillingAccountModel = require('../../../../app/models/billing-account.model.js') - -// Things we need to stub -const FetchReviewLicenceResultsService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js') - -// Thing under test -const ReviewLicenceService = require('../../../../app/services/bill-runs/two-part-tariff/review-licence.service.js') - -describe('Review Licence Service', () => { - const billRunId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' - const licenceId = '082f528e-4ae4-4f41-ba64-b740a0a210ff' - - let yarStub - - beforeEach(async () => { - Sinon.stub(FetchReviewLicenceResultsService, 'go').resolves(_fetchReviewLicenceResults()) - - yarStub = { flash: Sinon.stub().returns(['This licence has been marked.']) } - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when called', () => { - it('returns page data for the view', async () => { - const result = await ReviewLicenceService.go(billRunId, licenceId, yarStub) - - expect(result.bannerMessage).to.equal('This licence has been marked.') - - // NOTE: The service mainly just regurgitates what the ReviewLicencePresenter returns. So, we don't diligently - // check each property of the result because we know this will have been covered by the ReviewLicencePresenter - expect(result.billRunId).to.equal('6620135b-0ecf-4fd4-924e-371f950c0526') - expect(result.region).to.equal('Anglian') - expect(result.licence.licenceId).to.equal('786f0d83-eaf7-43c3-9de5-ec59e3de05ee') - expect(result.licence.licenceHolder).to.equal('Licence Holder Ltd') - expect(result.matchedReturns[0].returnId).to.equal('v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31') - expect(result.unmatchedReturns[0].returnId).to.equal('v2:1:01/60/28/3437:17061181:2022-04-01:2023-03-31') - expect(result.chargeData[0].financialYear).to.equal('2022 to 2023') - expect(result.chargeData[0].billingAccountDetails.billingAccountId).to.equal('a17ae69b-8074-4d27-80bf-074f4c79a05a') - }) - }) -}) - -function _fetchReviewLicenceResults () { - const billingAccountDetails = BillingAccountModel.fromJson({ - id: 'a17ae69b-8074-4d27-80bf-074f4c79a05a', - accountNumber: 'E88896464A', - company: { - id: 'e44491db-2b33-4473-9c3a-b57aceabb6e8', - name: 'Furland Farm', - type: 'organisation' - }, - billingAccountAddresses: [ - { - id: 'eb5cb54a-0b51-4e4a-8472-dab993eb6157', - billingAccountId: 'a17ae69b-8074-4d27-80bf-074f4c79a05a', - addressId: 'cc32fefd-7f3e-4581-b437-78a3fae66d4b', - startDate: new Date('2016-05-20'), - endDate: null, - companyId: null, - contactId: null, - company: null, - contact: null, - address: { - id: 'cc32fefd-7f3e-4581-b437-78a3fae66d4b', - address1: 'Furland Farm', - address2: 'Furland', - address3: null, - address4: null, - address5: 'Crewkerne', - address6: 'Somerset', - postcode: 'TA18 7TT', - country: 'England' - } - } - ] - }) - - return { - billRun: { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023, - region: { - displayName: 'Anglian' - } - }, - licence: [{ - id: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - billRunId: '82772a06-c8ce-45f7-8504-dd20ea8824e4', - licenceId: '786f0d83-eaf7-43c3-9de5-ec59e3de05ee', - licenceRef: '01/49/80/4608', - licenceHolder: 'Licence Holder Ltd', - issues: '', - status: 'ready', - progress: false, - hasReviewStatus: false, - reviewReturns: [{ - id: '2264f443-5c16-4ca9-8522-f63e2d4e38be', - reviewLicenceId: '78a99c1c-26d3-4163-ab58-084cd78594ab', - returnId: 'v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: [{ - tertiary: { - description: 'Site description' - } - }], - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date(' 2022-04-01'), - endDate: new Date('2022-05-06'), - issues: '', - reviewChargeElements: [{ - id: 'e840f418-ca6b-4d96-9f36-bf684c78590f', - reviewChargeReferenceId: '7759e0f9-5763-4b94-8d45-0621aea3edc1', - chargeElementId: 'b1cd4f98-ad96-4901-9e21-4432f032492a', - allocated: 0, - amendedAllocated: 0, - chargeDatesOverlap: false, - issues: '', - status: 'ready' - }], - returnLog: { - periodEndDay: 31, - periodEndMonth: 3, - periodStartDay: 1, - periodStartMonth: 4 - } - }, - { - id: '4864f643-5c16-5ca9-8512-f63e1d4e58be', - reviewLicenceId: '78a99c1c-26d3-4163-ab58-084cd78594ab', - returnId: 'v2:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: [{ - tertiary: { - description: 'Site description' - } - }], - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date(' 2022-04-01'), - endDate: new Date('2022-05-06'), - issues: '', - reviewChargeElements: [], - returnLog: { - periodEndDay: 31, - periodEndMonth: 3, - periodStartDay: 1, - periodStartMonth: 4 - } - }], - reviewChargeVersions: [{ - id: '3de5634a-da26-4241-87e9-7248a4b83a69', - reviewLicenceId: 'd9e78306-bf65-4020-b279-5ae471cea4e6', - chargeVersionId: 'd103bb54-1819-4e77-b3d9-bc8913454e06', - changeReason: 'Strategic review of charges (SRoC)', - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-05'), - reviewChargeReferences: [{ - id: 'b2af5935-4b65-4dce-9f75-9073798f6375', - reviewChargeVersionId: 'bd16e7b0-c2a3-4258-b873-b965fd74cdf5', - chargeReferenceId: '82ce8695-5841-41b0-a1e7-d016407adad4', - aggregate: 1, - createdAt: new Date('2024-03-18'), - updatedAt: new Date('2024-03-18'), - chargeReference: { - chargeCategoryId: 'f100dc23-c6a7-4efa-af4f-80618260b32e', - chargeCategory: { - reference: '4.6.7', - shortDescription: 'High loss, non-tidal, greater than 15 up to and including 50 ML/yr' - } - }, - reviewChargeElements: [{ - id: '8bc0cd32-400e-4a45-9dd7-fbce3d486031', - reviewChargeReferenceId: '2210bb45-1efc-4e69-85cb-c8cc6e75c4fd', - chargeElementId: 'b1001716-cfb4-43c6-91f0-1863f4529223', - allocated: 0, - amendedAllocated: 0, - chargeDatesOverlap: false, - issues: '', - status: 'ready', - chargeElement: { - description: 'Trickle Irrigation - Direct', - abstractionPeriodStartDay: 1, - abstractionPeriodStartMonth: 4, - abstractionPeriodEndDay: 31, - abstractionPeriodEndMonth: 3, - authorisedAnnualQuantity: 200, - purpose: { - description: 'Spray irrigation - direct' - } - }, - reviewReturns: [{ - id: '2264f443-5c16-4ca9-8522-f63e2d4e38be', - reviewLicenceId: '78a99c1c-26d3-4163-ab58-084cd78594ab', - returnId: 'v1:1:01/60/28/3437:17061181:2022-04-01:2023-03-31', - returnReference: '10031343', - quantity: 0, - allocated: 0, - underQuery: false, - returnStatus: 'completed', - nilReturn: false, - abstractionOutsidePeriod: false, - receivedDate: new Date('2022-06-03'), - dueDate: new Date('2022-06-03'), - purposes: {}, - description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', - startDate: new Date(' 2022-04-01'), - endDate: new Date('2022-05-06'), - issues: '' - }] - }] - }], - chargeVersion: { - billingAccountId: '67d7cacb-5d10-4a08-b7f8-e6ce98cbf4c8' - }, - billingAccountDetails - }] - }] - } -} From 90e8d2e0bc95cf50b3ae9e4764ffdab6501203d5 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:34:37 +0000 Subject: [PATCH 126/147] Move, rename & refactor fetch review licence service test --- .../fetch-review-licence.service.test.js | 278 ++++++++++++++++++ ...tch-review-licence-results.service.test.js | 263 ----------------- 2 files changed, 278 insertions(+), 263 deletions(-) create mode 100644 test/services/bill-runs/review/fetch-review-licence.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.test.js diff --git a/test/services/bill-runs/review/fetch-review-licence.service.test.js b/test/services/bill-runs/review/fetch-review-licence.service.test.js new file mode 100644 index 0000000000..72e7765a55 --- /dev/null +++ b/test/services/bill-runs/review/fetch-review-licence.service.test.js @@ -0,0 +1,278 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, before } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const AddressHelper = require('../../../support/helpers/address.helper.js') +const BillingAccountHelper = require('../../../support/helpers/billing-account.helper.js') +const BillingAccountAddressHelper = require('../../../support/helpers/billing-account-address.helper.js') +const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') +const ChargeCategoryHelper = require('../../../support/helpers/charge-category.helper.js') +const ChargeElementHelper = require('../../../support/helpers/charge-element.helper.js') +const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') +const ChargeVersionHelper = require('../../../support/helpers/charge-version.helper.js') +const CompanyHelper = require('../../../support/helpers/company.helper.js') +const ContactHelper = require('../../../support/helpers/contact.helper.js') +const LicenceHelper = require('../../../support/helpers/licence.helper.js') +const PurposeHelper = require('../../../support/helpers/purpose.helper.js') +const RegionHelper = require('../../../support/helpers/region.helper.js') +const ReturnLogHelper = require('../../../support/helpers/return-log.helper.js') +const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') +const ReviewChargeElementReturnHelper = require('../../../support/helpers/review-charge-element-return.helper.js') +const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') +const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') +const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') +const ReviewReturnHelper = require('../../../support/helpers/review-return.helper.js') + +// Thing under test +const FetchReviewLicenceService = require('../../../../app/services/bill-runs/review/fetch-review-licence.service.js') + +describe('Bill Runs Review - Fetch Review Licence service', () => { + let address + let billingAccount + let billingAccountAddress + let billRun + let chargeCategory + let chargeElement + let chargeReference + let chargeVersion + let company + let contact + let licence + let purpose + let region + let returnLog + let reviewChargeElement + let reviewChargeVersion + let reviewChargeReference + let reviewLicence + let reviewReturn + + before(async () => { + address = await AddressHelper.add() + company = await CompanyHelper.add() + contact = await ContactHelper.add() + billingAccount = await BillingAccountHelper.add({ companyId: company.id }) + billingAccountAddress = await BillingAccountAddressHelper.add({ + addressId: address.id, + billingAccountId: billingAccount.id, + companyId: company.id, + contactId: contact.id + }) + + region = RegionHelper.select() + + billRun = await BillRunHelper.add({ batchType: 'two_part_tariff', regionId: region.id, status: 'review' }) + + licence = await LicenceHelper.add() + returnLog = await ReturnLogHelper.add() + + chargeVersion = await ChargeVersionHelper.add({ + billingAccountId: billingAccount.id, licenceId: licence.id, licenceRef: licence.licenceRef + }) + chargeCategory = ChargeCategoryHelper.select() + chargeReference = await ChargeReferenceHelper.add({ + chargeCategoryId: chargeCategory.id, chargeVersionId: chargeVersion.id + }) + purpose = PurposeHelper.select() + chargeElement = await ChargeElementHelper.add({ chargeReferenceId: chargeReference.id, purposeId: purpose.id }) + + reviewLicence = await ReviewLicenceHelper.add({ + billRunId: billRun.id, licenceId: licence.id, licenceRef: licence.licenceRef + }) + reviewReturn = await ReviewReturnHelper.add({ + purposes: [{ + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '400', description: 'Spray Irrigation - Direct' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + }], + returnId: returnLog.id, + reviewLicenceId: reviewLicence.id + }) + + reviewChargeVersion = await ReviewChargeVersionHelper.add({ + chargeVersionId: chargeVersion.id, + reviewLicenceId: reviewLicence.id + }) + reviewChargeReference = await ReviewChargeReferenceHelper.add({ + chargeReferenceId: chargeReference.id, + reviewChargeVersionId: reviewChargeVersion.id + }) + reviewChargeElement = await ReviewChargeElementHelper.add({ + chargeElementId: chargeElement.id, + reviewChargeReferenceId: reviewChargeReference.id + }) + + await ReviewChargeElementReturnHelper.add({ + reviewChargeElementId: reviewChargeElement.id, reviewReturnId: reviewReturn.id + }) + }) + + describe('when a matching review licence exists', () => { + it('returns the match', async () => { + const result = await FetchReviewLicenceService.go(reviewLicence.id) + + expect(result).to.equal({ + id: reviewLicence.id, + billRunId: reviewLicence.billRunId, + licenceId: reviewLicence.licenceId, + licenceRef: reviewLicence.licenceRef, + licenceHolder: 'Licence Holder Ltd', + status: 'ready', + progress: false, + billRun: { + id: billRun.id, + toFinancialYearEnding: 2023, + region: { + id: region.id, + displayName: region.displayName + } + }, + reviewReturns: [ + { + id: reviewReturn.id, + allocated: 0, + description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', + endDate: new Date('2022-05-06'), + issues: '', + quantity: 0, + purposes: [ + { + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '400', description: 'Spray Irrigation - Direct' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + } + ], + returnId: reviewReturn.returnId, + returnReference: reviewReturn.returnReference, + returnStatus: 'completed', + startDate: new Date('2022-04-01'), + underQuery: false, + returnLog: { + id: returnLog.id, + periodStartDay: 1, + periodStartMonth: 4, + periodEndDay: 28, + periodEndMonth: 4 + }, + reviewChargeElements: [ + { + id: reviewChargeElement.id + } + ] + } + ], + reviewChargeVersions: [ + { + id: reviewChargeVersion.id, + chargePeriodStartDate: new Date('2022-04-01'), + chargePeriodEndDate: new Date('2022-06-05'), + reviewChargeReferences: [ + { + id: reviewChargeReference.id, + aggregate: 1, + amendedAuthorisedVolume: 50, + chargeAdjustment: 1, + chargeReference: { + id: chargeReference.id, + chargeCategory: { + id: chargeCategory.id, + reference: chargeCategory.reference, + shortDescription: chargeCategory.shortDescription + } + }, + reviewChargeElements: [ + { + id: reviewChargeElement.id, + amendedAllocated: 0, + issues: '', + status: 'ready', + chargeElement: { + id: chargeElement.id, + abstractionPeriodStartDay: 1, + abstractionPeriodStartMonth: 4, + abstractionPeriodEndDay: 31, + abstractionPeriodEndMonth: 3, + authorisedAnnualQuantity: 200, + description: 'Trickle Irrigation - Direct', + purpose: { + id: purpose.id, + description: purpose.description + } + }, + reviewReturns: [ + { + id: reviewReturn.id, + quantity: 0, + returnReference: reviewReturn.returnReference, + returnStatus: 'completed' + } + ] + } + ] + } + ], + chargeVersion: { + id: chargeVersion.id, + billingAccount: { + id: billingAccount.id, + accountNumber: billingAccount.accountNumber, + billingAccountAddresses: [ + { + id: billingAccountAddress.id, + address: { + id: address.id, + address1: 'ENVIRONMENT AGENCY', + address2: 'HORIZON HOUSE', + address3: 'DEANERY ROAD', + address4: 'BRISTOL', + address5: null, + address6: null, + postcode: 'BS1 5AH', + country: 'United Kingdom' + }, + company: { + id: company.id, + name: 'Example Trading Ltd', + type: 'organisation' + }, + contact: { + id: contact.id, + contactType: 'person', + dataSource: 'wrls', + department: null, + firstName: 'Amara', + initials: null, + lastName: 'Gupta', + middleInitials: null, + salutation: null, + suffix: null + } + } + ], + company: { + id: company.id, + name: 'Example Trading Ltd', + type: 'organisation' + } + } + } + } + ] + }) + }) + }) + + describe('when no matching review licence exists', () => { + it('returns nothing', async () => { + const result = await FetchReviewLicenceService.go('dfa47d48-0c98-4707-a5b8-820eb16c1dfd') + + expect(result).to.be.undefined() + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.test.js b/test/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.test.js deleted file mode 100644 index 5afde19bb4..0000000000 --- a/test/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.test.js +++ /dev/null @@ -1,263 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') -const ChargeCategoryHelper = require('../../../support/helpers/charge-category.helper.js') -const ChargeElementHelper = require('../../../support/helpers/charge-element.helper.js') -const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') -const ChargeVersionHelper = require('../../../support/helpers/charge-version.helper.js') -const LicenceHelper = require('../../../support/helpers/licence.helper.js') -const PurposeHelper = require('../../../support/helpers/purpose.helper.js') -const RegionHelper = require('../../../support/helpers/region.helper.js') -const ReturnLogHelper = require('../../../support/helpers/return-log.helper.js') -const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') -const ReviewChargeElementReturnHelper = require('../../../support/helpers/review-charge-element-return.helper.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') -const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') -const ReviewReturnHelper = require('../../../support/helpers/review-return.helper.js') - -// Things we need to stub -const BillingAccountModel = require('../../../../app/models/billing-account.model.js') - -// Thing under test -const FetchReviewLicenceResultsService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-review-licence-results.service.js') - -describe('Fetch Review Licence Results Service', () => { - let billRun - let region - - afterEach(() => { - Sinon.restore() - }) - - describe('when there is a valid bill run', () => { - beforeEach(async () => { - region = RegionHelper.select() - billRun = await BillRunHelper.add({ regionId: region.id, batchType: 'two_part_tariff' }) - }) - - describe('and a valid licence that is included in the bill run', () => { - let licence - let reviewLicence - let chargeVersion - let reviewChargeVersion - let chargeReference - let reviewChargeReference - let chargeElement - let reviewChargeElement - let returnLog - let reviewReturn - let purpose - let chargeCategory - - beforeEach(async () => { - licence = await LicenceHelper.add() - reviewLicence = await ReviewLicenceHelper.add({ licenceId: licence.id, billRunId: billRun.id }) - - chargeVersion = await ChargeVersionHelper.add({ licenceId: licence.id, licenceRef: licence.licenceRef }) - reviewChargeVersion = await ReviewChargeVersionHelper.add({ - reviewLicenceId: reviewLicence.id, - chargeVersionId: chargeVersion.id - }) - - chargeCategory = ChargeCategoryHelper.select() - chargeReference = await ChargeReferenceHelper.add({ - chargeVersionId: chargeVersion.id, - chargeCategoryId: chargeCategory.id - }) - reviewChargeReference = await ReviewChargeReferenceHelper.add({ - reviewChargeVersionId: reviewChargeVersion.id, - chargeReferenceId: chargeReference.id - }) - - purpose = PurposeHelper.select() - chargeElement = await ChargeElementHelper.add({ chargeReferenceId: chargeReference.id, purposeId: purpose.id }) - reviewChargeElement = await ReviewChargeElementHelper.add({ - reviewChargeReferenceId: reviewChargeReference.id, - chargeElementId: chargeElement.id - }) - - const metadata = { - nald: { - periodEndDay: 30, - periodEndMonth: 9, - periodStartDay: 1, - periodStartMonth: 4 - } - } - - returnLog = await ReturnLogHelper.add({ licenceRef: licence.licenceRef, metadata }) - reviewReturn = await ReviewReturnHelper.add({ returnId: returnLog.id, reviewLicenceId: reviewLicence.id }) - - await ReviewChargeElementReturnHelper.add({ - reviewChargeElementId: reviewChargeElement.id, - reviewReturnId: reviewReturn.id - }) - - Sinon.stub(BillingAccountModel, 'query').returns({ - findById: Sinon.stub().returnsThis(), - modify: Sinon.stub().resolves([]) - }) - }) - - it('returns details of the bill run', async () => { - const result = await FetchReviewLicenceResultsService.go(billRun.id, licence.id) - - expect(result.billRun).to.equal({ - id: billRun.id, - fromFinancialYearEnding: 2023, - toFinancialYearEnding: 2023, - region: { - displayName: region.displayName - } - }) - }) - - it('returns the licence review data', async () => { - const result = await FetchReviewLicenceResultsService.go(billRun.id, licence.id) - - expect(result.licence).to.equal([{ - id: reviewLicence.id, - billRunId: billRun.id, - licenceId: licence.id, - licenceRef: reviewLicence.licenceRef, - licenceHolder: reviewLicence.licenceHolder, - issues: reviewLicence.issues, - status: reviewLicence.status, - progress: false, - hasReviewStatus: false, - reviewReturns: [{ - id: reviewReturn.id, - reviewLicenceId: reviewReturn.reviewLicenceId, - returnId: reviewReturn.returnId, - returnReference: reviewReturn.returnReference, - quantity: reviewReturn.quantity, - allocated: reviewReturn.allocated, - underQuery: reviewReturn.underQuery, - returnStatus: reviewReturn.returnStatus, - nilReturn: reviewReturn.nilReturn, - abstractionOutsidePeriod: reviewReturn.abstractionOutsidePeriod, - receivedDate: reviewReturn.receivedDate, - dueDate: reviewReturn.dueDate, - purposes: reviewReturn.purposes, - description: reviewReturn.description, - startDate: reviewReturn.startDate, - endDate: reviewReturn.endDate, - issues: reviewReturn.issues, - createdAt: reviewReturn.createdAt, - updatedAt: reviewReturn.updatedAt, - reviewChargeElements: [{ - id: reviewChargeElement.id, - reviewChargeReferenceId: reviewChargeElement.reviewChargeReferenceId, - chargeElementId: reviewChargeElement.chargeElementId, - allocated: reviewChargeElement.allocated, - amendedAllocated: reviewChargeElement.amendedAllocated, - chargeDatesOverlap: reviewChargeElement.chargeDatesOverlap, - issues: reviewChargeElement.issues, - status: reviewChargeElement.status, - createdAt: reviewChargeElement.createdAt, - updatedAt: reviewChargeElement.updatedAt - }], - returnLog: { - periodEndDay: returnLog.metadata.nald.periodEndDay, - periodEndMonth: returnLog.metadata.nald.periodEndMonth, - periodStartDay: returnLog.metadata.nald.periodStartDay, - periodStartMonth: returnLog.metadata.nald.periodStartMonth - } - }], - reviewChargeVersions: [{ - id: reviewChargeVersion.id, - reviewLicenceId: reviewLicence.id, - chargeVersionId: chargeVersion.id, - changeReason: reviewChargeVersion.changeReason, - chargePeriodStartDate: reviewChargeVersion.chargePeriodStartDate, - chargePeriodEndDate: reviewChargeVersion.chargePeriodEndDate, - createdAt: reviewChargeVersion.createdAt, - updatedAt: reviewChargeVersion.updatedAt, - reviewChargeReferences: [{ - id: reviewChargeReference.id, - reviewChargeVersionId: reviewChargeVersion.id, - chargeReferenceId: reviewChargeReference.chargeReferenceId, - aggregate: reviewChargeReference.aggregate, - amendedAggregate: reviewChargeReference.amendedAggregate, - chargeAdjustment: reviewChargeReference.chargeAdjustment, - amendedChargeAdjustment: reviewChargeReference.amendedChargeAdjustment, - canalAndRiverTrustAgreement: reviewChargeReference.canalAndRiverTrustAgreement, - abatementAgreement: reviewChargeReference.abatementAgreement, - winterDiscount: reviewChargeReference.winterDiscount, - twoPartTariffAgreement: reviewChargeReference.twoPartTariffAgreement, - authorisedVolume: reviewChargeReference.authorisedVolume, - amendedAuthorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - createdAt: reviewChargeReference.createdAt, - updatedAt: reviewChargeReference.updatedAt, - chargeReference: { - chargeCategoryId: chargeReference.chargeCategoryId, - chargeCategory: { - reference: chargeCategory.reference, - shortDescription: chargeCategory.shortDescription - } - }, - reviewChargeElements: [{ - id: reviewChargeElement.id, - reviewChargeReferenceId: reviewChargeElement.reviewChargeReferenceId, - chargeElementId: reviewChargeElement.chargeElementId, - allocated: reviewChargeElement.allocated, - amendedAllocated: reviewChargeElement.amendedAllocated, - chargeDatesOverlap: reviewChargeElement.chargeDatesOverlap, - issues: reviewChargeElement.issues, - status: reviewChargeElement.status, - createdAt: reviewChargeElement.createdAt, - updatedAt: reviewChargeElement.updatedAt, - chargeElement: { - description: chargeElement.description, - abstractionPeriodStartDay: chargeElement.abstractionPeriodStartDay, - abstractionPeriodStartMonth: chargeElement.abstractionPeriodStartMonth, - abstractionPeriodEndDay: chargeElement.abstractionPeriodEndDay, - abstractionPeriodEndMonth: chargeElement.abstractionPeriodEndMonth, - authorisedAnnualQuantity: chargeElement.authorisedAnnualQuantity, - purpose: { - description: purpose.description - } - }, - reviewReturns: [{ - id: reviewReturn.id, - reviewLicenceId: reviewReturn.reviewLicenceId, - returnId: reviewReturn.returnId, - returnReference: reviewReturn.returnReference, - quantity: reviewReturn.quantity, - allocated: reviewReturn.allocated, - underQuery: reviewReturn.underQuery, - returnStatus: reviewReturn.returnStatus, - nilReturn: reviewReturn.nilReturn, - abstractionOutsidePeriod: reviewReturn.abstractionOutsidePeriod, - receivedDate: reviewReturn.receivedDate, - dueDate: reviewReturn.dueDate, - purposes: reviewReturn.purposes, - description: reviewReturn.description, - startDate: reviewReturn.startDate, - endDate: reviewReturn.endDate, - issues: reviewReturn.issues, - createdAt: reviewReturn.createdAt, - updatedAt: reviewReturn.updatedAt - }] - }] - }], - chargeVersion: { - billingAccountId: chargeVersion.billingAccountId - }, - billingAccountDetails: [] - }] - }]) - }) - }) - }) -}) From 5faa056c3443c528476419b66faa194a48fdafac Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:35:08 +0000 Subject: [PATCH 127/147] Move, rename & refactor fetch chg elmnt service test --- ...etch-review-charge-element.service.test.js | 146 ++++++++++++++ .../fetch-match-details.service.test.js | 190 ------------------ 2 files changed, 146 insertions(+), 190 deletions(-) create mode 100644 test/services/bill-runs/review/fetch-review-charge-element.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/fetch-match-details.service.test.js diff --git a/test/services/bill-runs/review/fetch-review-charge-element.service.test.js b/test/services/bill-runs/review/fetch-review-charge-element.service.test.js new file mode 100644 index 0000000000..61f0a0f795 --- /dev/null +++ b/test/services/bill-runs/review/fetch-review-charge-element.service.test.js @@ -0,0 +1,146 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, before } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') +const ChargeElementHelper = require('../../../support/helpers/charge-element.helper.js') +const RegionHelper = require('../../../support/helpers/region.helper.js') +const ReturnLogHelper = require('../../../support/helpers/return-log.helper.js') +const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') +const ReviewChargeElementReturnHelper = require('../../../support/helpers/review-charge-element-return.helper.js') +const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') +const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') +const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') +const ReviewReturnHelper = require('../../../support/helpers/review-return.helper.js') + +// Thing under test +const FetchReviewChargeElementService = require('../../../../app/services/bill-runs/review/fetch-review-charge-element.service.js') + +describe('Bill Runs Review - Fetch Review Charge Element service', () => { + let billRun + let chargeElement + let returnLog + let reviewChargeElement + let reviewChargeVersion + let reviewChargeReference + let reviewLicence + let reviewReturn + + before(async () => { + const region = RegionHelper.select() + + billRun = await BillRunHelper.add({ batchType: 'two_part_tariff', regionId: region.id, status: 'review' }) + + returnLog = await ReturnLogHelper.add() + chargeElement = await ChargeElementHelper.add() + + reviewLicence = await ReviewLicenceHelper.add({ billRunId: billRun.id }) + reviewReturn = await ReviewReturnHelper.add({ + purposes: [{ + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '400', description: 'Spray Irrigation - Direct' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + }], + returnId: returnLog.id, + returnReference: returnLog.returnReference, + reviewLicenceId: reviewLicence.id + }) + + reviewChargeVersion = await ReviewChargeVersionHelper.add({ reviewLicenceId: reviewLicence.id }) + reviewChargeReference = await ReviewChargeReferenceHelper.add({ reviewChargeVersionId: reviewChargeVersion.id }) + reviewChargeElement = await ReviewChargeElementHelper.add({ + chargeElementId: chargeElement.id, reviewChargeReferenceId: reviewChargeReference.id + }) + + await ReviewChargeElementReturnHelper.add({ + reviewChargeElementId: reviewChargeElement.id, reviewReturnId: reviewReturn.id + }) + }) + + describe('when a matching review charge element exists', () => { + it('returns the match', async () => { + const result = await FetchReviewChargeElementService.go(reviewChargeElement.id) + + expect(result).to.equal({ + id: reviewChargeElement.id, + amendedAllocated: 0, + issues: '', + status: 'ready', + chargeElement: { + id: chargeElement.id, + abstractionPeriodStartDay: 1, + abstractionPeriodStartMonth: 4, + abstractionPeriodEndDay: 31, + abstractionPeriodEndMonth: 3, + authorisedAnnualQuantity: 200, + description: 'Trickle Irrigation - Direct' + }, + reviewChargeReference: { + id: reviewChargeReference.id, + amendedAuthorisedVolume: 50, + reviewChargeElements: [ + { + id: reviewChargeElement.id + } + ], + reviewChargeVersion: { + id: reviewChargeVersion.id, + chargePeriodStartDate: new Date('2022-04-01'), + chargePeriodEndDate: new Date('2022-06-05'), + reviewLicence: { + id: reviewLicence.id, + licenceId: reviewLicence.licenceId, + billRun: { + id: billRun.id, + toFinancialYearEnding: 2023 + } + } + } + }, + reviewReturns: [ + { + id: reviewReturn.id, + allocated: 0, + description: 'Lands at Mosshayne Farm, Exeter & Broadclyst', + endDate: new Date('2022-05-06'), + issues: '', + quantity: 0, + purposes: [ + { + primary: { code: 'A', description: 'Agriculture' }, + tertiary: { code: '400', description: 'Spray Irrigation - Direct' }, + secondary: { code: 'AGR', description: 'General Agriculture' } + } + ], + returnId: reviewReturn.returnId, + returnReference: reviewReturn.returnReference, + returnStatus: 'completed', + startDate: new Date('2022-04-01'), + underQuery: false, + returnLog: { + id: returnLog.id, + periodStartDay: 1, + periodStartMonth: 4, + periodEndDay: 28, + periodEndMonth: 4 + } + } + ] + }) + }) + }) + + describe('when no matching review charge element exists', () => { + it('returns nothing', async () => { + const result = await FetchReviewChargeElementService.go('dfa47d48-0c98-4707-a5b8-820eb16c1dfd') + + expect(result).to.be.undefined() + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/fetch-match-details.service.test.js b/test/services/bill-runs/two-part-tariff/fetch-match-details.service.test.js deleted file mode 100644 index 8ccc5d15af..0000000000 --- a/test/services/bill-runs/two-part-tariff/fetch-match-details.service.test.js +++ /dev/null @@ -1,190 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') -const ChargeElementHelper = require('../../../support/helpers/charge-element.helper.js') -const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') -const ReturnLogHelper = require('../../../support/helpers/return-log.helper.js') -const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') -const ReviewChargeElementReturnHelper = require('../../../support/helpers/review-charge-element-return.helper.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') -const ReviewReturnHelper = require('../../../support/helpers/review-return.helper.js') - -// Thing under test -const FetchMatchDetailsService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-match-details.service.js') - -describe('Fetch Match Details service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when there is a valid bill run', () => { - let billRun - - beforeEach(async () => { - billRun = await BillRunHelper.add() - }) - - describe('and a valid review charge element', () => { - let reviewChargeElement - let chargeElement - let chargeReference - let reviewChargeVersion - let reviewChargeReference - let returnLog - - beforeEach(async () => { - reviewChargeVersion = await ReviewChargeVersionHelper.add() - chargeReference = await ChargeReferenceHelper.add() - reviewChargeReference = await ReviewChargeReferenceHelper.add( - { reviewChargeVersionId: reviewChargeVersion.id, chargeReferenceId: chargeReference.id } - ) - - chargeElement = await ChargeElementHelper.add({ chargeReferenceId: reviewChargeReference.chargeReferenceId }) - reviewChargeElement = await ReviewChargeElementHelper.add( - { reviewChargeReferenceId: reviewChargeReference.id, chargeElementId: chargeElement.id } - ) - }) - - describe('that has a matching return', () => { - let reviewReturn - - beforeEach(async () => { - const metadata = { - nald: { - periodEndDay: 30, - periodEndMonth: 9, - periodStartDay: 1, - periodStartMonth: 4 - } - } - - returnLog = await ReturnLogHelper.add({ metadata }) - reviewReturn = await ReviewReturnHelper.add({ returnId: returnLog.id }) - - await ReviewChargeElementReturnHelper.add({ - reviewChargeElementId: reviewChargeElement.id, - reviewReturnId: reviewReturn.id - }) - }) - - it('returns details of the bill run', async () => { - const result = await FetchMatchDetailsService.go(billRun.id, reviewChargeElement.id) - - expect(result.billRun).to.equal({ - id: billRun.id, - fromFinancialYearEnding: billRun.fromFinancialYearEnding, - toFinancialYearEnding: billRun.toFinancialYearEnding - }) - }) - - it('returns details of the charge element and its matched returns', async () => { - const result = await FetchMatchDetailsService.go(billRun.id, reviewChargeElement.id) - - expect(result.reviewChargeElement).to.equal({ - id: reviewChargeElement.id, - reviewChargeReferenceId: reviewChargeReference.id, - chargeElementId: chargeElement.id, - allocated: reviewChargeElement.allocated, - amendedAllocated: reviewChargeElement.amendedAllocated, - chargeDatesOverlap: reviewChargeElement.chargeDatesOverlap, - issues: reviewChargeElement.issues, - status: reviewChargeElement.status, - createdAt: reviewChargeElement.createdAt, - updatedAt: reviewChargeElement.updatedAt, - reviewReturns: [ - { - id: reviewReturn.id, - reviewLicenceId: reviewReturn.reviewLicenceId, - returnId: reviewReturn.returnId, - returnReference: reviewReturn.returnReference, - quantity: reviewReturn.quantity, - allocated: reviewReturn.allocated, - underQuery: reviewReturn.underQuery, - returnStatus: reviewReturn.returnStatus, - nilReturn: reviewReturn.nilReturn, - abstractionOutsidePeriod: reviewReturn.abstractionOutsidePeriod, - receivedDate: reviewReturn.receivedDate, - dueDate: reviewReturn.dueDate, - purposes: {}, - description: reviewReturn.description, - startDate: reviewReturn.startDate, - endDate: reviewReturn.endDate, - issues: reviewReturn.issues, - createdAt: reviewReturn.createdAt, - updatedAt: reviewReturn.updatedAt, - returnLog: { - periodEndDay: returnLog.metadata.nald.periodEndDay, - periodEndMonth: returnLog.metadata.nald.periodEndMonth, - periodStartDay: returnLog.metadata.nald.periodStartDay, - periodStartMonth: returnLog.metadata.nald.periodStartMonth - } - } - ], - chargeElement: { - description: chargeElement.description, - abstractionPeriodStartDay: chargeElement.abstractionPeriodStartDay, - abstractionPeriodStartMonth: chargeElement.abstractionPeriodStartMonth, - abstractionPeriodEndDay: chargeElement.abstractionPeriodEndDay, - abstractionPeriodEndMonth: chargeElement.abstractionPeriodEndMonth, - authorisedAnnualQuantity: chargeElement.authorisedAnnualQuantity - }, - reviewChargeReference: { - id: reviewChargeReference.id, - amendedAuthorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - reviewChargeVersion: { - chargePeriodStartDate: reviewChargeVersion.chargePeriodStartDate, - chargePeriodEndDate: reviewChargeVersion.chargePeriodEndDate - } - } - }) - }) - }) - - describe('with a charge element that did not match to a return', () => { - it('does not return any matching return details', async () => { - const result = await FetchMatchDetailsService.go(billRun.id, reviewChargeElement.id) - - expect(result.reviewChargeElement).to.equal({ - id: reviewChargeElement.id, - reviewChargeReferenceId: reviewChargeReference.id, - chargeElementId: chargeElement.id, - allocated: reviewChargeElement.allocated, - amendedAllocated: reviewChargeElement.amendedAllocated, - chargeDatesOverlap: reviewChargeElement.chargeDatesOverlap, - issues: reviewChargeElement.issues, - status: reviewChargeElement.status, - createdAt: reviewChargeElement.createdAt, - updatedAt: reviewChargeElement.updatedAt, - reviewReturns: [], - chargeElement: { - description: chargeElement.description, - abstractionPeriodStartDay: chargeElement.abstractionPeriodStartDay, - abstractionPeriodStartMonth: chargeElement.abstractionPeriodStartMonth, - abstractionPeriodEndDay: chargeElement.abstractionPeriodEndDay, - abstractionPeriodEndMonth: chargeElement.abstractionPeriodEndMonth, - authorisedAnnualQuantity: chargeElement.authorisedAnnualQuantity - }, - reviewChargeReference: { - id: reviewChargeReference.id, - amendedAuthorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - reviewChargeVersion: { - chargePeriodStartDate: reviewChargeVersion.chargePeriodStartDate, - chargePeriodEndDate: reviewChargeVersion.chargePeriodEndDate - } - } - }) - }) - }) - }) - }) -}) From dc586ac884674d7e812e55c7a2084af5ceb16147 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:35:31 +0000 Subject: [PATCH 128/147] Move, rename & refactor review chg ref service test --- .../fetch-review-charge-reference.test.js | 123 ++++++++++++++++++ ...ch-review-charge-reference.service.test.js | 109 ---------------- 2 files changed, 123 insertions(+), 109 deletions(-) create mode 100644 test/services/bill-runs/review/fetch-review-charge-reference.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.test.js diff --git a/test/services/bill-runs/review/fetch-review-charge-reference.test.js b/test/services/bill-runs/review/fetch-review-charge-reference.test.js new file mode 100644 index 0000000000..fe623d9f79 --- /dev/null +++ b/test/services/bill-runs/review/fetch-review-charge-reference.test.js @@ -0,0 +1,123 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, before } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') +const ChargeCategoryHelper = require('../../../support/helpers/charge-category.helper.js') +const ChargeElementHelper = require('../../../support/helpers/charge-element.helper.js') +const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') +const LicenceHelper = require('../../../support/helpers/licence.helper.js') +const RegionHelper = require('../../../support/helpers/region.helper.js') +const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') +const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') +const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') +const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') + +// Thing under test +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') + +describe('Bill Runs Review - Fetch Review Charge Reference service', () => { + let billRun + let chargeCategory + let chargeElement + let chargeReference + let licence + let reviewChargeElement + let reviewChargeVersion + let reviewChargeReference + let reviewLicence + + before(async () => { + const region = RegionHelper.select() + + billRun = await BillRunHelper.add({ batchType: 'two_part_tariff', regionId: region.id, status: 'review' }) + + chargeCategory = ChargeCategoryHelper.select() + chargeReference = await ChargeReferenceHelper.add({ + additionalCharges: { isSupplyPublicWater: true, supportedSource: { name: 'Foo source' } }, + chargeCategoryId: chargeCategory.id + }) + chargeElement = await ChargeElementHelper.add({ chargeReferenceId: chargeReference.id }) + licence = await LicenceHelper.add() + + reviewLicence = await ReviewLicenceHelper.add({ + billRunId: billRun.id, licenceId: licence.id, licenceRef: licence.licenceRef + }) + + reviewChargeVersion = await ReviewChargeVersionHelper.add({ reviewLicenceId: reviewLicence.id }) + reviewChargeReference = await ReviewChargeReferenceHelper.add({ + chargeReferenceId: chargeReference.id, + reviewChargeVersionId: reviewChargeVersion.id + }) + reviewChargeElement = await ReviewChargeElementHelper.add({ + chargeElementId: chargeElement.id, reviewChargeReferenceId: reviewChargeReference.id + }) + }) + + describe('when a matching review charge reference exists', () => { + it('returns the match', async () => { + const result = await FetchReviewChargeReferenceService.go(reviewChargeReference.id) + + expect(result).to.equal({ + id: reviewChargeReference.id, + abatementAgreement: 1, + aggregate: 1, + amendedAggregate: 1, + amendedAuthorisedVolume: 50, + amendedChargeAdjustment: 1, + canalAndRiverTrustAgreement: false, + chargeAdjustment: 1, + twoPartTariffAgreement: true, + winterDiscount: false, + reviewChargeVersion: { + id: reviewChargeVersion.id, + chargePeriodStartDate: new Date('2022-04-01'), + chargePeriodEndDate: new Date('2022-06-05'), + reviewLicence: { + id: reviewLicence.id, + billRun: { + id: billRun.id, + toFinancialYearEnding: 2023 + }, + licence: { + id: licence.id, + waterUndertaker: false + } + } + }, + reviewChargeElements: [ + { + id: reviewChargeElement.id, + amendedAllocated: 0 + } + ], + chargeReference: { + id: chargeReference.id, + volume: 6.819, + loss: 'low', + supportedSourceName: 'Foo source', + waterCompanyCharge: 'true', + chargeCategory: { + id: chargeCategory.id, + reference: chargeCategory.reference, + shortDescription: chargeCategory.shortDescription + } + } + }) + }) + }) + + describe('when no matching review charge reference exists', () => { + it('returns nothing', async () => { + const result = await FetchReviewChargeReferenceService.go('dfa47d48-0c98-4707-a5b8-820eb16c1dfd') + + expect(result).to.be.undefined() + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.test.js b/test/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.test.js deleted file mode 100644 index b303c15461..0000000000 --- a/test/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.test.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') -const ChargeCategoryHelper = require('../../../support/helpers/charge-category.helper.js') -const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') -const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') - -// Thing under test -const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js') - -describe('Fetch Review Charge Reference service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when there is a valid bill run', () => { - let billRun - - beforeEach(async () => { - billRun = await BillRunHelper.add() - }) - - describe('and a valid review charge reference', () => { - let reviewChargeReference - let chargeReference - let reviewChargeVersion - let reviewChargeElement - let chargeCategory - - beforeEach(async () => { - reviewChargeVersion = await ReviewChargeVersionHelper.add() - chargeCategory = ChargeCategoryHelper.select() - chargeReference = await ChargeReferenceHelper.add({ - chargeCategoryId: chargeCategory.id, - additionalCharges: { - isSupplyPublicWater: true, - supportedSource: { - name: 'Thames' - } - } - }) - reviewChargeReference = await ReviewChargeReferenceHelper.add({ - reviewChargeVersionId: reviewChargeVersion.id, - chargeReferenceId: chargeReference.id - }) - reviewChargeElement = await ReviewChargeElementHelper.add({ reviewChargeReferenceId: reviewChargeReference.id }) - }) - - it('returns details of the bill run', async () => { - const result = await FetchReviewChargeReferenceService.go(billRun.id, reviewChargeReference.id) - - expect(result.billRun).to.equal({ - id: billRun.id, - toFinancialYearEnding: billRun.toFinancialYearEnding - }) - }) - - it('returns details of the review charge reference', async () => { - const result = await FetchReviewChargeReferenceService.go(billRun.id, reviewChargeReference.id) - - expect(result.reviewChargeReference).to.equal({ - id: reviewChargeReference.id, - reviewChargeVersionId: reviewChargeVersion.id, - chargeReferenceId: chargeReference.id, - aggregate: reviewChargeReference.aggregate, - createdAt: reviewChargeReference.createdAt, - updatedAt: reviewChargeReference.updatedAt, - amendedAggregate: reviewChargeReference.amendedAggregate, - chargeAdjustment: reviewChargeReference.chargeAdjustment, - amendedChargeAdjustment: reviewChargeReference.amendedChargeAdjustment, - abatementAgreement: reviewChargeReference.abatementAgreement, - winterDiscount: reviewChargeReference.winterDiscount, - twoPartTariffAgreement: reviewChargeReference.twoPartTariffAgreement, - canalAndRiverTrustAgreement: reviewChargeReference.canalAndRiverTrustAgreement, - authorisedVolume: reviewChargeReference.authorisedVolume, - amendedAuthorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - reviewChargeVersion: { - chargePeriodStartDate: reviewChargeVersion.chargePeriodStartDate, - chargePeriodEndDate: reviewChargeVersion.chargePeriodEndDate - }, - reviewChargeElements: [{ - amendedAllocated: reviewChargeElement.amendedAllocated - }], - chargeReference: { - volume: chargeReference.volume, - chargeCategoryId: chargeCategory.id, - supportedSourceName: chargeReference.additionalCharges.supportedSource.name, - waterCompanyCharge: `${chargeReference.additionalCharges.isSupplyPublicWater}`, - chargeCategory: { - reference: chargeCategory.reference, - shortDescription: chargeCategory.shortDescription - } - } - }) - }) - }) - }) -}) From 60ad24d6748a7546f7e8db446b8d2c46cf113c32 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:36:11 +0000 Subject: [PATCH 129/147] Add new fetch remove review licence service test --- ...etch-remove-review-licence.service.test.js | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 test/services/bill-runs/review/fetch-remove-review-licence.service.test.js diff --git a/test/services/bill-runs/review/fetch-remove-review-licence.service.test.js b/test/services/bill-runs/review/fetch-remove-review-licence.service.test.js new file mode 100644 index 0000000000..387fbb15ef --- /dev/null +++ b/test/services/bill-runs/review/fetch-remove-review-licence.service.test.js @@ -0,0 +1,61 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') + +const { describe, it, before } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') +const RegionHelper = require('../../../support/helpers/region.helper.js') +const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') + +// Thing under test +const FetchRemoveReviewLicenceService = require('../../../../app/services/bill-runs/review/fetch-remove-review-licence.service.js') + +describe('Bill Runs Review - Fetch Remove Review Licence service', () => { + let billRun + let region + let reviewLicence + + before(async () => { + region = RegionHelper.select() + + billRun = await BillRunHelper.add({ batchType: 'two_part_tariff', regionId: region.id, status: 'review' }) + + reviewLicence = await ReviewLicenceHelper.add({ billRunId: billRun.id }) + }) + + describe('when a matching review licence exists', () => { + it('returns the match', async () => { + const result = await FetchRemoveReviewLicenceService.go(reviewLicence.id) + + expect(result).to.equal({ + id: reviewLicence.id, + licenceId: reviewLicence.licenceId, + licenceRef: reviewLicence.licenceRef, + billRun: { + id: billRun.id, + billRunNumber: billRun.billRunNumber, + createdAt: billRun.createdAt, + status: 'review', + toFinancialYearEnding: billRun.toFinancialYearEnding, + region: { + id: region.id, + displayName: region.displayName + } + } + }) + }) + }) + + describe('when no matching review licence exists', () => { + it('returns nothing', async () => { + const result = await FetchRemoveReviewLicenceService.go('dfa47d48-0c98-4707-a5b8-820eb16c1dfd') + + expect(result).to.be.undefined() + }) + }) +}) From cc8878bb23fece7b94fda84beffc4311baba58ec Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:36:45 +0000 Subject: [PATCH 130/147] Update fetch bill run licences service test --- .../bill-runs/review/fetch-bill-run-licences.service.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/services/bill-runs/review/fetch-bill-run-licences.service.test.js b/test/services/bill-runs/review/fetch-bill-run-licences.service.test.js index 5f15250f09..4e07006003 100644 --- a/test/services/bill-runs/review/fetch-bill-run-licences.service.test.js +++ b/test/services/bill-runs/review/fetch-bill-run-licences.service.test.js @@ -17,7 +17,7 @@ const ReviewLicenceHelper = require('../../../support/helpers/review-licence.hel // Thing under test const FetchBillRunLicencesService = require('../../../../app/services/bill-runs/review/fetch-bill-run-licences.service.js') -describe('Fetch Bill Run Licences service', () => { +describe('Bill Runs Review - Fetch Bill Run Licences service', () => { let filterIssues let filterLicenceHolderNumber let filterLicenceStatus From 868fb438b81d584e884a2f2b89dfcee065f86fb3 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:37:13 +0000 Subject: [PATCH 131/147] Update review bill run service test --- test/services/bill-runs/review/review-bill-run.service.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/services/bill-runs/review/review-bill-run.service.test.js b/test/services/bill-runs/review/review-bill-run.service.test.js index 79eb6db7ea..253e46dc5c 100644 --- a/test/services/bill-runs/review/review-bill-run.service.test.js +++ b/test/services/bill-runs/review/review-bill-run.service.test.js @@ -19,7 +19,7 @@ const ReviewBillRunPresenter = require('../../../../app/presenters/bill-runs/rev // Thing under test const ReviewBillRunService = require('../../../../app/services/bill-runs/review/review-bill-run.service.js') -describe('Review Bill Run Service', () => { +describe('Bill Runs Review - Review Bill Run Service', () => { const billRunId = '2c80bd22-a005-4cf4-a2a2-73812a9861de' let page From 53512a9b29f5937131982b925eafa3a0cc5bceb5 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Wed, 6 Nov 2024 23:37:33 +0000 Subject: [PATCH 132/147] Remove redundant fetch authorised volume service test --- .../fetch-authorised-volume.service.test.js | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 test/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.test.js diff --git a/test/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.test.js b/test/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.test.js deleted file mode 100644 index 2b47648da8..0000000000 --- a/test/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.test.js +++ /dev/null @@ -1,86 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') -const ChargeCategoryHelper = require('../../../support/helpers/charge-category.helper.js') -const ChargeReferenceHelper = require('../../../support/helpers/charge-reference.helper.js') -const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeVersionHelper = require('../../../support/helpers/review-charge-version.helper.js') - -// Thing under test -const FetchAuthorisedVolumeService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js') - -describe('Fetch Authorised Volume service', () => { - afterEach(() => { - Sinon.restore() - }) - - describe('when there is a valid bull run', () => { - let billRun - - beforeEach(async () => { - billRun = await BillRunHelper.add() - }) - - describe('and a valid review charge reference', () => { - let reviewChargeReference - let chargeReference - let reviewChargeVersion - let reviewChargeElement - let chargeCategory - - beforeEach(async () => { - reviewChargeVersion = await ReviewChargeVersionHelper.add() - chargeCategory = ChargeCategoryHelper.select() - chargeReference = await ChargeReferenceHelper.add({ chargeCategoryId: chargeCategory.id }) - reviewChargeReference = await ReviewChargeReferenceHelper.add({ - reviewChargeVersionId: reviewChargeVersion.id, - chargeReferenceId: chargeReference.id - }) - reviewChargeElement = await ReviewChargeElementHelper.add({ reviewChargeReferenceId: reviewChargeReference.id }) - }) - - it('returns details of the bill run', async () => { - const result = await FetchAuthorisedVolumeService.go(billRun.id, reviewChargeReference.id) - - expect(result.billRun).to.equal({ - id: billRun.id, - toFinancialYearEnding: billRun.toFinancialYearEnding - }) - }) - - it('returns details of the review charge reference', async () => { - const result = await FetchAuthorisedVolumeService.go(billRun.id, reviewChargeReference.id) - - expect(result.reviewChargeReference).to.equal({ - id: reviewChargeReference.id, - amendedAuthorisedVolume: reviewChargeReference.amendedAuthorisedVolume, - chargeReference: { - chargeCategoryId: chargeCategory.id, - chargeCategory: { - shortDescription: chargeCategory.shortDescription, - maxVolume: chargeCategory.maxVolume, - minVolume: chargeCategory.minVolume - } - }, - reviewChargeElements: [{ - amendedAllocated: reviewChargeElement.amendedAllocated - }], - reviewChargeVersion: { - chargePeriodStartDate: reviewChargeVersion.chargePeriodStartDate, - chargePeriodEndDate: reviewChargeVersion.chargePeriodEndDate - } - }) - }) - }) - }) -}) From 57ebd41f8d081f3aa6ced1f7026c7d44f0afba2c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 01:04:02 +0000 Subject: [PATCH 133/147] Move, rename & refactor submit authorised test --- .../review/submit-authorised.service.test.js | 98 ++++++++++++ ...-amended-authorised-volume.service.test.js | 147 ------------------ 2 files changed, 98 insertions(+), 147 deletions(-) create mode 100644 test/services/bill-runs/review/submit-authorised.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.test.js diff --git a/test/services/bill-runs/review/submit-authorised.service.test.js b/test/services/bill-runs/review/submit-authorised.service.test.js new file mode 100644 index 0000000000..3d45221399 --- /dev/null +++ b/test/services/bill-runs/review/submit-authorised.service.test.js @@ -0,0 +1,98 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') +const ReviewChargeReferenceModel = require('../../../../app/models/review-charge-reference.model.js') + +// Thing under test +const SubmitAuthorisedService = require('../../../../app/services/bill-runs/review/submit-authorised.service.js') + +describe('Bill Runs Review - Submit Authorised Service', () => { + let payload + let patchStub + let reviewChargeReference + let yarStub + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + + patchStub = Sinon.stub().resolves() + Sinon.stub(ReviewChargeReferenceModel, 'query').returns({ + findById: Sinon.stub().withArgs(reviewChargeReference.id).returnsThis(), + patch: patchStub + }) + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('with a valid payload', () => { + beforeEach(async () => { + payload = { amendedAuthorisedVolume: '9.092', totalBillableReturns: '9.092' } + }) + + it('saves the submitted value, adds a flash message and returns an empty object', async () => { + const result = await SubmitAuthorisedService.go(reviewChargeReference.id, yarStub, payload) + + // Check we save the change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ amendedAuthorisedVolume: '9.092' }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('The authorised volume for this licence have been updated') + + // Check we return an empty object (controller knows POST was successful so redirects) + expect(result).to.equal({}) + }) + }) + + describe('with an invalid payload', () => { + beforeEach(async () => { + payload = { amendedAuthorisedVolume: '-1', totalBillableReturns: '9.092' } + }) + + it('does not save the submitted value or add a flash message, and returns the page data including an error', async () => { + const result = await SubmitAuthorisedService.go(reviewChargeReference.id, yarStub, payload) + + // Check we didn't save + expect(patchStub.called).to.be.false() + + // Check we didn't add the flash message + expect(yarStub.flash.called).to.be.false() + + // Check we return page data including error (controller knows POST failed so re-renders) + expect(result).to.equal({ + amendedAuthorisedVolume: 9.092, + error: { text: 'The authorised volume must be greater than 9.092' }, + pageTitle: 'Set the authorised volume', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023', + totalBillableReturns: 0 + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.test.js b/test/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.test.js deleted file mode 100644 index 1dfaac82ce..0000000000 --- a/test/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.test.js +++ /dev/null @@ -1,147 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const AmendAuthorisedVolumePresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-authorised-volume.presenter.js') -const FetchAuthorisedVolumeService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-authorised-volume.service.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeReferenceModel = require('../../../../app/models/review-charge-reference.model.js') - -// Thing under test -const SubmitAmendedAuthorisedVolumeService = require('../../../../app/services/bill-runs/two-part-tariff/submit-amended-authorised-volume.service.js') - -describe('Submit Amended Authorised Volume Service', () => { - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - let payload - let reviewChargeReference - let yarStub - - beforeEach(async () => { - yarStub = { flash: Sinon.stub() } - - reviewChargeReference = await ReviewChargeReferenceHelper.add() - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when called', () => { - describe('with a valid payload for authorised volume', () => { - beforeEach(async () => { - payload = { - authorisedVolume: '10', - totalBillableReturns: '5', - minVolume: '5', - maxVolume: '20' - } - }) - - it('saves the users entered value', async () => { - await SubmitAmendedAuthorisedVolumeService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const reviewChargeReferenceData = await _fetchReviewChargeReference(reviewChargeReference.id) - - expect(reviewChargeReferenceData.amendedAuthorisedVolume).to.equal(10) - }) - - it('sets the banner message to "The authorised volume for this licence have been updated"', async () => { - await SubmitAmendedAuthorisedVolumeService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The authorised volume for this licence have been updated') - }) - }) - - describe('with an invalid payload', () => { - beforeEach(() => { - Sinon.stub(FetchAuthorisedVolumeService, 'go').resolves({ billRun: 'bill run', reviewChargeReference: 'charge reference' }) - Sinon.stub(AmendAuthorisedVolumePresenter, 'go').returns(_amendAuthorisedVolumeData()) - }) - - describe('because the user left the authorised volume input blank', () => { - beforeEach(() => { - payload = { - totalBillableReturns: '5', - minVolume: '5', - maxVolume: '20' - } - }) - - it('returns the page data for the view', async () => { - const result = await SubmitAmendedAuthorisedVolumeService.go( - billRunId, licenceId, reviewChargeReference.id, payload, yarStub - ) - - expect(result).to.equal({ - activeNavBar: 'search', - pageTitle: 'Set the authorised volume', - id: '6b3d11f2-d361-4eaa-bce2-5561283bd023', - amendedAuthorisedVolume: 25.5, - chargeReference: { - chargeCategoryId: 'b4354db6-6699-4987-b4c8-d53ac2bf2250', - chargeCategory: { - shortDescription: 'Medium loss, non-tidal, greater than 83 up to and including 142 ML/yr', - minVolume: 83, - maxVolume: 142 - } - }, - reviewChargeElements: [{ amendedAllocated: 15 }], - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-01') - } - }, { skip: ['error'] }) - }) - - it('returns the page data with an error for the authorised volume input element', async () => { - const result = await SubmitAmendedAuthorisedVolumeService.go( - billRunId, licenceId, reviewChargeReference.id, payload, yarStub - ) - - expect(result.error).to.equal({ - authorisedVolume: 'Enter an authorised volume' - }) - }) - }) - }) - }) -}) - -function _amendAuthorisedVolumeData () { - return { - id: '6b3d11f2-d361-4eaa-bce2-5561283bd023', - amendedAuthorisedVolume: 25.5, - chargeReference: { - chargeCategoryId: 'b4354db6-6699-4987-b4c8-d53ac2bf2250', - chargeCategory: { - shortDescription: 'Medium loss, non-tidal, greater than 83 up to and including 142 ML/yr', - minVolume: 83, - maxVolume: 142 - } - }, - reviewChargeElements: [{ - amendedAllocated: 15 - }], - reviewChargeVersion: { - chargePeriodStartDate: new Date('2022-04-01'), - chargePeriodEndDate: new Date('2022-06-01') - } - } -} - -async function _fetchReviewChargeReference (id) { - return ReviewChargeReferenceModel.query() - .findById(id) -} From f936ce160c76fb16fca9dffb65ee2c273ba3f02c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 01:04:27 +0000 Subject: [PATCH 134/147] Move, rename & refactor submit edit test --- .../review/submit-edit.service.test.js | 180 ++++++++++++++ ...t-amended-billable-returns.service.test.js | 235 ------------------ 2 files changed, 180 insertions(+), 235 deletions(-) create mode 100644 test/services/bill-runs/review/submit-edit.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.test.js diff --git a/test/services/bill-runs/review/submit-edit.service.test.js b/test/services/bill-runs/review/submit-edit.service.test.js new file mode 100644 index 0000000000..0db8ea9496 --- /dev/null +++ b/test/services/bill-runs/review/submit-edit.service.test.js @@ -0,0 +1,180 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeElementService = require('../../../../app/services/bill-runs/review/fetch-review-charge-element.service.js') +const ReviewChargeElementModel = require('../../../../app/models/review-charge-element.model.js') + +// Thing under test +const SubmitEditService = require('../../../../app/services/bill-runs/review/submit-edit.service.js') + +describe('Bill Runs Review - Submit Edit Service', () => { + const elementIndex = 1 + + let payload + let patchStub + let reviewChargeElement + let yarStub + + beforeEach(() => { + reviewChargeElement = BillRunsReviewFixture.reviewChargeElement() + + Sinon.stub(FetchReviewChargeElementService, 'go').resolves(reviewChargeElement) + + patchStub = Sinon.stub().resolves() + Sinon.stub(ReviewChargeElementModel, 'query').returns({ + findById: Sinon.stub().withArgs(reviewChargeElement.id).returnsThis(), + patch: patchStub + }) + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('with a valid payload', () => { + describe('where the user has selected the authorised quantity', () => { + beforeEach(async () => { + payload = { quantityOptions: 25, authorisedVolume: 30 } + }) + + it('saves the submitted value, adds a flash message and returns an empty object', async () => { + const result = await SubmitEditService.go(reviewChargeElement.id, elementIndex, yarStub, payload) + + // Check we save the change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ amendedAllocated: 25 }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('The billable returns for this licence have been updated') + + // Check we return an empty object (controller knows POST was successful so redirects) + expect(result).to.equal({}) + }) + }) + + describe('where the user has a custom quantity', () => { + beforeEach(async () => { + payload = { quantityOptions: 'customQuantity', customQuantity: 12, authorisedVolume: 30 } + }) + + it('saves the submitted value, adds a flash message and returns an empty object', async () => { + const result = await SubmitEditService.go(reviewChargeElement.id, elementIndex, yarStub, payload) + + // Check we save the change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ amendedAllocated: 12 }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('The billable returns for this licence have been updated') + + // Check we return an empty object (controller knows POST was successful so redirects) + expect(result).to.equal({}) + }) + }) + }) + + describe('with an invalid payload', () => { + describe('because the user did not select an option', () => { + beforeEach(async () => { + payload = { authorisedVolume: 30 } + }) + + it('does not save the submitted value or add a flash message, and returns the page data including an error', async () => { + const result = await SubmitEditService.go(reviewChargeElement.id, elementIndex, yarStub, payload) + + // Check we didn't save + expect(patchStub.called).to.be.false() + + // Check we didn't add the flash message + expect(yarStub.flash.called).to.be.false() + + // Check we return page data including error (controller knows POST failed so re-renders) + expect(result).to.equal({ + customQuantitySelected: false, + customQuantityValue: undefined, + error: { + errorList: [ + { + href: '#quantityOptions-error', + text: 'Select the billable quantity' + } + ], + quantityOptionsErrorMessage: { text: 'Select the billable quantity' } + }, + pageTitle: 'Set the billable returns quantity for this bill run', + authorisedQuantity: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementIndex: 1, + financialPeriod: '2023 to 2024', + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' + }) + }) + }) + + describe('because the submitted an invalid custom quantity', () => { + beforeEach(async () => { + payload = { quantityOptions: 'customQuantity', customQuantity: -0.1, authorisedVolume: 25 } + }) + + it('does not save the submitted value or add a flash message, and returns the page data including an error', async () => { + const result = await SubmitEditService.go(reviewChargeElement.id, elementIndex, yarStub, payload) + + // Check we didn't save + expect(patchStub.called).to.be.false() + + // Check we didn't add the flash message + expect(yarStub.flash.called).to.be.false() + + // Check we return page data including error (controller knows POST failed so re-renders) + expect(result).to.equal({ + customQuantitySelected: true, + customQuantityValue: -0.1, + error: { + errorList: [ + { + href: '#custom-quantity', + text: 'The quantity must be zero or higher' + } + ], + customQuantityErrorMessage: { text: 'The quantity must be zero or higher' } + }, + pageTitle: 'Set the billable returns quantity for this bill run', + authorisedQuantity: 9.092, + billableReturns: 0, + chargeDescription: 'Spray Irrigation - Direct', + chargePeriod: '1 April 2023 to 31 March 2024', + chargePeriods: ['1 April 2023 to 30 September 2023'], + elementIndex: 1, + financialPeriod: '2023 to 2024', + reviewChargeElementId: 'a1840523-a04c-4c64-bff7-4a515e8ba1c1' + }) + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.test.js b/test/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.test.js deleted file mode 100644 index 4e260a60b0..0000000000 --- a/test/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.test.js +++ /dev/null @@ -1,235 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const ReviewChargeElementHelper = require('../../../support/helpers/review-charge-element.helper.js') -const ReviewChargeElementModel = require('../../../../app/models/review-charge-element.model.js') - -// Things we need to stub -const FetchMatchDetailsService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-match-details.service.js') -const AmendBillableReturnsPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-billable-returns.presenter.js') - -// Thing under test -const SubmitAmendedBillableReturnsService = require('../../../../app/services/bill-runs/two-part-tariff/submit-amended-billable-returns.service.js') - -describe('Submit Amended Billable Returns Service', () => { - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - let payload - let reviewChargeElement - let yarStub - - beforeEach(async () => { - yarStub = { flash: Sinon.stub() } - - reviewChargeElement = await ReviewChargeElementHelper.add() - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when called', () => { - describe('with a valid payload for quantityOptions', () => { - beforeEach(async () => { - payload = { - 'quantity-options': 10, - authorisedVolume: 11 - } - }) - - it('saves the submitted option', async () => { - await SubmitAmendedBillableReturnsService.go(billRunId, licenceId, reviewChargeElement.id, payload, yarStub) - - const reviewChargeElementData = await _fetchReviewChargeElement(reviewChargeElement.id) - - expect(reviewChargeElementData.amendedAllocated).to.equal(10) - }) - - it('sets the banner message to "The billable returns for this licence have been updated"', async () => { - await SubmitAmendedBillableReturnsService.go(billRunId, licenceId, reviewChargeElement.id, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The billable returns for this licence have been updated') - }) - }) - - describe('with a valid payload for customQuantity', () => { - beforeEach(async () => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: 20, - authorisedVolume: 25 - } - }) - - it('saves the submitted value', async () => { - await SubmitAmendedBillableReturnsService.go(billRunId, licenceId, reviewChargeElement.id, payload, yarStub) - - const reviewChargeElementData = await _fetchReviewChargeElement(reviewChargeElement.id) - - expect(reviewChargeElementData.amendedAllocated).to.equal(20) - }) - - it('sets the banner message to "The billable returns for this licence have been updated"', async () => { - await SubmitAmendedBillableReturnsService.go(billRunId, licenceId, reviewChargeElement.id, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The billable returns for this licence have been updated') - }) - }) - - describe('with an invalid payload', () => { - beforeEach(() => { - Sinon.stub(FetchMatchDetailsService, 'go').resolves({ billRun: 'bill run', reviewChargeElement: 'charge element' }) - Sinon.stub(AmendBillableReturnsPresenter, 'go').returns(_amendBillableReturnsData()) - }) - describe('because the user did not select anything', () => { - beforeEach(async () => { - payload = { - authorisedVolume: 11 - } - }) - - it('returns the page data for the view', async () => { - const result = await SubmitAmendedBillableReturnsService.go( - billRunId, - licenceId, - reviewChargeElement.id, - payload, - yarStub - ) - - expect(result).to.equal({ - activeNavBar: 'search', - pageTitle: 'Set the billable returns quantity for this bill run', - chargeElement: { - description: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - authorisedQuantity: 200, - reviewChargeElementId: 'b4d70c89-de1b-4f68-a47f-832b338ac044' - }, - billRun: { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023' - }, - chargeVersion: { - chargePeriod: '1 April 2022 to 5 June 2022' - }, - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - customQuantitySelected: false, - customQuantityValue: undefined - }, { skip: ['error'] }) - }) - - it('returns page data with an error for the radio form element', async () => { - const result = await SubmitAmendedBillableReturnsService.go( - billRunId, - licenceId, - reviewChargeElement.id, - payload, - yarStub - ) - - expect(result.error).to.equal({ - message: 'Select the billable quantity', - radioFormElement: { text: 'Select the billable quantity' }, - customQuantityInputFormElement: null - }) - }) - }) - - describe('because the user entered an invalid value', () => { - beforeEach(async () => { - payload = { - 'quantity-options': 'customQuantity', - customQuantity: 'Hello world', - authorisedVolume: 11 - } - }) - - it('returns the page data for the view', async () => { - const result = await SubmitAmendedBillableReturnsService.go( - billRunId, - licenceId, - reviewChargeElement.id, - payload, - yarStub - ) - - expect(result).to.equal({ - activeNavBar: 'search', - pageTitle: 'Set the billable returns quantity for this bill run', - chargeElement: { - description: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - authorisedQuantity: 200, - reviewChargeElementId: 'b4d70c89-de1b-4f68-a47f-832b338ac044' - }, - billRun: { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023' - }, - chargeVersion: { - chargePeriod: '1 April 2022 to 5 June 2022' - }, - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1', - customQuantitySelected: true, - customQuantityValue: 'Hello world' - }, { skip: ['error'] }) - }) - - it('returns page data with an error for the custom quantity input form element', async () => { - const result = await SubmitAmendedBillableReturnsService.go( - billRunId, - licenceId, - reviewChargeElement.id, - payload, - yarStub - ) - - expect(result.error).to.equal({ - message: 'The quantity must be a number', - radioFormElement: null, - customQuantityInputFormElement: { text: 'The quantity must be a number' } - }) - }) - }) - }) - }) -}) - -function _amendBillableReturnsData () { - return { - chargeElement: { - description: 'Trickle Irrigation - Direct', - dates: ['1 April 2022 to 5 June 2022'], - authorisedQuantity: 200, - reviewChargeElementId: 'b4d70c89-de1b-4f68-a47f-832b338ac044' - }, - billRun: { - id: '6620135b-0ecf-4fd4-924e-371f950c0526', - financialYear: '2022 to 2023' - }, - chargeVersion: { - chargePeriod: '1 April 2022 to 5 June 2022' - }, - licenceId: '5aa8e752-1a5c-4b01-9112-d92a543b70d1' - } -} - -async function _fetchReviewChargeElement (id) { - return ReviewChargeElementModel.query() - .findById(id) -} From 7e5cbb8e57c1ef4265796a3767e40860fc791289 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 01:04:53 +0000 Subject: [PATCH 135/147] Move, rename & refactor submit factors test --- .../review/submit-factors.service.test.js | 106 +++++++ ...-amended-adjustment-factor.service.test.js | 269 ------------------ 2 files changed, 106 insertions(+), 269 deletions(-) create mode 100644 test/services/bill-runs/review/submit-factors.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.test.js diff --git a/test/services/bill-runs/review/submit-factors.service.test.js b/test/services/bill-runs/review/submit-factors.service.test.js new file mode 100644 index 0000000000..f70e88ca21 --- /dev/null +++ b/test/services/bill-runs/review/submit-factors.service.test.js @@ -0,0 +1,106 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/review/fetch-review-charge-reference.service.js') +const ReviewChargeReferenceModel = require('../../../../app/models/review-charge-reference.model.js') + +// Thing under test +const SubmitFactorsService = require('../../../../app/services/bill-runs/review/submit-factors.service.js') + +describe('Bill Runs Review - Submit Factors Service', () => { + let payload + let patchStub + let reviewChargeReference + let yarStub + + beforeEach(() => { + reviewChargeReference = BillRunsReviewFixture.reviewChargeReference() + + Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves(reviewChargeReference) + + patchStub = Sinon.stub().resolves() + Sinon.stub(ReviewChargeReferenceModel, 'query').returns({ + findById: Sinon.stub().withArgs(reviewChargeReference.id).returnsThis(), + patch: patchStub + }) + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('with a valid payload', () => { + beforeEach(async () => { + payload = { amendedAggregate: 0.5, amendedChargeAdjustment: 0.5 } + }) + + it('saves the submitted value, adds a flash message and returns an empty object', async () => { + const result = await SubmitFactorsService.go(reviewChargeReference.id, yarStub, payload) + + // Check we save the change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ amendedAggregate: 0.5, amendedChargeAdjustment: 0.5 }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('The adjustment factors for this licence have been updated') + + // Check we return an empty object (controller knows POST was successful so redirects) + expect(result).to.equal({}) + }) + }) + + describe('with an invalid payload', () => { + beforeEach(async () => { + payload = {} + }) + + it('does not save the submitted value or add a flash message, and returns the page data including an error', async () => { + const result = await SubmitFactorsService.go(reviewChargeReference.id, yarStub, payload) + + // Check we didn't save + expect(patchStub.called).to.be.false() + + // Check we didn't add the flash message + expect(yarStub.flash.called).to.be.false() + + // Check we return page data including error (controller knows POST failed so re-renders) + expect(result).to.equal({ + amendedAggregate: 0.333333333, + amendedChargeAdjustment: 1, + error: { + errorList: [ + { href: '#amended-aggregate', text: 'Enter an aggregate factor' }, + { href: '#amended-charge-adjustment', text: 'Enter a charge factor' } + ], + amendedAggregate: { message: 'Enter an aggregate factor' }, + amendedChargeAdjustment: { message: 'Enter a charge factor' } + }, + pageTitle: 'Set the adjustment factors', + chargeDescription: 'High loss, non-tidal, restricted water, up to and including 15 ML/yr, Tier 1 model', + chargePeriod: '1 April 2023 to 31 March 2024', + financialPeriod: '2023 to 2024', + otherAdjustments: ['Two part tariff agreement'], + reviewChargeReferenceId: '6b3d11f2-d361-4eaa-bce2-5561283bd023' + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.test.js b/test/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.test.js deleted file mode 100644 index 346fdd1dd0..0000000000 --- a/test/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.test.js +++ /dev/null @@ -1,269 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const AmendAdjustmentFactorPresenter = require('../../../../app/presenters/bill-runs/two-part-tariff/amend-adjustment-factor.presenter.js') -const FetchReviewChargeReferenceService = require('../../../../app/services/bill-runs/two-part-tariff/fetch-review-charge-reference.service.js') -const ReviewChargeReferenceHelper = require('../../../support/helpers/review-charge-reference.helper.js') -const ReviewChargeReferenceModel = require('../../../../app/models/review-charge-reference.model.js') - -// Thing under test -const SubmitAmendedAdjustmentFactorService = require('../../../../app/services/bill-runs/two-part-tariff/submit-amended-adjustment-factor.service.js') - -describe('Submit Amended Adjustment Factor Service', () => { - const billRunId = 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e' - const licenceId = '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2' - - let payload - let reviewChargeReference - let yarStub - - beforeEach(async () => { - yarStub = { flash: Sinon.stub() } - - reviewChargeReference = await ReviewChargeReferenceHelper.add() - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when called', () => { - describe('with a valid payload for aggregate factor', () => { - beforeEach(async () => { - // Note: Both values should always be present because the input box auto populates the original value before a - // user can change it. If either aren't then this leads to a validation error - payload = { - amendedAggregateFactor: 0.5, - amendedChargeAdjustment: 1 - } - }) - - it('saves the users entered value', async () => { - await SubmitAmendedAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const reviewChargeReferenceData = await _fetchReviewChargeReference(reviewChargeReference.id) - - expect(reviewChargeReferenceData.amendedAggregate).to.equal(0.5) - }) - - it('sets the banner message to "The adjustment factors for this licence have been updated"', async () => { - await SubmitAmendedAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The adjustment factors for this licence have been updated') - }) - }) - - describe('with a valid payload for charge adjustment', () => { - beforeEach(async () => { - payload = { - amendedAggregateFactor: 1, - amendedChargeAdjustment: 0.7 - } - }) - - it('saves the users entered value', async () => { - await SubmitAmendedAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const reviewChargeReferenceData = await _fetchReviewChargeReference(reviewChargeReference.id) - - expect(reviewChargeReferenceData.amendedChargeAdjustment).to.equal(0.7) - }) - - it('sets the banner message to "The adjustment factors for this licence have been updated"', async () => { - await SubmitAmendedAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The adjustment factors for this licence have been updated') - }) - }) - - describe('with a valid payload for both aggregate factor and charge adjustment', () => { - beforeEach(async () => { - payload = { - amendedAggregateFactor: 0.2, - amendedChargeAdjustment: 0.3 - } - }) - - it('saves the users entered value', async () => { - await SubmitAmendedAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const reviewChargeReferenceData = await _fetchReviewChargeReference(reviewChargeReference.id) - - expect(reviewChargeReferenceData.amendedAggregate).to.equal(0.2) - expect(reviewChargeReferenceData.amendedChargeAdjustment).to.equal(0.3) - }) - - it('sets the banner message to "The adjustment factors for this licence have been updated"', async () => { - await SubmitAmendedAdjustmentFactorService.go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The adjustment factors for this licence have been updated') - }) - }) - - describe('when an invalid payload', () => { - beforeEach(() => { - Sinon.stub(FetchReviewChargeReferenceService, 'go').resolves({ billRun: 'bill run', reviewChargeReference: 'charge reference' }) - Sinon.stub(AmendAdjustmentFactorPresenter, 'go').returns(_amendAdjustmentFactorData()) - }) - - describe('because the user left the aggregate factor input blank', () => { - beforeEach(() => { - payload = { - amendedChargeAdjustment: 0.3 - } - }) - - it('returns the page data for the view', async () => { - const result = await SubmitAmendedAdjustmentFactorService - .go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - expect(result).to.equal({ - activeNavBar: 'search', - pageTitle: 'Set the adjustment factors', - inputtedAggregateValue: undefined, - inputtedChargeValue: 0.3, - billRunId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - licenceId: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - financialYear: '2022 to 2023', - chargePeriod: '1 September 2022 to 31 March 2023', - chargeReference: { - id: 'e93fa3c6-195f-48eb-a03f-f87db7218f2d', - description: 'High loss, non-tidal, greater than 50 up to and including 85 ML/yr', - aggregateFactor: 0.5, - chargeAdjustment: 0.5, - otherAdjustments: '' - } - }, { skip: ['error'] }) - }) - - it('returns the page data with an error for the aggregate factor input element', async () => { - const result = await SubmitAmendedAdjustmentFactorService - .go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - expect(result.error).to.equal({ - aggregateFactorElement: { text: 'Enter a aggregate factor' }, - chargeAdjustmentElement: null - }) - }) - }) - - describe('because the user left the charge factor input blank', () => { - beforeEach(() => { - payload = { - amendedAggregateFactor: 0.2 - } - }) - - it('returns the page data for the view', async () => { - const result = await SubmitAmendedAdjustmentFactorService - .go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - expect(result).to.equal({ - activeNavBar: 'search', - pageTitle: 'Set the adjustment factors', - inputtedAggregateValue: 0.2, - inputtedChargeValue: undefined, - billRunId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - licenceId: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - financialYear: '2022 to 2023', - chargePeriod: '1 September 2022 to 31 March 2023', - chargeReference: { - id: 'e93fa3c6-195f-48eb-a03f-f87db7218f2d', - description: 'High loss, non-tidal, greater than 50 up to and including 85 ML/yr', - aggregateFactor: 0.5, - chargeAdjustment: 0.5, - otherAdjustments: '' - } - }, { skip: ['error'] }) - }) - - it('returns the page data with an error for the charge factor input element', async () => { - const result = await SubmitAmendedAdjustmentFactorService - .go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - expect(result.error).to.equal({ - aggregateFactorElement: null, - chargeAdjustmentElement: { text: 'Enter a charge factor' } - }) - }) - }) - - describe('because the user left both the aggregate and charge factor input blank', () => { - beforeEach(() => { - payload = {} - }) - - it('returns the page data for the view', async () => { - const result = await SubmitAmendedAdjustmentFactorService - .go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - expect(result).to.equal({ - activeNavBar: 'search', - pageTitle: 'Set the adjustment factors', - inputtedAggregateValue: undefined, - inputtedChargeValue: undefined, - billRunId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - licenceId: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - financialYear: '2022 to 2023', - chargePeriod: '1 September 2022 to 31 March 2023', - chargeReference: { - id: 'e93fa3c6-195f-48eb-a03f-f87db7218f2d', - description: 'High loss, non-tidal, greater than 50 up to and including 85 ML/yr', - aggregateFactor: 0.5, - chargeAdjustment: 0.5, - otherAdjustments: '' - } - }, { skip: ['error'] }) - }) - - it('returns the page data with an error for the aggregate and charge factor input element', async () => { - const result = await SubmitAmendedAdjustmentFactorService - .go(billRunId, licenceId, reviewChargeReference.id, payload, yarStub) - - expect(result.error).to.equal({ - aggregateFactorElement: { text: 'Enter a aggregate factor' }, - chargeAdjustmentElement: { text: 'Enter a charge factor' } - }) - }) - }) - }) - }) -}) - -function _amendAdjustmentFactorData () { - return { - billRunId: 'cc4bbb18-0d6a-4254-ac2c-7409de814d7e', - licenceId: '9a8a148d-b71e-463c-bea8-bc5e0a5d95e2', - financialYear: '2022 to 2023', - chargePeriod: '1 September 2022 to 31 March 2023', - chargeReference: { - id: 'e93fa3c6-195f-48eb-a03f-f87db7218f2d', - description: 'High loss, non-tidal, greater than 50 up to and including 85 ML/yr', - aggregateFactor: 0.5, - chargeAdjustment: 0.5, - otherAdjustments: '' - } - } -} - -async function _fetchReviewChargeReference (id) { - return ReviewChargeReferenceModel.query() - .findById(id) -} From ab3d28010b41f6499f17a6544ad4e0ed18770b7c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 01:05:35 +0000 Subject: [PATCH 136/147] Move, rename & refactor submit remove test --- .../review/submit-remove.service.test.js | 105 ++++++++++++++++++ ...it-remove-bill-run-licence.service.test.js | 95 ---------------- 2 files changed, 105 insertions(+), 95 deletions(-) create mode 100644 test/services/bill-runs/review/submit-remove.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.test.js diff --git a/test/services/bill-runs/review/submit-remove.service.test.js b/test/services/bill-runs/review/submit-remove.service.test.js new file mode 100644 index 0000000000..f1f0b0168d --- /dev/null +++ b/test/services/bill-runs/review/submit-remove.service.test.js @@ -0,0 +1,105 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') + +// Things we need to stub +const CreateLicenceSupplementaryYearService = require('../../../../app/services/licences/supplementary/create-licence-supplementary-year.service.js') +const FetchRemoveReviewLicenceService = require('../../../../app/services/bill-runs/review/fetch-remove-review-licence.service.js') +const ProcessBillRunPostRemove = require('../../../../app/services/bill-runs/review/process-bill-run-post-remove.service.js') +const RemoveReviewLicenceService = require('../../../../app/services/bill-runs/review/remove-review-licence.service.js') + +// Thing under test +const SubmitRemoveService = require('../../../../app/services/bill-runs/review/submit-remove.service.js') + +describe('Bill Runs Review - Submit Remove service', () => { + let createLicenceSupplementaryYearStub + let removeReviewLicence + let removeReviewLicenceStub + let yarStub + + beforeEach(() => { + removeReviewLicence = BillRunsReviewFixture.removeReviewLicence() + + Sinon.stub(FetchRemoveReviewLicenceService, 'go').resolves(removeReviewLicence) + + removeReviewLicenceStub = Sinon + .stub(RemoveReviewLicenceService, 'go') + .withArgs(removeReviewLicence.id) + .resolves() + + createLicenceSupplementaryYearStub = Sinon + .stub(CreateLicenceSupplementaryYearService, 'go') + .withArgs(removeReviewLicence.licenceId, [removeReviewLicence.billRun.toFinancialYearEnding], true) + .resolves() + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('and this is the last licence in the bill run', () => { + beforeEach(() => { + Sinon.stub(ProcessBillRunPostRemove, 'go').withArgs(removeReviewLicence.billRun.id).resolves(true) + }) + + it('removes the review licence, flags the licence for supplementary billing, does not add a flash message, and returns `empty: true`', async () => { + const result = await SubmitRemoveService.go(removeReviewLicence.id, yarStub) + + // Confirm we called the remove review licence service with the correct ID + expect(removeReviewLicenceStub.called).to.be.true() + + // Confirm we flagged the licence for the next two-part tariff supplementary bill run + expect(createLicenceSupplementaryYearStub.called).to.be.true() + + // Check we didn't add the flash message + expect(yarStub.flash.called).to.be.false() + + // Check we return empty true in our result so the controller knows to redirect to the bill runs page + expect(result).to.equal({ + billRunId: '287aeb25-cf11-429d-8c6f-f98f06db021d', + empty: true + }) + }) + }) + + describe('and this is not the last licence in the bill run', () => { + beforeEach(() => { + Sinon.stub(ProcessBillRunPostRemove, 'go').withArgs(removeReviewLicence.billRun.id).resolves(false) + }) + + it('removes the review licence, flags the licence for supplementary billing, adds a flash message, and returns `empty: false`', async () => { + const result = await SubmitRemoveService.go(removeReviewLicence.id, yarStub) + + // Confirm we called the remove review licence service with the correct ID + expect(removeReviewLicenceStub.called).to.be.true() + + // Confirm we flagged the licence for the next two-part tariff supplementary bill run + expect(createLicenceSupplementaryYearStub.called).to.be.true() + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('Licence 1/11/11/*11/1111 removed from the bill run.') + + // Check we return empty true in our result so the controller knows to redirect to the bill runs page + expect(result).to.equal({ + billRunId: '287aeb25-cf11-429d-8c6f-f98f06db021d', + empty: false + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.test.js b/test/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.test.js deleted file mode 100644 index 9e22bd9553..0000000000 --- a/test/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.test.js +++ /dev/null @@ -1,95 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const BillRunHelper = require('../../../support/helpers/bill-run.helper.js') -const BillRunModel = require('../../../../app/models/bill-run.model.js') -const LicenceHelper = require('../../../support/helpers/licence.helper.js') -const LicenceSupplementaryYearModel = require('../../../../app/models/licence-supplementary-year.model.js') -const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') - -// Things we need to stub -const RemoveReviewDataService = require('../../../../app/services/bill-runs/two-part-tariff/remove-review-data.service.js') - -// Thing under test -const SubmitRemoveBillRunLicenceService = require('../../../../app/services/bill-runs/two-part-tariff/submit-remove-bill-run-licence.service.js') - -describe('Submit Remove Bill Run Licence service', () => { - let yarStub - - beforeEach(async () => { - Sinon.stub(RemoveReviewDataService, 'go').resolves() - yarStub = { flash: Sinon.stub() } - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when called with a valid billRunId & licenceId', () => { - let billRun - let licence - - beforeEach(async () => { - billRun = await BillRunHelper.add({ status: 'review' }) - - licence = await LicenceHelper.add() - }) - - describe('which has at least one licence remaining in the bill run after the licence is removed', () => { - beforeEach(async () => { - // add an extra record to the `reviewLicence` table so that it isn't empty when the licence is removed - await ReviewLicenceHelper.add({ billRunId: billRun.id }) - }) - - it('will return false as all licences are not removed and generate a banner message', async () => { - const result = await SubmitRemoveBillRunLicenceService.go(billRun.id, licence.id, yarStub) - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(result).to.be.false() - - expect(yarStub.flash.called).to.be.true() - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal(`Licence ${licence.licenceRef} removed from the bill run.`) - }) - }) - - describe('which has NO licences remain in the bill run after the licence is removed', () => { - it('will return true as no licences remain in the bill run and NO banner message is generated', async () => { - const result = await SubmitRemoveBillRunLicenceService.go(billRun.id, licence.id, yarStub) - - expect(result).to.be.true() - expect(yarStub.flash.called).to.be.false() - }) - - it('will set the bill run status to empty', async () => { - await SubmitRemoveBillRunLicenceService.go(billRun.id, licence.id, yarStub) - const { status } = await BillRunModel.query().findById(billRun.id).select('status') - - expect(status).to.equal('empty') - }) - - it('will mark the licence for two-part tariff supplementary billing', async () => { - await SubmitRemoveBillRunLicenceService.go(billRun.id, licence.id, yarStub) - const includeInSrocTptBilling = await LicenceSupplementaryYearModel.query() - .select([ - 'licenceId', - 'twoPartTariff', - 'financialYearEnd' - ]) - .where('licenceId', licence.id) - - expect(includeInSrocTptBilling[0].licenceId).to.equal(licence.id) - expect(includeInSrocTptBilling[0].twoPartTariff).to.be.true() - expect(includeInSrocTptBilling[0].financialYearEnd).to.equal(billRun.toFinancialYearEnding) - }) - }) - }) -}) From df06fcc7d74ac13d240970f5ed227a0a7f952323 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 01:05:48 +0000 Subject: [PATCH 137/147] Update describe on submit review bill run test --- .../bill-runs/review/submit-review-bill-run.service.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/services/bill-runs/review/submit-review-bill-run.service.test.js b/test/services/bill-runs/review/submit-review-bill-run.service.test.js index cba8b58a65..985abf4380 100644 --- a/test/services/bill-runs/review/submit-review-bill-run.service.test.js +++ b/test/services/bill-runs/review/submit-review-bill-run.service.test.js @@ -11,7 +11,7 @@ const { expect } = Code // Thing under test const SubmitReviewBillRunService = require('../../../../app/services/bill-runs/review/submit-review-bill-run.service.js') -describe('Submit Review Bill Run Service', () => { +describe('Bill Runs Review - Submit Review Bill Run Service', () => { const billRunId = '27dad88a-6b3c-438b-a25f-f1483e7e12a0' let yarStub From 7c035e9ecb20eee8073a45754533dde440222c3f Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 09:32:16 +0000 Subject: [PATCH 138/147] Add tests for new ProcessBillRunPostRemove service --- ...ocess-bill-run-post-remove.service.test.js | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 test/services/bill-runs/review/process-bill-run-post-remove.service.test.js diff --git a/test/services/bill-runs/review/process-bill-run-post-remove.service.test.js b/test/services/bill-runs/review/process-bill-run-post-remove.service.test.js new file mode 100644 index 0000000000..7bb65334c1 --- /dev/null +++ b/test/services/bill-runs/review/process-bill-run-post-remove.service.test.js @@ -0,0 +1,76 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Things we need to stub +const BillRunModel = require('../../../../app/models/bill-run.model.js') +const ReviewLicenceModel = require('../../../../app/models/review-licence.model.js') + +// Thing under test +const ProcessBillRunPostRemoveService = require('../../../../app/services/bill-runs/review/process-bill-run-post-remove.service.js') + +describe('Bill Runs Review - Process Bill Run Post Remove service', () => { + const billRunId = 'd4b76592-8f98-4064-892c-399ff83928f7' + + let billRunPatchStub + + beforeEach(() => { + billRunPatchStub = Sinon.stub().resolves() + Sinon.stub(BillRunModel, 'query').returns({ + findById: Sinon.stub().withArgs(billRunId).returnsThis(), + patch: billRunPatchStub + }) + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('and the bill run contains no licences (it is now empty)', () => { + beforeEach(() => { + Sinon.stub(ReviewLicenceModel, 'query').returns({ + select: Sinon.stub().withArgs('id').returnsThis(), + where: Sinon.stub().withArgs('billRunId', billRunId).returnsThis(), + resultSize: Sinon.stub().resolves(0) + }) + }) + + it('sets the status of the bill run to empty and returns "true"', async () => { + const result = await ProcessBillRunPostRemoveService.go(billRunId) + + expect(result).to.be.true() + + // Check we set the bill run status + const [patchObject] = billRunPatchStub.args[0] + + expect(patchObject).to.equal({ status: 'empty' }) + }) + }) + + describe('and the bill run still contains licences', () => { + beforeEach(() => { + Sinon.stub(ReviewLicenceModel, 'query').returns({ + select: Sinon.stub().withArgs('id').returnsThis(), + where: Sinon.stub().withArgs('billRunId', billRunId).returnsThis(), + resultSize: Sinon.stub().resolves(1) + }) + }) + + it('does not change the bill run status status and returns "false"', async () => { + const result = await ProcessBillRunPostRemoveService.go(billRunId) + + expect(result).to.be.false() + + // Check we not change the bill run status + expect(billRunPatchStub.called).to.be.false() + }) + }) + }) +}) From 928a07135e007f61c46ed9c96b665539f98aff7a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 09:52:28 +0000 Subject: [PATCH 139/147] Move, rename & refactor submit review licence test --- .../submit-review-licence.service.test.js | 111 ++++++++++++++ .../submit-review-licence.service.test.js | 136 ------------------ 2 files changed, 111 insertions(+), 136 deletions(-) create mode 100644 test/services/bill-runs/review/submit-review-licence.service.test.js delete mode 100644 test/services/bill-runs/two-part-tariff/submit-review-licence.service.test.js diff --git a/test/services/bill-runs/review/submit-review-licence.service.test.js b/test/services/bill-runs/review/submit-review-licence.service.test.js new file mode 100644 index 0000000000..a3be9a2384 --- /dev/null +++ b/test/services/bill-runs/review/submit-review-licence.service.test.js @@ -0,0 +1,111 @@ +'use strict' + +// Test framework dependencies +const Lab = require('@hapi/lab') +const Code = require('@hapi/code') +const Sinon = require('sinon') + +const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() +const { expect } = Code + +// Test helpers +const BillRunsReviewFixture = require('../../../fixtures/bill-runs-review.fixture.js') +const ReviewLicenceModel = require('../../../../app/models/review-licence.model.js') + +// Things we need to stub +const FetchReviewLicenceService = require('../../../../app/services/bill-runs/review/fetch-review-licence.service.js') + +// Thing under test +const SubmitReviewLicenceService = require('../../../../app/services/bill-runs/review/submit-review-licence.service.js') + +describe('Bill Runs Review - Submit Review Licence Service', () => { + let payload + let patchStub + let reviewLicence + let yarStub + + beforeEach(async () => { + reviewLicence = BillRunsReviewFixture.reviewLicence() + + Sinon.stub(FetchReviewLicenceService, 'go').resolves(reviewLicence) + + patchStub = Sinon.stub().resolves() + Sinon.stub(ReviewLicenceModel, 'query').returns({ + findById: Sinon.stub().withArgs(reviewLicence.id).returnsThis(), + patch: patchStub + }) + + yarStub = { flash: Sinon.stub() } + }) + + afterEach(() => { + Sinon.restore() + }) + + describe('when called', () => { + describe('and the user is updating the status', () => { + beforeEach(() => { + payload = { 'licence-status': 'ready' } + }) + + it('sets a flash message and updates the status of the review licence', async () => { + await SubmitReviewLicenceService.go(reviewLicence.id, yarStub, payload) + + // Check we save the status change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ status: 'ready' }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('Licence changed to ready.') + }) + }) + + describe('and the user is updating the progress', () => { + describe('to mark it as "in progress"', () => { + beforeEach(() => { + payload = { 'mark-progress': 'mark' } + }) + + it('sets a flash message and updates the progress of the review licence', async () => { + await SubmitReviewLicenceService.go(reviewLicence.id, yarStub, payload) + + // Check we save the status change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ progress: true }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('This licence has been marked.') + }) + }) + + describe('to unmark it', () => { + beforeEach(() => { + payload = { 'mark-progress': 'unmark' } + }) + + it('sets a flash message and updates the progress of the review licence', async () => { + await SubmitReviewLicenceService.go(reviewLicence.id, yarStub, payload) + + // Check we save the status change + const [patchObject] = patchStub.args[0] + + expect(patchObject).to.equal({ progress: false }) + + // Check we add the flash message + const [flashType, bannerMessage] = yarStub.flash.args[0] + + expect(flashType).to.equal('banner') + expect(bannerMessage).to.equal('The progress mark for this licence has been removed.') + }) + }) + }) + }) +}) diff --git a/test/services/bill-runs/two-part-tariff/submit-review-licence.service.test.js b/test/services/bill-runs/two-part-tariff/submit-review-licence.service.test.js deleted file mode 100644 index e481dde7c3..0000000000 --- a/test/services/bill-runs/two-part-tariff/submit-review-licence.service.test.js +++ /dev/null @@ -1,136 +0,0 @@ -'use strict' - -// Test framework dependencies -const Lab = require('@hapi/lab') -const Code = require('@hapi/code') -const Sinon = require('sinon') - -const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() -const { expect } = Code - -// Test helpers -const ReviewLicenceHelper = require('../../../support/helpers/review-licence.helper.js') - -// Thing under test -const SubmitReviewLicenceService = require('../../../../app/services/bill-runs/two-part-tariff/submit-review-licence.service.js') - -describe('Submit Review Licence Service', () => { - const billRunId = '1760c5f9-b868-4d77-adb0-961dfc5f5c5d' - const licenceId = '7a0388cf-d5e8-4bec-ac5a-bc495d0106b2' - - let payload - let reviewLicence - let yarStub - - beforeEach(async () => { - yarStub = { flash: Sinon.stub() } - }) - - afterEach(() => { - Sinon.restore() - }) - - describe('when called by the status button', () => { - describe('to set the review licence status to "review"', () => { - beforeEach(async () => { - payload = { 'licence-status': 'review' } - - reviewLicence = await ReviewLicenceHelper.add({ billRunId, licenceId, status: 'ready' }) - }) - - it('updates the review licence record status to "review"', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const refreshedRecord = await reviewLicence.$query() - - expect(refreshedRecord.status).to.equal('review') - }) - - it('sets the banner message to "Licence changed to review."', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('Licence changed to review.') - }) - }) - - describe('to set the review licence status to "ready"', () => { - beforeEach(async () => { - payload = { 'licence-status': 'ready' } - - reviewLicence = await ReviewLicenceHelper.add({ billRunId, licenceId, status: 'review' }) - }) - - it('updates the review licence record status to "ready"', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const refreshedRecord = await reviewLicence.$query() - - expect(refreshedRecord.status).to.equal('ready') - }) - - it('sets the banner message to "Licence changed to ready."', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('Licence changed to ready.') - }) - }) - }) - - describe('when called by the progress button', () => { - describe('to mark the licence as in progress', () => { - beforeEach(async () => { - payload = { 'mark-progress': 'mark' } - - reviewLicence = await ReviewLicenceHelper.add({ billRunId, licenceId, progress: false }) - }) - - it('updates the review licence record progress to true', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const refreshedRecord = await reviewLicence.$query() - - expect(refreshedRecord.progress).to.be.true() - }) - - it('sets the banner message to "This licence has been marked."', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('This licence has been marked.') - }) - }) - - describe('to remove the progress mark from the licence', () => { - beforeEach(async () => { - payload = { 'mark-progress': 'unmark' } - - reviewLicence = await ReviewLicenceHelper.add({ billRunId, licenceId, progress: true }) - }) - - it('updates the review licence record progress to false', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const refreshedRecord = await reviewLicence.$query() - - expect(refreshedRecord.progress).to.be.false() - }) - - it('sets the banner message to "The progress mark for this licence has been removed."', async () => { - await SubmitReviewLicenceService.go(billRunId, licenceId, payload, yarStub) - - const [flashType, bannerMessage] = yarStub.flash.args[0] - - expect(flashType).to.equal('banner') - expect(bannerMessage).to.equal('The progress mark for this licence has been removed.') - }) - }) - }) -}) From 95c890823e086aa7a961ba1c5f8b89135c3ec144 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 09:55:49 +0000 Subject: [PATCH 140/147] Housekeeping - fix missing service from filename --- ...g-requirements.js => fetch-existing-requirements.service.js} | 0 .../setup/generate-from-existing-requirements.service.js | 2 +- ...ents.test.js => fetch-existing-requirements.service.test.js} | 2 +- .../setup/generate-from-existing-requirements.service.test.js | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename app/services/return-versions/setup/{fetch-existing-requirements.js => fetch-existing-requirements.service.js} (100%) rename test/services/return-versions/setup/{fetch-existing-requirements.test.js => fetch-existing-requirements.service.test.js} (98%) diff --git a/app/services/return-versions/setup/fetch-existing-requirements.js b/app/services/return-versions/setup/fetch-existing-requirements.service.js similarity index 100% rename from app/services/return-versions/setup/fetch-existing-requirements.js rename to app/services/return-versions/setup/fetch-existing-requirements.service.js diff --git a/app/services/return-versions/setup/generate-from-existing-requirements.service.js b/app/services/return-versions/setup/generate-from-existing-requirements.service.js index 63090764f6..ea74b46f3e 100644 --- a/app/services/return-versions/setup/generate-from-existing-requirements.service.js +++ b/app/services/return-versions/setup/generate-from-existing-requirements.service.js @@ -5,7 +5,7 @@ * @module GenerateFromExistingRequirementsService */ -const FetchExistingRequirementsService = require('./fetch-existing-requirements.js') +const FetchExistingRequirementsService = require('./fetch-existing-requirements.service.js') /** * Generates returns setup requirements from an existing return version diff --git a/test/services/return-versions/setup/fetch-existing-requirements.test.js b/test/services/return-versions/setup/fetch-existing-requirements.service.test.js similarity index 98% rename from test/services/return-versions/setup/fetch-existing-requirements.test.js rename to test/services/return-versions/setup/fetch-existing-requirements.service.test.js index b6730530d4..64d47938bc 100644 --- a/test/services/return-versions/setup/fetch-existing-requirements.test.js +++ b/test/services/return-versions/setup/fetch-existing-requirements.service.test.js @@ -11,7 +11,7 @@ const { expect } = Code const RequirementsForReturnsSeeder = require('../../../support/seeders/requirements-for-returns.seeder.js') // Thing under test -const FetchExistingRequirementsService = require('../../../../app/services/return-versions/setup/fetch-existing-requirements.js') +const FetchExistingRequirementsService = require('../../../../app/services/return-versions/setup/fetch-existing-requirements.service.js') describe('Return Versions Setup - Fetch Existing Requirements service', () => { let returnVersion diff --git a/test/services/return-versions/setup/generate-from-existing-requirements.service.test.js b/test/services/return-versions/setup/generate-from-existing-requirements.service.test.js index ee817af11f..a967db449c 100644 --- a/test/services/return-versions/setup/generate-from-existing-requirements.service.test.js +++ b/test/services/return-versions/setup/generate-from-existing-requirements.service.test.js @@ -9,7 +9,7 @@ const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script() const { expect } = Code // Things we need to stub -const FetchExistingRequirementsService = require('../../../../app/services/return-versions/setup/fetch-existing-requirements.js') +const FetchExistingRequirementsService = require('../../../../app/services/return-versions/setup/fetch-existing-requirements.service.js') // Thing under test const GenerateFromExistingRequirementsService = require('../../../../app/services/return-versions/setup/generate-from-existing-requirements.service.js') From 03896ff1eaa81dc3ef9dc4afde268a43fabc2204 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 10:10:01 +0000 Subject: [PATCH 141/147] Housekeeping - second pass of the JSDocs --- app/presenters/bill-runs/review/base-review.presenter.js | 2 +- app/presenters/bill-runs/review/remove.presenter.js | 2 +- .../review/fetch-review-charge-element.service.js | 9 ++++++--- .../bill-runs/review/submit-review-bill-run.service.js | 2 ++ app/validators/bill-runs/review/edit.validator.js | 1 + app/validators/bill-runs/review/factors.validator.js | 3 +++ 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index 38426a611e..cf5048ec89 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -102,7 +102,7 @@ function formatChargePeriod (reviewChargeVersion) { * * @param {module:ReviewChargeElementModel} reviewChargeElement - instance of `ReviewChargeElementModel` containing at * least a `chargeElement` property populated with abstraction days and months - * @param {*} [chargePeriod] + * @param {object} [chargePeriod] - The start and end date of the calculated charge period * * @returns {string[]} an array containing the review charge element's charge period(s) formatted as 'DD MMMM YYYY to DD * MMMM YYYY' diff --git a/app/presenters/bill-runs/review/remove.presenter.js b/app/presenters/bill-runs/review/remove.presenter.js index d26197af1e..c44e9800bb 100644 --- a/app/presenters/bill-runs/review/remove.presenter.js +++ b/app/presenters/bill-runs/review/remove.presenter.js @@ -13,7 +13,7 @@ const { formatFinancialYear, formatLongDate } = require('../../base.presenter.js * @param {module:ReviewLicenceModel} reviewLicence - instance of the `ReviewLicenceModel` returned from * `FetchRemoveReviewLicenceService` * - * @returns {object}page date needed for the remove review licence confirmation page + * @returns {object} page date needed for the remove review licence confirmation page */ function go (reviewLicence) { const { billRun, id: reviewLicenceId, licenceRef } = reviewLicence diff --git a/app/services/bill-runs/review/fetch-review-charge-element.service.js b/app/services/bill-runs/review/fetch-review-charge-element.service.js index c9ba3ed900..a5912e1fcb 100644 --- a/app/services/bill-runs/review/fetch-review-charge-element.service.js +++ b/app/services/bill-runs/review/fetch-review-charge-element.service.js @@ -1,7 +1,7 @@ 'use strict' /** - * Fetches the selected review charge element instance and related data for the 2PT review charge element page + * Fetches the selected review charge element instance and related data for the 2PT review charge element pages * @module FetchReviewChargeReferenceService */ @@ -10,11 +10,14 @@ const { ref } = require('objection') const ReviewChargeElementModel = require('../../../models/review-charge-element.model.js') /** - * Fetches the match details for an individual charge element + * Fetches the selected review charge element instance and related data for the 2PT review charge element pages + * + * This fetch service fetches the data needed for the main review charge element page, but also the edit page/service. * * @param {string} reviewChargeElementId - The UUID of the review charge element being viewed * - * @returns {Promise} An object containing the bill run and review charge element instances + * @returns {Promise} the matching `ReviewChargeElementModel` instance and related data needed for the + * two-part tariff review charge element page */ async function go (reviewChargeElementId) { return _fetch(reviewChargeElementId) diff --git a/app/services/bill-runs/review/submit-review-bill-run.service.js b/app/services/bill-runs/review/submit-review-bill-run.service.js index f5ac10a68f..15a183870a 100644 --- a/app/services/bill-runs/review/submit-review-bill-run.service.js +++ b/app/services/bill-runs/review/submit-review-bill-run.service.js @@ -11,6 +11,8 @@ * @param {string} billRunId - The UUID of the bill run * @param {object} payload - The `request.payload` containing the filter data. * @param {object} yar - The Hapi `request.yar` session manager passed on by the controller + * + * @returns {Promise} the promise returned is not intended to resolve to any particular value */ async function go (billRunId, payload, yar) { const clearFilters = payload?.clearFilters diff --git a/app/validators/bill-runs/review/edit.validator.js b/app/validators/bill-runs/review/edit.validator.js index 4ba3717e21..f68d61d4ff 100644 --- a/app/validators/bill-runs/review/edit.validator.js +++ b/app/validators/bill-runs/review/edit.validator.js @@ -14,6 +14,7 @@ const Joi = require('joi') * there own custom volume. The validation happening here is to ensure that a user selects either option and if its the * custom one, that they enter a number above 0 but below the authorised volume and that the number is less than 6 * decimal places. + * * @param {object} payload - The payload from the request to be validated * * @returns {object} the result from calling Joi's schema.validate(). It will be an object with a `value:` property. If diff --git a/app/validators/bill-runs/review/factors.validator.js b/app/validators/bill-runs/review/factors.validator.js index 40429e3bac..17203f48d9 100644 --- a/app/validators/bill-runs/review/factors.validator.js +++ b/app/validators/bill-runs/review/factors.validator.js @@ -10,6 +10,9 @@ const Joi = require('joi') /** * Validates data submitted for the review charge reference factors page * + * There are two inputs on the page, both of which need to contain valid values. However, they are always pre-populated + * with existing data, so in theory would only both be invalid if the user has incorrectly updated both. + * * @param {object} payload - The payload from the request to be validated * * @returns {object} The result from calling Joi's schema.validate(). If any errors are found the `error:` property will From fbfe9ae744a94e8811835a17004ceb4a5921b74f Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 17:24:20 +0000 Subject: [PATCH 142/147] Add new base review formatter for adjustments --- .../bill-runs/review/base-review.presenter.js | 44 +++++++++++ .../review/base-review.presenter.test.js | 78 +++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/app/presenters/bill-runs/review/base-review.presenter.js b/app/presenters/bill-runs/review/base-review.presenter.js index cf5048ec89..b72507bc36 100644 --- a/app/presenters/bill-runs/review/base-review.presenter.js +++ b/app/presenters/bill-runs/review/base-review.presenter.js @@ -72,6 +72,49 @@ function formatAdditionalCharges (chargeReference) { return additionalCharges } +/** + * Extract and format the adjustments (excluding aggregate and charge adjustment) from a charge reference for display + * + * If the charge reference has adjustments, for example, an abatement and two-part tariff agreement then the following + * is returned. + * + * ```javascript + * const agreements = [ + * 'Abatement agreement 0.8', + * 'Two part tariff agreement' + * ] + * ``` + * + * We exclude aggregate and charge adjustment because the review screens have functionality to allow users to edit these + * values when they have been applied to a charge reference. Therefore they are handled separately. + * + * @param {module:ReviewChargeReferenceModel} reviewChargeReference - instance of `ReviewChargeReferenceModel` to format + * the adjustments for + * + * @returns {string[]} the adjustments (if present) formatted as a string for display + */ +function formatAdjustments (reviewChargeReference) { + const adjustments = [] + + if (reviewChargeReference.abatementAgreement && reviewChargeReference.abatementAgreement !== 1) { + adjustments.push(`Abatement agreement (${reviewChargeReference.abatementAgreement})`) + } + + if (reviewChargeReference.winterDiscount) { + adjustments.push('Winter discount') + } + + if (reviewChargeReference.twoPartTariffAgreement) { + adjustments.push('Two part tariff agreement') + } + + if (reviewChargeReference.canalAndRiverTrustAgreement) { + adjustments.push('Canal and River trust agreement') + } + + return adjustments +} + /** * Formats the charge period into its string variant, for example, '1 April 2023 to 10 October 2023' * @@ -212,6 +255,7 @@ module.exports = { calculateTotalBillableReturns, determineReturnLink, formatAdditionalCharges, + formatAdjustments, formatChargePeriod, formatChargePeriods, formatIssues, diff --git a/test/presenters/bill-runs/review/base-review.presenter.test.js b/test/presenters/bill-runs/review/base-review.presenter.test.js index 568c3ef572..c4d02b6180 100644 --- a/test/presenters/bill-runs/review/base-review.presenter.test.js +++ b/test/presenters/bill-runs/review/base-review.presenter.test.js @@ -124,6 +124,84 @@ describe('Bill Runs Review - Base Review presenter', () => { }) }) + describe('#formatAdjustments()', () => { + let reviewChargeReference + + describe('when the review charge reference has no adjustments', () => { + beforeEach(() => { + reviewChargeReference = {} + }) + + it('returns an empty array', () => { + const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + + expect(result).to.be.empty() + }) + }) + + describe('when the review charge reference has an abatement agreement', () => { + describe('that is set to a value other than 1', () => { + beforeEach(() => { + reviewChargeReference = { abatementAgreement: 0.3 } + }) + + it('includes it in the array returned', () => { + const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + + expect(result).to.include('Abatement agreement (0.3)') + }) + }) + + describe('that is set to 1', () => { + beforeEach(() => { + reviewChargeReference = { abatementAgreement: 1 } + }) + + it('does not add include it in the array returned', () => { + const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + + expect(result).to.not.include('Abatement agreement (1)') + }) + }) + }) + + describe('when the review charge reference has a winter discount', () => { + beforeEach(() => { + reviewChargeReference = { winterDiscount: true } + }) + + it('includes it in the array returned', () => { + const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + + expect(result).to.include('Winter discount') + }) + }) + + describe('when the review charge reference has a two part tariff agreement', () => { + beforeEach(() => { + reviewChargeReference = { twoPartTariffAgreement: true } + }) + + it('includes it in the array returned', () => { + const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + + expect(result).to.include('Two part tariff agreement') + }) + }) + + describe('when the review charge reference has a canal and river trust agreement', () => { + beforeEach(() => { + reviewChargeReference = { canalAndRiverTrustAgreement: true } + }) + + it('includes it in the array returned', () => { + const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + + expect(result).to.include('Canal and River trust agreement') + }) + }) + }) + describe('#formatChargePeriod()', () => { const reviewChargeVersion = { chargePeriodStartDate: new Date('2024-04-01'), From 88ba275778b9ca3319cf599b63da2755c0284600 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 17:35:13 +0000 Subject: [PATCH 143/147] Update Factors presenter to use new formatter --- .../bill-runs/review/factors.presenter.js | 33 +--------- .../review/factors.presenter.test.js | 60 +++++-------------- 2 files changed, 16 insertions(+), 77 deletions(-) diff --git a/app/presenters/bill-runs/review/factors.presenter.js b/app/presenters/bill-runs/review/factors.presenter.js index b2abfcb2c3..5a560c9484 100644 --- a/app/presenters/bill-runs/review/factors.presenter.js +++ b/app/presenters/bill-runs/review/factors.presenter.js @@ -6,7 +6,7 @@ */ const { formatFinancialYear } = require('../../base.presenter.js') -const { formatAdditionalCharges, formatChargePeriod } = require('./base-review.presenter.js') +const { formatAdditionalCharges, formatChargePeriod, formatAdjustments } = require('./base-review.presenter.js') /** * Formats the review charge reference data ready for presenting in the review charge reference factors page @@ -26,7 +26,7 @@ function go (reviewChargeReference) { } = reviewChargeReference const additionalCharges = formatAdditionalCharges(chargeReference) - const adjustments = _adjustments(reviewChargeReference) + const adjustments = formatAdjustments(reviewChargeReference) return { amendedAggregate, @@ -39,35 +39,6 @@ function go (reviewChargeReference) { } } -function _adjustments (reviewChargeReference) { - const { - abatementAgreement, - canalAndRiverTrustAgreement, - twoPartTariffAgreement, - winterDiscount - } = reviewChargeReference - - const adjustments = [] - - if (abatementAgreement !== 1) { - adjustments.push(`Abatement agreement (${abatementAgreement})`) - } - - if (winterDiscount) { - adjustments.push('Winter discount') - } - - if (twoPartTariffAgreement) { - adjustments.push('Two part tariff agreement') - } - - if (canalAndRiverTrustAgreement) { - adjustments.push('Canal and River trust agreement') - } - - return adjustments -} - module.exports = { go } diff --git a/test/presenters/bill-runs/review/factors.presenter.test.js b/test/presenters/bill-runs/review/factors.presenter.test.js index 18e5597071..10cc08c063 100644 --- a/test/presenters/bill-runs/review/factors.presenter.test.js +++ b/test/presenters/bill-runs/review/factors.presenter.test.js @@ -36,85 +36,53 @@ describe('Bill Runs Review - Factors presenter', () => { }) }) + // NOTE: otherAdjustments combines the results of `formatAdditionalCharges()` and `formatAdjustments()` from + // `base-review.presenter.js`. So, just to ensure the combining is working correctly we just test what we get back + // when we have one of each, and one from each type describe('the "otherAdjustments" property', () => { beforeEach(() => { // Our fixture has this as true by default. We set it false so it doesn't interfere with the following tests reviewChargeReference.twoPartTariffAgreement = false }) - describe('when the charge reference has an abatement agreement', () => { + describe('when the charge reference has only an adjustment', () => { beforeEach(() => { reviewChargeReference.abatementAgreement = 0.3 }) - it('adds the abatement agreement to the otherAdjustments property', () => { + it('the otherAdjustments property only contains the adjustment', () => { const result = FactorsPresenter.go(reviewChargeReference) expect(result.otherAdjustments).to.equal(['Abatement agreement (0.3)']) }) }) - describe('when the charge reference has a winter discount', () => { + describe('when the charge reference has only an additional charge', () => { beforeEach(() => { - reviewChargeReference.winterDiscount = true - }) - - it('adds the winter discount to the otherAdjustments property', () => { - const result = FactorsPresenter.go(reviewChargeReference) - - expect(result.otherAdjustments).to.equal(['Winter discount']) - }) - }) - - describe('when the charge reference has a two part tariff agreement', () => { - beforeEach(() => { - reviewChargeReference.twoPartTariffAgreement = true - }) - - it('adds the two part tariff agreement to the otherAdjustments property', () => { - const result = FactorsPresenter.go(reviewChargeReference) - - expect(result.otherAdjustments).to.equal(['Two part tariff agreement']) - }) - }) - - describe('when the charge reference has a canal and river trust agreement', () => { - beforeEach(() => { - reviewChargeReference.canalAndRiverTrustAgreement = true - }) - - it('adds the canal and river trust agreement to the otherAdjustments property', () => { - const result = FactorsPresenter.go(reviewChargeReference) - - expect(result.otherAdjustments).to.equal(['Canal and River trust agreement']) - }) - }) - - describe('when the charge reference has a supported source', () => { - beforeEach(() => { - reviewChargeReference.chargeReference.supportedSourceName = 'Thames' + reviewChargeReference.chargeReference.waterCompanyCharge = true }) - it('adds the supported source to the otherAdjustments property', () => { + it('the otherAdjustments property only contains the additional charge', () => { const result = FactorsPresenter.go(reviewChargeReference) - expect(result.otherAdjustments).to.equal(['Supported source Thames']) + expect(result.otherAdjustments).to.equal(['Public Water Supply']) }) }) - describe('when the charge reference has a public water supply', () => { + describe('when the charge reference has both an adjustment and an additional charge', () => { beforeEach(() => { + reviewChargeReference.abatementAgreement = 0.3 reviewChargeReference.chargeReference.waterCompanyCharge = true }) - it('adds the public water supply to the otherAdjustments property', () => { + it('the otherAdjustments property contains both', () => { const result = FactorsPresenter.go(reviewChargeReference) - expect(result.otherAdjustments).to.equal(['Public Water Supply']) + expect(result.otherAdjustments).to.equal(['Public Water Supply', 'Abatement agreement (0.3)']) }) }) - describe('when the charge reference has no other adjustments', () => { + describe('when the charge reference has no adjustments or additional charges', () => { beforeEach(() => { reviewChargeReference.twoPartTariffAgreement = false }) From b971662e452c1fc975044774dd86b0d275eed158 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 17:52:11 +0000 Subject: [PATCH 144/147] Update chg ref presenter to use new formatter The reason we added the formatter was because the acceptance tests highlighted we were doing a mix of things depending on - if the factors were set (not 1) - if the factors were set but they had been amended to 1 (they've been unset) Basically, they were hiding and displaying, and the logic was having to mix the original and amended values to control this behaviour. We've now simplified it. If you can amend the factors, we _always_ display them. Plus, we show the amended and original so the two values can be easily compared. This simplifies the logic, which is what allowed us to move a chunk of the 'adjustments' code into a shared formatter. --- .../review-charge-reference.presenter.js | 46 ++---- .../review-charge-reference.presenter.test.js | 138 +++++++++--------- 2 files changed, 86 insertions(+), 98 deletions(-) diff --git a/app/presenters/bill-runs/review/review-charge-reference.presenter.js b/app/presenters/bill-runs/review/review-charge-reference.presenter.js index 6756f1d1aa..42691310df 100644 --- a/app/presenters/bill-runs/review/review-charge-reference.presenter.js +++ b/app/presenters/bill-runs/review/review-charge-reference.presenter.js @@ -9,6 +9,7 @@ const { formatFinancialYear } = require('../../base.presenter.js') const { calculateTotalBillableReturns, formatAdditionalCharges, + formatAdjustments, formatChargePeriod } = require('./base-review.presenter.js') @@ -29,11 +30,15 @@ function go (reviewChargeReference) { id: reviewChargeReferenceId } = reviewChargeReference + const canAmend = _canAmend(reviewChargeReference) + const adjustments = formatAdjustments(reviewChargeReference) + const factors = _factors(reviewChargeReference, canAmend) + return { additionalCharges: formatAdditionalCharges(chargeReference).join(', '), - adjustments: _adjustments(reviewChargeReference), + adjustments: [...factors, ...adjustments], amendedAuthorisedVolume, - canAmend: _canAmend(reviewChargeReference), + canAmend, chargeCategory: chargeReference.chargeCategory.reference, chargeDescription: chargeReference.chargeCategory.shortDescription, chargePeriod: formatChargePeriod(reviewChargeVersion), @@ -44,45 +49,22 @@ function go (reviewChargeReference) { } } -function _adjustments (reviewChargeReference) { +function _factors (reviewChargeReference, canAmend) { const { - abatementAgreement, aggregate, amendedAggregate, amendedChargeAdjustment, - canalAndRiverTrustAgreement, - chargeAdjustment, - twoPartTariffAgreement, - winterDiscount + chargeAdjustment } = reviewChargeReference - const adjustments = [] - - if (aggregate !== 1) { - adjustments.push(`Aggregate factor (${amendedAggregate})`) - } - - if (chargeAdjustment !== 1) { - adjustments.push(`Charge adjustment (${amendedChargeAdjustment})`) - } - - if (abatementAgreement !== 1) { - adjustments.push(`Abatement agreement (${abatementAgreement})`) - } - - if (winterDiscount) { - adjustments.push('Winter discount') - } - - if (twoPartTariffAgreement) { - adjustments.push('Two part tariff agreement') - } + const factors = [] - if (canalAndRiverTrustAgreement) { - adjustments.push('Canal and River trust agreement') + if (canAmend) { + factors.push(`Aggregate factor (${amendedAggregate} / ${aggregate})`) + factors.push(`Charge adjustment (${amendedChargeAdjustment} / ${chargeAdjustment})`) } - return adjustments + return factors } function _canAmend (reviewChargeReference) { diff --git a/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js b/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js index c9566b691e..eb4451e856 100644 --- a/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js +++ b/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js @@ -40,6 +40,9 @@ describe('Bill Runs Review - Review Charge Reference presenter', () => { }) }) + // NOTE: adjustments combines the results of an internal `_factors()` method and `formatAdjustments()` from + // `base-review.presenter.js`. So, the tests focus on ensuring `_factors()` is working and combining as expected with + // the result of `formatAdjustments()`. describe('the "adjustments" property', () => { beforeEach(() => { // Our fixture has these set by default. We set unset them so they don't interfere with the following tests @@ -48,85 +51,88 @@ describe('Bill Runs Review - Review Charge Reference presenter', () => { reviewChargeReference.twoPartTariffAgreement = false }) - describe('when the charge reference has an aggregate factor', () => { - beforeEach(() => { - reviewChargeReference.aggregate = 0.5 - reviewChargeReference.amendedAggregate = 0.5 + // NOTE: A value other than 1 or false means the charge reference has the 'adjustment' + describe('when the user can change the factors', () => { + describe('because the aggregate factor is not 1', () => { + beforeEach(() => { + reviewChargeReference.aggregate = 0.5 + reviewChargeReference.amendedAggregate = 0.6 + }) + + it('adds it to the ""adjustments" property and displays both amended and original values', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal([ + 'Aggregate factor (0.6 / 0.5)', + 'Charge adjustment (1 / 1)' + ]) + }) }) - it('adds the aggregate factor to the adjustments property', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + describe('because the charge adjustment factor is not 1', () => { + beforeEach(() => { + reviewChargeReference.amendedChargeAdjustment = 0.8 + reviewChargeReference.chargeAdjustment = 0.7 + }) - expect(result.adjustments).to.equal(['Aggregate factor (0.5)']) - }) - }) - - describe('when the charge reference has a charge adjustment factor', () => { - beforeEach(() => { - reviewChargeReference.amendedChargeAdjustment = 0.7 - reviewChargeReference.chargeAdjustment = 0.7 - }) - - it('adds the charge adjustment factor to the adjustments property', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - - expect(result.adjustments).to.equal(['Charge adjustment (0.7)']) - }) - }) - - describe('when the charge reference has a abatement agreement', () => { - beforeEach(() => { - reviewChargeReference.abatementAgreement = 0.3 - }) - - it('adds the abatement agreement to the adjustments property', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - - expect(result.adjustments).to.equal(['Abatement agreement (0.3)']) - }) - }) - - describe('when the charge reference has a winter discount', () => { - beforeEach(() => { - reviewChargeReference.winterDiscount = true - }) - - it('adds the winter discount to the adjustments property', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - - expect(result.adjustments).to.equal(['Winter discount']) - }) - }) + it('adds it to the ""adjustments" property and displays both amended and original values', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - describe('when the charge reference has a two part tariff agreement', () => { - beforeEach(() => { - reviewChargeReference.twoPartTariffAgreement = true + expect(result.adjustments).to.equal([ + 'Aggregate factor (1 / 1)', + 'Charge adjustment (0.8 / 0.7)' + ]) + }) }) - it('adds the two part tariff agreement to the adjustments property', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - - expect(result.adjustments).to.equal(['Two part tariff agreement']) + describe('and there is also an adjustment', () => { + beforeEach(() => { + reviewChargeReference.aggregate = 0.9 + reviewChargeReference.amendedAggregate = 0.9 + reviewChargeReference.twoPartTariffAgreement = true + }) + + it('adds it to the ""adjustments" property along with the factors', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.equal([ + 'Aggregate factor (0.9 / 0.9)', + 'Charge adjustment (1 / 1)', + 'Two part tariff agreement' + ]) + }) }) }) - describe('when the charge reference has a canal and river trust agreement', () => { - beforeEach(() => { - reviewChargeReference.canalAndRiverTrustAgreement = true + describe('when the user cannot change the factors', () => { + describe('because both the aggregate and charge adjustment factors are 1', () => { + beforeEach(() => { + reviewChargeReference.aggregate = 1 + reviewChargeReference.amendedAggregate = 1 + reviewChargeReference.amendedChargeAdjustment = 1 + reviewChargeReference.chargeAdjustment = 1 + }) + + it('does not add either factor to "adjustments"', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + + expect(result.adjustments).to.not.include('Aggregate factor (1)') + expect(result.adjustments).to.not.include('Charge adjustment (1)') + }) }) - it('adds the canal and river trust agreement to the adjustments property', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - - expect(result.adjustments).to.equal(['Canal and River trust agreement']) - }) - }) + describe('but there is an adjustment', () => { + beforeEach(() => { + reviewChargeReference.aggregate = 1 + reviewChargeReference.amendedAggregate = 1 + reviewChargeReference.twoPartTariffAgreement = true + }) - describe('when the charge reference has no adjustments', () => { - it('sets the adjustments property as empty', () => { - const result = ReviewChargeReferencePresenter.go(reviewChargeReference) + it('adds just the adjustment to the ""adjustments" property', () => { + const result = ReviewChargeReferencePresenter.go(reviewChargeReference) - expect(result.adjustments).to.equal([]) + expect(result.adjustments).to.equal(['Two part tariff agreement']) + }) }) }) }) From d832c9e28729a80302f2ccdb7d7ab28b8ad3ed30 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 21:18:57 +0000 Subject: [PATCH 145/147] Fixes and updates to support acceptance tests Either correcting element data attributes or adding them to support the acceptance tests. --- app/views/bill-runs/review/factors.njk | 3 ++- .../bill-runs/review/review-charge-element.njk | 2 +- app/views/bill-runs/review/review-licence.njk | 13 +++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/views/bill-runs/review/factors.njk b/app/views/bill-runs/review/factors.njk index c2b8a2612f..4d15f4780d 100644 --- a/app/views/bill-runs/review/factors.njk +++ b/app/views/bill-runs/review/factors.njk @@ -36,7 +36,8 @@ {% set insertText %}

    Other adjustments apply:

    {% for otherAdjustment in otherAdjustments %} -
    {{otherAdjustment}}
    + {% set adjustmentIndex = loop.index0 %} +
    {{otherAdjustment}}
    {% endfor %} {% endset %} diff --git a/app/views/bill-runs/review/review-charge-element.njk b/app/views/bill-runs/review/review-charge-element.njk index 83fb3a247b..1ca1f56d72 100644 --- a/app/views/bill-runs/review/review-charge-element.njk +++ b/app/views/bill-runs/review/review-charge-element.njk @@ -207,6 +207,6 @@ rows: tableRows }) }} {% else %} -

    No matching two-part tariff returns

    +

    No matching two-part tariff returns

    {% endif %} {% endblock %} diff --git a/app/views/bill-runs/review/review-licence.njk b/app/views/bill-runs/review/review-licence.njk index cfc27fc395..c7a44402a0 100644 --- a/app/views/bill-runs/review/review-licence.njk +++ b/app/views/bill-runs/review/review-licence.njk @@ -40,29 +40,30 @@ {% set issues = '' %} {% for issue in return.issues %} - {% set issues = issues + '
    ' + issue + '
    ' %} + {% set issueIndex = loop.index0 %} + {% set issues = issues + '
    ' + issue + '
    ' %} {% endfor %} {% set tableRow = [ { html: action, classes: 'govuk-body-s', - attributes: { 'data-test': matchType + '-return-action-' + matchedReturnIndex } + attributes: { 'data-test': matchType + '-return-action-' + returnIndex } }, { html: returnSummary, classes: 'govuk-body-s', - attributes: { 'data-test': matchType + '-return-summary-' + matchedReturnIndex } + attributes: { 'data-test': matchType + '-return-summary-' + returnIndex } }, { html: tag, classes: 'govuk-body-s', - attributes: { 'data-test': matchType + '-return-status-' + matchedReturnIndex } + attributes: { 'data-test': matchType + '-return-status-' + returnIndex } }, { html: '
    ' + return.returnTotal + '
    ' + issues, classes: "govuk-body-s govuk-!-text-align-right", - attributes: { 'data-test': matchType + '-return-total-' + matchedReturnIndex } + attributes: { 'data-test': matchType + '-return-total-' + returnIndex } }] %} @@ -244,7 +245,7 @@ {# Unmatched Returns #} {% if unmatchedReturns.length > 0 %} - {{ returnsTable('unmatched', matchedReturns) }} + {{ returnsTable('unmatched', unmatchedReturns) }} {% endif %} {% endif %} From 5140a5526b7aafc7b5d87d3c3fef37c1d228eabe Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 21:40:52 +0000 Subject: [PATCH 146/147] Resolve sonarcloud issues with variable shadowing --- .../fetch-remove-review-licence.service.js | 8 +-- .../fetch-review-charge-element.service.js | 32 +++++----- .../fetch-review-charge-reference.service.js | 28 ++++----- .../review/fetch-review-licence.service.js | 60 +++++++++---------- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/app/services/bill-runs/review/fetch-remove-review-licence.service.js b/app/services/bill-runs/review/fetch-remove-review-licence.service.js index 7b85d9675d..21fe8d167a 100644 --- a/app/services/bill-runs/review/fetch-remove-review-licence.service.js +++ b/app/services/bill-runs/review/fetch-remove-review-licence.service.js @@ -28,8 +28,8 @@ async function _fetch (reviewLicenceId) { 'licenceRef' ]) .withGraphFetched('billRun') - .modifyGraph('billRun', (builder) => { - builder + .modifyGraph('billRun', (billRunBuilder) => { + billRunBuilder .select([ 'id', 'billRunNumber', @@ -38,8 +38,8 @@ async function _fetch (reviewLicenceId) { 'toFinancialYearEnding' ]) .withGraphFetched('region') - .modifyGraph('region', (builder) => { - builder.select([ + .modifyGraph('region', (regionBuilder) => { + regionBuilder.select([ 'id', 'displayName' ]) diff --git a/app/services/bill-runs/review/fetch-review-charge-element.service.js b/app/services/bill-runs/review/fetch-review-charge-element.service.js index a5912e1fcb..547b5e435f 100644 --- a/app/services/bill-runs/review/fetch-review-charge-element.service.js +++ b/app/services/bill-runs/review/fetch-review-charge-element.service.js @@ -33,8 +33,8 @@ async function _fetch (reviewChargeElementId) { 'status' ]) .withGraphFetched('chargeElement') - .modifyGraph('chargeElement', (builder) => { - builder + .modifyGraph('chargeElement', (chargeElementBuilder) => { + chargeElementBuilder .select([ 'id', 'abstractionPeriodStartDay', @@ -46,34 +46,34 @@ async function _fetch (reviewChargeElementId) { ]) }) .withGraphFetched('reviewChargeReference') - .modifyGraph('reviewChargeReference', (builder) => { - builder + .modifyGraph('reviewChargeReference', (reviewChargeReferenceBuilder) => { + reviewChargeReferenceBuilder .select([ 'id', 'amendedAuthorisedVolume' ]) .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder + .modifyGraph('reviewChargeElements', (reviewChargeElementsBuilder) => { + reviewChargeElementsBuilder .select(['id']) }) .withGraphFetched('reviewChargeVersion') - .modifyGraph('reviewChargeVersion', (builder) => { - builder + .modifyGraph('reviewChargeVersion', (reviewChargeVersionBuilder) => { + reviewChargeVersionBuilder .select([ 'id', 'chargePeriodStartDate', 'chargePeriodEndDate' ]).withGraphFetched('reviewLicence') - .modifyGraph('reviewLicence', (builder) => { - builder + .modifyGraph('reviewLicence', (reviewLicenceBuilder) => { + reviewLicenceBuilder .select([ 'id', 'licenceId' ]) .withGraphFetched('billRun') - .modifyGraph('billRun', (builder) => { - builder + .modifyGraph('billRun', (billRunBuilder) => { + billRunBuilder .select([ 'id', 'toFinancialYearEnding' @@ -83,8 +83,8 @@ async function _fetch (reviewChargeElementId) { }) }) .withGraphFetched('reviewReturns') - .modifyGraph('reviewReturns', (builder) => { - builder + .modifyGraph('reviewReturns', (reviewReturnsBuilder) => { + reviewReturnsBuilder .select([ 'reviewReturns.id', 'reviewReturns.allocated', @@ -101,8 +101,8 @@ async function _fetch (reviewChargeElementId) { ]) .orderBy('reviewReturns.startDate', 'asc') .withGraphFetched('returnLog') - .modifyGraph('returnLog', (builder) => { - builder + .modifyGraph('returnLog', (returnLogBuilder) => { + returnLogBuilder .select([ 'id', ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), diff --git a/app/services/bill-runs/review/fetch-review-charge-reference.service.js b/app/services/bill-runs/review/fetch-review-charge-reference.service.js index 5fecb7ce45..1f107be829 100644 --- a/app/services/bill-runs/review/fetch-review-charge-reference.service.js +++ b/app/services/bill-runs/review/fetch-review-charge-reference.service.js @@ -40,30 +40,30 @@ async function _fetch (reviewChargeReferenceId) { 'winterDiscount' ]) .withGraphFetched('reviewChargeVersion') - .modifyGraph('reviewChargeVersion', (builder) => { - builder + .modifyGraph('reviewChargeVersion', (reviewChargeVersionBuilder) => { + reviewChargeVersionBuilder .select([ 'id', 'chargePeriodStartDate', 'chargePeriodEndDate' ]) .withGraphFetched('reviewLicence') - .modifyGraph('reviewLicence', (builder) => { - builder + .modifyGraph('reviewLicence', (reviewLicenceBuilder) => { + reviewLicenceBuilder .select([ 'id' ]) .withGraphFetched('billRun') - .modifyGraph('billRun', (builder) => { - builder + .modifyGraph('billRun', (billRunBuilder) => { + billRunBuilder .select([ 'id', 'toFinancialYearEnding' ]) }) .withGraphFetched('licence') - .modifyGraph('licence', (builder) => { - builder + .modifyGraph('licence', (licenceBuilder) => { + licenceBuilder .select([ 'id', 'waterUndertaker' @@ -72,16 +72,16 @@ async function _fetch (reviewChargeReferenceId) { }) }) .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder + .modifyGraph('reviewChargeElements', (reviewChargeElementsBuilder) => { + reviewChargeElementsBuilder .select([ 'id', 'amendedAllocated' ]) }) .withGraphFetched('chargeReference') - .modifyGraph('chargeReference', (builder) => { - builder + .modifyGraph('chargeReference', (chargeReferenceBuilder) => { + chargeReferenceBuilder .select([ 'id', 'volume', @@ -90,8 +90,8 @@ async function _fetch (reviewChargeReferenceId) { ref('chargeReferences.additionalCharges:isSupplyPublicWater').castText().as('waterCompanyCharge') ]) .withGraphFetched('chargeCategory') - .modifyGraph('chargeCategory', (builder) => { - builder + .modifyGraph('chargeCategory', (chargeCategoryBuilder) => { + chargeCategoryBuilder .select([ 'id', 'reference', diff --git a/app/services/bill-runs/review/fetch-review-licence.service.js b/app/services/bill-runs/review/fetch-review-licence.service.js index 78c86f8731..31161ab0fc 100644 --- a/app/services/bill-runs/review/fetch-review-licence.service.js +++ b/app/services/bill-runs/review/fetch-review-licence.service.js @@ -34,23 +34,23 @@ async function _fetch (reviewLicenceId) { 'progress' ]) .withGraphFetched('billRun') - .modifyGraph('billRun', (builder) => { - builder + .modifyGraph('billRun', (billRunBuilder) => { + billRunBuilder .select([ 'id', 'toFinancialYearEnding' ]) .withGraphFetched('region') - .modifyGraph('region', (builder) => { - builder.select([ + .modifyGraph('region', (regionBuilder) => { + regionBuilder.select([ 'id', 'displayName' ]) }) }) .withGraphFetched('reviewReturns') - .modifyGraph('reviewReturns', (builder) => { - builder + .modifyGraph('reviewReturns', (reviewReturnsBuilder) => { + reviewReturnsBuilder .select([ 'id', 'allocated', @@ -67,8 +67,8 @@ async function _fetch (reviewLicenceId) { ]) .orderBy('reviewReturns.startDate', 'asc') .withGraphFetched('returnLog') - .modifyGraph('returnLog', (builder) => { - builder + .modifyGraph('returnLog', (returnLogBuilder) => { + returnLogBuilder .select([ 'id', ref('metadata:nald.periodStartDay').castInt().as('periodStartDay'), @@ -78,16 +78,16 @@ async function _fetch (reviewLicenceId) { ]) }) .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder + .modifyGraph('reviewChargeElements', (reviewChargeElementsBuilder) => { + reviewChargeElementsBuilder .select([ 'reviewChargeElements.id' ]) }) }) .withGraphFetched('reviewChargeVersions') - .modifyGraph('reviewChargeVersions', (builder) => { - builder + .modifyGraph('reviewChargeVersions', (reviewChargeVersions) => { + reviewChargeVersions .select([ 'id', 'chargePeriodEndDate', @@ -95,8 +95,8 @@ async function _fetch (reviewLicenceId) { ]) .orderBy('chargePeriodStartDate', 'asc') .withGraphFetched('reviewChargeReferences') - .modifyGraph('reviewChargeReferences', (builder) => { - builder + .modifyGraph('reviewChargeReferences', (reviewChargeReferencesBuilder) => { + reviewChargeReferencesBuilder .select([ 'id', 'aggregate', @@ -104,14 +104,14 @@ async function _fetch (reviewLicenceId) { 'chargeAdjustment' ]) .withGraphFetched('chargeReference') - .modifyGraph('chargeReference', (builder) => { - builder + .modifyGraph('chargeReference', (chargeReferenceBuilder) => { + chargeReferenceBuilder .select([ 'id' ]) .withGraphFetched('chargeCategory') - .modifyGraph('chargeCategory', (builder) => { - builder + .modifyGraph('chargeCategory', (chargeCategoryBuilder) => { + chargeCategoryBuilder .select([ 'id', 'reference', @@ -120,8 +120,8 @@ async function _fetch (reviewLicenceId) { }) }) .withGraphFetched('reviewChargeElements') - .modifyGraph('reviewChargeElements', (builder) => { - builder + .modifyGraph('reviewChargeElements', (reviewChargeElementsBuilder) => { + reviewChargeElementsBuilder .select([ 'reviewChargeElements.id', 'reviewChargeElements.amendedAllocated', @@ -131,8 +131,8 @@ async function _fetch (reviewLicenceId) { .join('chargeElements', 'reviewChargeElements.chargeElementId', 'chargeElements.id') .orderBy('chargeElements.authorisedAnnualQuantity', 'desc') .withGraphFetched('chargeElement') - .modifyGraph('chargeElement', (builder) => { - builder + .modifyGraph('chargeElement', (chargeElementBuilder) => { + chargeElementBuilder .select([ 'id', 'abstractionPeriodStartDay', @@ -143,8 +143,8 @@ async function _fetch (reviewLicenceId) { 'description' ]) .withGraphFetched('purpose') - .modifyGraph('purpose', (builder) => { - builder + .modifyGraph('purpose', (purposeBuilder) => { + purposeBuilder .select([ 'id', 'description' @@ -152,8 +152,8 @@ async function _fetch (reviewLicenceId) { }) }) .withGraphFetched('reviewReturns') - .modifyGraph('reviewReturns', (builder) => { - builder + .modifyGraph('reviewReturns', (reviewReturnsBuilder) => { + reviewReturnsBuilder .select([ 'reviewReturns.id', 'reviewReturns.quantity', @@ -164,14 +164,14 @@ async function _fetch (reviewLicenceId) { }) }) .withGraphFetched('chargeVersion') - .modifyGraph('chargeVersion', (builder) => { - builder + .modifyGraph('chargeVersion', (chargeVersionBuilder) => { + chargeVersionBuilder .select([ 'id' ]) .withGraphFetched('billingAccount') - .modifyGraph('billingAccount', (builder) => { - builder.modify('contactDetails') + .modifyGraph('billingAccount', (billingAccountBuilder) => { + billingAccountBuilder.modify('contactDetails') }) }) }) From e581c0ac25877ea22052c9c5d7759d2bce230194 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Thu, 7 Nov 2024 21:51:06 +0000 Subject: [PATCH 147/147] Fix broken tests --- .../review/base-review.presenter.test.js | 12 ++++++------ .../review-charge-reference.presenter.test.js | 6 +++++- .../review-charge-reference.service.test.js | 18 +++++++++++++++--- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/test/presenters/bill-runs/review/base-review.presenter.test.js b/test/presenters/bill-runs/review/base-review.presenter.test.js index c4d02b6180..707588366a 100644 --- a/test/presenters/bill-runs/review/base-review.presenter.test.js +++ b/test/presenters/bill-runs/review/base-review.presenter.test.js @@ -133,7 +133,7 @@ describe('Bill Runs Review - Base Review presenter', () => { }) it('returns an empty array', () => { - const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + const result = BaseReviewPresenter.formatAdjustments(reviewChargeReference) expect(result).to.be.empty() }) @@ -146,7 +146,7 @@ describe('Bill Runs Review - Base Review presenter', () => { }) it('includes it in the array returned', () => { - const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + const result = BaseReviewPresenter.formatAdjustments(reviewChargeReference) expect(result).to.include('Abatement agreement (0.3)') }) @@ -158,7 +158,7 @@ describe('Bill Runs Review - Base Review presenter', () => { }) it('does not add include it in the array returned', () => { - const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + const result = BaseReviewPresenter.formatAdjustments(reviewChargeReference) expect(result).to.not.include('Abatement agreement (1)') }) @@ -171,7 +171,7 @@ describe('Bill Runs Review - Base Review presenter', () => { }) it('includes it in the array returned', () => { - const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + const result = BaseReviewPresenter.formatAdjustments(reviewChargeReference) expect(result).to.include('Winter discount') }) @@ -183,7 +183,7 @@ describe('Bill Runs Review - Base Review presenter', () => { }) it('includes it in the array returned', () => { - const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + const result = BaseReviewPresenter.formatAdjustments(reviewChargeReference) expect(result).to.include('Two part tariff agreement') }) @@ -195,7 +195,7 @@ describe('Bill Runs Review - Base Review presenter', () => { }) it('includes it in the array returned', () => { - const result = BaseReviewPresenter.formatOtherAdjustments(reviewChargeReference) + const result = BaseReviewPresenter.formatAdjustments(reviewChargeReference) expect(result).to.include('Canal and River trust agreement') }) diff --git a/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js b/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js index eb4451e856..daffa75b5c 100644 --- a/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js +++ b/test/presenters/bill-runs/review/review-charge-reference.presenter.test.js @@ -26,7 +26,11 @@ describe('Bill Runs Review - Review Charge Reference presenter', () => { expect(result).to.equal({ additionalCharges: '', - adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + adjustments: [ + 'Aggregate factor (0.333333333 / 0.333333333)', + 'Charge adjustment (1 / 1)', + 'Two part tariff agreement' + ], amendedAuthorisedVolume: 9.092, canAmend: true, chargeCategory: '4.6.5', diff --git a/test/services/bill-runs/review/review-charge-reference.service.test.js b/test/services/bill-runs/review/review-charge-reference.service.test.js index f8ff472ff4..0053d2b1eb 100644 --- a/test/services/bill-runs/review/review-charge-reference.service.test.js +++ b/test/services/bill-runs/review/review-charge-reference.service.test.js @@ -50,7 +50,11 @@ describe('Bill Runs Review - Review Charge Reference Service', () => { bannerMessage: 'The authorised volume for this licence have been updated', chargeMessage: undefined, additionalCharges: '', - adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + adjustments: [ + 'Aggregate factor (0.333333333 / 0.333333333)', + 'Charge adjustment (1 / 1)', + 'Two part tariff agreement' + ], amendedAuthorisedVolume: 9.092, canAmend: true, chargeCategory: '4.6.5', @@ -82,7 +86,11 @@ describe('Bill Runs Review - Review Charge Reference Service', () => { bannerMessage: undefined, chargeMessage: 'Based on this information the example charge is £256.48.', additionalCharges: '', - adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + adjustments: [ + 'Aggregate factor (0.333333333 / 0.333333333)', + 'Charge adjustment (1 / 1)', + 'Two part tariff agreement' + ], amendedAuthorisedVolume: 9.092, canAmend: true, chargeCategory: '4.6.5', @@ -114,7 +122,11 @@ describe('Bill Runs Review - Review Charge Reference Service', () => { bannerMessage: undefined, chargeMessage: undefined, additionalCharges: '', - adjustments: ['Aggregate factor (0.333333333)', 'Two part tariff agreement'], + adjustments: [ + 'Aggregate factor (0.333333333 / 0.333333333)', + 'Charge adjustment (1 / 1)', + 'Two part tariff agreement' + ], amendedAuthorisedVolume: 9.092, canAmend: true, chargeCategory: '4.6.5',