From e51889f81448563dd3e1010da7a423b6c7d0567c Mon Sep 17 00:00:00 2001 From: Jason Claxton <30830544+Jozzey@users.noreply.github.com> Date: Thu, 23 May 2024 10:55:21 +0100 Subject: [PATCH] Calculate and display expected charge during 2PT review (#1036) https://eaflood.atlassian.net/browse/WATER-4441 Add functionality to the Review Charge Reference page to allow the user to preview the charge for the Charge Reference. The preview of the charge will be triggered by a button on the Review Charge Reference details page and will display the result in a banner at the top of the screen. This is the first of two PRs. In this PR a new Charging Module "request" is being added to enable a request to be sent to the Charging Module to calculate a charge. The next PR will cover adding the functionality to the screens to enable a charge to be calculated for a charge reference. --- .../calculate-charge.request.js | 28 ++++ .../calculate-charge.request.test.js | 158 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 app/requests/charging-module/calculate-charge.request.js create mode 100644 test/requests/charging-module/calculate-charge.request.test.js diff --git a/app/requests/charging-module/calculate-charge.request.js b/app/requests/charging-module/calculate-charge.request.js new file mode 100644 index 0000000000..11fdf18605 --- /dev/null +++ b/app/requests/charging-module/calculate-charge.request.js @@ -0,0 +1,28 @@ +'use strict' + +/** + * Connects with the Charging Module to calculate a standalone charge + * @module CalculateChargeRequest + */ + +const ChargingModuleRequest = require('../charging-module.request.js') + +/** + * Sends a request to the Charging Module to calculate a standalone charge and returns the result. + * + * See {@link https://defra.github.io/sroc-charging-module-api-docs/#/calculate/CalculateCharge | API docs} for + * more details + * + * @param {Object} transactionData - The transaction details to be sent in the body of the request + * + * @returns {Promise} The result of the request; whether it succeeded and the response or error returned + */ +async function send (transactionData) { + const path = 'v3/wrls/calculate-charge' + + return ChargingModuleRequest.post(path, transactionData) +} + +module.exports = { + send +} diff --git a/test/requests/charging-module/calculate-charge.request.test.js b/test/requests/charging-module/calculate-charge.request.test.js new file mode 100644 index 0000000000..a4b97354a7 --- /dev/null +++ b/test/requests/charging-module/calculate-charge.request.test.js @@ -0,0 +1,158 @@ +'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 ChargingModuleRequest = require('../../../app/requests/charging-module.request.js') + +// Thing under test +const CalculateChargeRequest = require('../../../app/requests/charging-module/calculate-charge.request.js') + +describe('Charging Module Calculate Charge request', () => { + const transactionData = _transactionData() + + afterEach(() => { + Sinon.restore() + }) + + describe('when the charge can be calculated', () => { + beforeEach(async () => { + Sinon.stub(ChargingModuleRequest, 'post').resolves({ + succeeded: true, + response: { + info: { + gitCommit: '273604040a47e0977b0579a0fef0f09726d95e39', + dockerTag: 'ghcr.io/defra/sroc-charging-module-api:v0.19.0' + }, + statusCode: 200, + body: { + calculation: { + chargeValue: 7000, + baseCharge: 9700, + waterCompanyChargeValue: 800, + supportedSourceValue: 3500, + winterOnlyFactor: null, + section130Factor: null, + section127Factor: 0.5, + compensationChargePercent: null + } + } + } + }) + }) + + it('returns a "true" success status', async () => { + const result = await CalculateChargeRequest.send(transactionData) + + expect(result.succeeded).to.be.true() + }) + + it('returns the results of the calculation in the "response"', async () => { + const result = await CalculateChargeRequest.send(transactionData) + + expect(result.response.body.calculation.chargeValue).to.equal(7000) + expect(result.response.body.calculation.baseCharge).to.equal(9700) + expect(result.response.body.calculation.waterCompanyChargeValue).to.equal(800) + expect(result.response.body.calculation.supportedSourceValue).to.equal(3500) + expect(result.response.body.calculation.winterOnlyFactor).to.be.null() + expect(result.response.body.calculation.section130Factor).to.be.null() + expect(result.response.body.calculation.section127Factor).to.equal(0.5) + expect(result.response.body.calculation.compensationChargePercent).to.be.null() + }) + }) + + describe('when the request cannot calculate a charge', () => { + describe('because the request did not return a 2xx/3xx response', () => { + beforeEach(async () => { + Sinon.stub(ChargingModuleRequest, 'post').resolves({ + succeeded: false, + response: { + info: { + gitCommit: '273604040a47e0977b0579a0fef0f09726d95e39', + dockerTag: 'ghcr.io/defra/sroc-charging-module-api:v0.19.0' + }, + statusCode: 401, + body: { + statusCode: 401, + error: 'Unauthorized', + message: 'Invalid JWT: Token format not valid', + attributes: { error: 'Invalid JWT: Token format not valid' } + } + } + }) + }) + + it('returns a "false" success status', async () => { + const result = await CalculateChargeRequest.send(transactionData) + + expect(result.succeeded).to.be.false() + }) + + it('returns the error in the "response"', async () => { + const result = await CalculateChargeRequest.send(transactionData) + + expect(result.response.body.statusCode).to.equal(401) + expect(result.response.body.error).to.equal('Unauthorized') + expect(result.response.body.message).to.equal('Invalid JWT: Token format not valid') + }) + }) + + describe('because the request attempt returned an error, for example, TimeoutError', () => { + beforeEach(async () => { + Sinon.stub(ChargingModuleRequest, 'post').resolves({ + succeeded: false, + response: new Error("Timeout awaiting 'request' for 5000ms") + }) + }) + + it('returns a "false" success status', async () => { + const result = await CalculateChargeRequest.send(transactionData) + + expect(result.succeeded).to.be.false() + }) + + it('returns the error in the "response"', async () => { + const result = await CalculateChargeRequest.send(transactionData) + + expect(result.response.statusCode).not.to.exist() + expect(result.response.body).not.to.exist() + expect(result.response.message).to.equal("Timeout awaiting 'request' for 5000ms") + }) + }) + }) +}) + +function _transactionData () { + return { + abatementFactor: 1.0, + actualVolume: 1.0, + adjustmentFactor: 1.0, + aggregateProportion: 1.0, + authorisedDays: 21, + authorisedVolume: 1.0, + billableDays: 2, + chargeCategoryCode: '4.1.1', + compensationCharge: false, + credit: false, + loss: 'Low', + periodStart: '01-APR-2022', + periodEnd: '31-MAR-2023', + ruleset: 'sroc', + section127Agreement: true, + section130Agreement: false, + supportedSource: true, + // If `supportedSource` is `true` then `supportedSourceName` must be present + supportedSourceName: 'Candover', + // If `twoPartTariff` is `true` then `section127Agreement` must also be `true` + twoPartTariff: true, + waterCompanyCharge: true, + waterUndertaker: false, + winterOnly: false + } +}