Skip to content

Commit

Permalink
Move SendTransactions to root with refactoring (#745)
Browse files Browse the repository at this point in the history
https://eaflood.atlassian.net/browse/WATER-4365

> For context this came out of us working on re-implementing the SROC annual bill run using what we've learnt and components from our supplementary billing engine.

As part of looking at re-implementing the SROC annual billing engine in this project our spike (WATER-4348 ) confirmed we'd need to reuse some of the services currently sitting in `app/services/bill-runs/supplementary`.

We moved most of these in [Move shared billing services to bill-runs root](#720) but left `app/services/bill-runs/supplementary/send-transactions.service.js` out even though we also need to reuse it.

When working on the spike we found there is some tidying up we can do in the service. We also spotted we were passing in `BillLicence` purely to set the `billLicenceId`. We now feel this should be done elsewhere.

So, we're doing those changes here as they are a little more involved than simply moving the service.
  • Loading branch information
Cruikshanks authored Feb 20, 2024
1 parent 2e8c94d commit ab71295
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 161 deletions.
16 changes: 9 additions & 7 deletions app/services/bill-runs/generate-transactions.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const CalculateAuthorisedAndBillableDaysServiceService = require('./calculate-au
* They will then be returned in an array for further processing before being persisted to the DB as
* `billing_transactions`.
*
* @param {String} billLicenceId The UUID of the bill licence the transaction will be linked to
* @param {Object} chargeReference The charge reference the transaction generated from
* @param {Object} billingPeriod A start and end date representing the billing period for the bill run
* @param {Object} chargePeriod A start and end date representing the charge period for the charge version
Expand All @@ -32,7 +33,7 @@ const CalculateAuthorisedAndBillableDaysServiceService = require('./calculate-au
*
* @returns {Object[]} an array of 0, 1 or 2 transaction objects
*/
function go (chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker) {
function go (billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker) {
const { authorisedDays, billableDays } = CalculateAuthorisedAndBillableDaysServiceService.go(
chargePeriod,
billingPeriod,
Expand All @@ -46,7 +47,7 @@ function go (chargeReference, billingPeriod, chargePeriod, newLicence, waterUnde
}

const standardTransaction = _standardTransaction(
generateUUID(),
billLicenceId,
authorisedDays,
billableDays,
chargeReference,
Expand All @@ -58,7 +59,7 @@ function go (chargeReference, billingPeriod, chargePeriod, newLicence, waterUnde
transactions.push(standardTransaction)

if (!waterUndertaker) {
const compensationTransaction = _compensationTransaction(generateUUID(), standardTransaction)
const compensationTransaction = _compensationTransaction(standardTransaction)
transactions.push(compensationTransaction)
}

Expand All @@ -69,10 +70,10 @@ function go (chargeReference, billingPeriod, chargePeriod, newLicence, waterUnde
* Generates a compensation transaction by taking a standard transaction and overwriting it with the supplied billing id
* and the correct charge type and description for a compensation charge.
*/
function _compensationTransaction (transactionId, standardTransaction) {
function _compensationTransaction (standardTransaction) {
return {
...standardTransaction,
id: transactionId,
id: generateUUID(),
chargeType: 'compensation',
description: 'Compensation charge: calculated from the charge reference, activity description and regional environmental improvement charge; excludes any supported source additional charge and two-part tariff charge agreement'
}
Expand Down Expand Up @@ -102,7 +103,7 @@ function _generateElements (chargeReference) {
* Generates a standard transaction based on the supplied data, along with some default fields (eg. status)
*/
function _standardTransaction (
transactionId,
billLicenceId,
authorisedDays,
billableDays,
chargeReference,
Expand All @@ -111,7 +112,8 @@ function _standardTransaction (
waterUndertaker
) {
return {
id: transactionId,
id: generateUUID(),
billLicenceId,
authorisedDays,
billableDays,
newLicence,
Expand Down
62 changes: 62 additions & 0 deletions app/services/bill-runs/send-transactions.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict'

/**
* Sends transactions to the Charging Module
* @module SendTransactionsService
*/

const BillRunError = require('../../errors/bill-run.error.js')
const BillRunModel = require('../../models/bill-run.model.js')
const ChargingModuleCreateTransactionService = require('../charging-module/create-transaction.service.js')
const ChargingModuleCreateTransactionPresenter = require('../../presenters/charging-module/create-transaction.presenter.js')

/**
* Sends the provided transactions to the Charging Module and returns an array of the sent transactions
*
* Each sent transaction is updated with a status of `charge_created` and the external id returned by the
* Charging Module.
*
* @param {Object[]} transactions - The transactions to be sent to the Charging Module
* @param {string} billRunExternalId - The Charging Module bill run id that the transactions are to be created on
* @param {string} accountNumber - The billing account number for the transactions
* @param {module:LicenceModel} licence - The licence that each transaction is linked to
*
* @returns {Promise<Object[]>} Array of transactions which have been sent to the Charging Module and updated with its
* response
*/
async function go (transactions, billRunExternalId, accountNumber, licence) {
// NOTE: we purposefully loop through all the transactions to send without awaiting them. This is for performance
// purposes. If for example we have 3 transactions to send we'll send the requests 1 straight after the other. We
// then wait for all 3 to complete. The overall process time will only be that of the one that takes the longest. If
// we await instead the overall time will be the sum of the time to complete each one.
const sendRequests = transactions.map((transaction) => {
return _sendTransactionToChargingModule(transaction, billRunExternalId, accountNumber, licence)
})

// We use Promise.all() to ensure we wait for all the send requests to resolve. The service that awaits the call to
// SendTransactionsService.go() will still get the updated transactions as Promise.all() returns what each promise
// resolves to as an array.
return Promise.all(sendRequests)
}

async function _sendTransactionToChargingModule (transaction, billRunExternalId, accountNumber, licence) {
try {
const chargingModuleRequest = ChargingModuleCreateTransactionPresenter.go(transaction, accountNumber, licence)

const chargingModuleResponse = await ChargingModuleCreateTransactionService.go(
billRunExternalId,
chargingModuleRequest
)

transaction.status = 'charge_created'
transaction.externalId = chargingModuleResponse.response.body.transaction.id

return transaction
} catch (error) {
throw new BillRunError(error, BillRunModel.errorCodes.failedToCreateCharge)
}
}

module.exports = {
go
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const DetermineMinimumChargeService = require('../determine-minimum-charge.servi
const GenerateTransactionsService = require('../generate-transactions.service.js')
const PreGenerateBillingDataService = require('./pre-generate-billing-data.service.js')
const ProcessTransactionsService = require('./process-transactions.service.js')
const SendTransactionsService = require('./send-transactions.service.js')
const SendTransactionsService = require('../send-transactions.service.js')
const TransactionModel = require('../../../models/transaction.model.js')

/**
Expand Down Expand Up @@ -62,11 +62,10 @@ async function _buildDataToPersist (billingData, billingPeriod, billRunExternalI

if (cleansedTransactions.length !== 0) {
const transactions = await SendTransactionsService.go(
currentBillingData.licence,
currentBillingData.bill,
currentBillingData.billLicence,
cleansedTransactions,
billRunExternalId,
cleansedTransactions
currentBillingData.bill.accountNumber,
currentBillingData.licence
)

dataToPersist.transactions.push(...transactions)
Expand Down Expand Up @@ -119,7 +118,7 @@ function _buildBillingDataWithTransactions (chargeVersions, preGeneratedData, bi
// We only need to calculate the transactions for charge versions with a status of `current` (APPROVED).
// We fetch the previous transactions for `superseded` (REPLACED) charge versions later in the process
if (chargeVersion.status === 'current') {
const calculatedTransactions = _generateCalculatedTransactions(billingPeriod, chargeVersion)
const calculatedTransactions = _generateCalculatedTransactions(billLicenceId, billingPeriod, chargeVersion)
acc[billLicenceId].calculatedTransactions.push(...calculatedTransactions)
}

Expand Down Expand Up @@ -185,7 +184,7 @@ async function _cleanseTransactions (currentBillingData, billingPeriod) {
return cleansedTransactions
}

function _generateCalculatedTransactions (billingPeriod, chargeVersion) {
function _generateCalculatedTransactions (billLicenceId, billingPeriod, chargeVersion) {
try {
const chargePeriod = DetermineChargePeriodService.go(chargeVersion, billingPeriod)

Expand All @@ -199,6 +198,7 @@ function _generateCalculatedTransactions (billingPeriod, chargeVersion) {
// We use flatMap as GenerateTransactionsService returns an array of transactions
const transactions = chargeVersion.chargeReferences.flatMap((chargeReference) => {
return GenerateTransactionsService.go(
billLicenceId,
chargeReference,
billingPeriod,
chargePeriod,
Expand Down
68 changes: 0 additions & 68 deletions app/services/bill-runs/supplementary/send-transactions.service.js

This file was deleted.

42 changes: 32 additions & 10 deletions test/services/bill-runs/generate-transactions.service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const CalculateAuthorisedAndBillableDaysService = require('../../../app/services
const GenerateTransactionsService = require('../../../app/services/bill-runs/generate-transactions.service.js')

describe('Generate Transactions service', () => {
const billLicenceId = '5e2afb53-ca92-4515-ad71-36a7cefbcebb'
const reference = '4.4.5'

let chargePeriod
Expand Down Expand Up @@ -63,6 +64,7 @@ describe('Generate Transactions service', () => {
newLicence = false

expectedStandardChargeResult = {
billLicenceId,
chargeReferenceId: chargeReference.id,
startDate: chargePeriod.startDate,
endDate: chargePeriod.endDate,
Expand Down Expand Up @@ -103,7 +105,9 @@ describe('Generate Transactions service', () => {
})

it('returns an array of one transaction containing the expected data', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

// Should only return the 'standard' charge transaction line
expect(results).to.have.length(1)
Expand All @@ -118,7 +122,9 @@ describe('Generate Transactions service', () => {
})

it('returns the charge element as JSON in the transaction line `purposes` property', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

const parsedElements = JSON.parse(results[0].purposes)

Expand All @@ -128,7 +134,9 @@ describe('Generate Transactions service', () => {

describe('and is not a water undertaker', () => {
it('returns an array of two transactions containing the expected data', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

// Should return both a 'standard' charge and 'compensation' charge transaction line
expect(results).to.have.length(2)
Expand All @@ -143,7 +151,9 @@ describe('Generate Transactions service', () => {
})

it('returns a second compensation charge transaction', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

expect(results[1]).to.equal(
{
Expand All @@ -157,7 +167,9 @@ describe('Generate Transactions service', () => {
})

it('returns the charge element as JSON in both transaction lines `purposes` property', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

const parsedStandardElements = JSON.parse(results[0].purposes)
const parsedCompensationElements = JSON.parse(results[1].purposes)
Expand All @@ -176,15 +188,19 @@ describe('Generate Transactions service', () => {
})

it('returns `newLicence` as true in the results', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

expect(results[0].newLicence).to.be.true()
})
})

describe('and is not a new licence', () => {
it('returns `newLicence` as false in the results', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

expect(results[0].newLicence).to.be.false()
})
Expand All @@ -193,7 +209,9 @@ describe('Generate Transactions service', () => {
describe('and a two-part tariff agreement (section 127)', () => {
describe('has not applied', () => {
it('returns the standard description', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

expect(results[0].description).to.equal(`Water abstraction charge: ${chargeReference.description}`)
})
Expand All @@ -205,7 +223,9 @@ describe('Generate Transactions service', () => {
})

it('returns the two-part tariff prefixed description', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

expect(results[0].description).to.equal(`Two-part tariff basic water abstraction charge: ${chargeReference.description}`)
})
Expand All @@ -224,7 +244,9 @@ describe('Generate Transactions service', () => {
})

it('returns an empty array', () => {
const results = GenerateTransactionsService.go(chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker)
const results = GenerateTransactionsService.go(
billLicenceId, chargeReference, billingPeriod, chargePeriod, newLicence, waterUndertaker
)

expect(results).to.be.empty()
})
Expand Down
Loading

0 comments on commit ab71295

Please sign in to comment.