Skip to content

Commit

Permalink
Reverse previous SROC billing batches in supplementary bill run proce…
Browse files Browse the repository at this point in the history
…ss (#186)

https://eaflood.atlassian.net/browse/WATER-3936

When we generate a supplementary bill run, we must reverse the previous ones in the same financial period. Essentially, when a licence is flagged for supplementary billing, for whatever reason, we reverse any previous bill runs and generate a new one.

This marks a change to our previous approach where only the last bill run was reversed. This is due to a scenario being found during testing which needed more than just the last bill run to be reversed. We therefore needed to change how we do this.

The way we decided to approach this is to get all credits and debits then remove any debits which have a matching credit, based on the value of billable days and the charge type. The debits that remain are the ones that we will then turn into credits in order to reverse the previous batches.
  • Loading branch information
Jozzey authored Apr 11, 2023
1 parent 08d6170 commit 6df4b18
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict'

/**
* Fetches the previously billed transactions that match the invoice, licence and year provided
* Fetches the previously billed transactions that match the invoice, licence and year provided, removing any debits
* which are cancelled out by previous credits.
* @module FetchPreviousBillingTransactionsService
*/

Expand All @@ -14,7 +15,29 @@ async function go (billingInvoice, billingInvoiceLicence, financialYearEnding) {
financialYearEnding
)

return billingTransactions
return _cleanse(billingTransactions)
}

/**
* Cleanse the billing transactions by cancelling out matching pairs of debits and credits, and return the remaining
* debits. We judge a pair of credits and debits to be matching if they have the same number of billable days and the
* same charge type.
*/
function _cleanse (billingTransactions) {
const credits = billingTransactions.filter((transaction) => transaction.isCredit)
const debits = billingTransactions.filter((transaction) => !transaction.isCredit)

for (const credit of credits) {
const debitIndex = debits.findIndex((debit) => {
return debit.billableDays === credit.billableDays && debit.chargeType === credit.chargeType
})

if (debitIndex > -1) {
debits.splice(debitIndex, 1)
}
}

return debits
}

async function _fetch (licenceId, invoiceAccountId, financialYearEnding) {
Expand Down Expand Up @@ -70,14 +93,9 @@ async function _fetch (licenceId, invoiceAccountId, financialYearEnding) {
'bb.status': 'sent',
'bb.scheme': 'sroc'
})
.orderBy('bb.dateCreated', 'desc')
.limit(1)
.as('validBillingInvoices'),
'bt.billingInvoiceLicenceId', 'validBillingInvoices.billingInvoiceLicenceId'
)
.where({
'bt.isCredit': false
})
}

module.exports = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,7 @@ describe('Fetch Previous Billing Transactions service', () => {
describe('when there is a bill run', () => {
describe('for the same licence and invoice account', () => {
beforeEach(async () => {
const { billingBatchId } = await BillingBatchHelper.add({ status: 'sent' })
const { billingInvoiceId } = await BillingInvoiceHelper.add({ invoiceAccountId }, { billingBatchId })
const { billingInvoiceLicenceId } = await BillingInvoiceLicenceHelper.add(
{},
{ licenceId },
{ billingInvoiceId }
)
const billingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(invoiceAccountId, licenceId)
await BillingTransactionHelper.add({ billingInvoiceLicenceId })
})

Expand All @@ -63,14 +57,35 @@ describe('Fetch Previous Billing Transactions service', () => {

describe('followed by another run which credits the previous', () => {
beforeEach(async () => {
const { billingBatchId } = await BillingBatchHelper.add({ status: 'sent' })
const { billingInvoiceId } = await BillingInvoiceHelper.add({ invoiceAccountId }, { billingBatchId })
const { billingInvoiceLicenceId } = await BillingInvoiceLicenceHelper.add(
{},
const billingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(invoiceAccountId, licenceId)
await BillingTransactionHelper.add({ billingInvoiceLicenceId, isCredit: true })
})

it('returns no results', async () => {
const result = await FetchPreviousBillingTransactionsService.go(
{ invoiceAccountId },
{ licenceId },
{ billingInvoiceId }
financialYearEnding
)
await BillingTransactionHelper.add({ billingInvoiceLicenceId, isCredit: true })

expect(result).to.be.empty()
})
})

describe('followed by more runs with equal credits and debits', () => {
beforeEach(async () => {
const creditsBillingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(invoiceAccountId, licenceId)
await BillingTransactionHelper.add({
billingInvoiceLicenceId: creditsBillingInvoiceLicenceId,
isCredit: true
})
await BillingTransactionHelper.add({
billingInvoiceLicenceId: creditsBillingInvoiceLicenceId,
isCredit: true
})

const debitBillingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(invoiceAccountId, licenceId)
await BillingTransactionHelper.add({ billingInvoiceLicenceId: debitBillingInvoiceLicenceId })
})

it('returns no results', async () => {
Expand All @@ -83,17 +98,42 @@ describe('Fetch Previous Billing Transactions service', () => {
expect(result).to.be.empty()
})
})

describe('followed by more runs with unequal credits and debits', () => {
beforeEach(async () => {
const unmatchedBillingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(
invoiceAccountId,
licenceId
)
await BillingTransactionHelper.add({
billingInvoiceLicenceId: unmatchedBillingInvoiceLicenceId,
billableDays: 30,
isCredit: true
})

const matchedBillingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(invoiceAccountId, licenceId)
await BillingTransactionHelper.add({
billingInvoiceLicenceId: matchedBillingInvoiceLicenceId,
isCredit: true
})
await BillingTransactionHelper.add({ billingInvoiceLicenceId: matchedBillingInvoiceLicenceId })
})

it('returns results', async () => {
const result = await FetchPreviousBillingTransactionsService.go(
{ invoiceAccountId },
{ licenceId },
financialYearEnding
)

expect(result).to.have.length(1)
})
})
})

describe('but for a different licence', () => {
beforeEach(async () => {
const { billingBatchId } = await BillingBatchHelper.add({ status: 'sent' })
const { billingInvoiceId } = await BillingInvoiceHelper.add({ invoiceAccountId }, { billingBatchId })
const { billingInvoiceLicenceId } = await BillingInvoiceLicenceHelper.add(
{},
{ licenceId: '66498337-e6a6-4a2a-9fb7-e39f43410f80' },
{ billingInvoiceId }
)
const billingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(invoiceAccountId, '66498337-e6a6-4a2a-9fb7-e39f43410f80')
await BillingTransactionHelper.add({ billingInvoiceLicenceId })
})

Expand All @@ -110,15 +150,9 @@ describe('Fetch Previous Billing Transactions service', () => {

describe('but for a different invoice account', () => {
beforeEach(async () => {
const { billingBatchId } = await BillingBatchHelper.add({ status: 'sent' })
const { billingInvoiceId } = await BillingInvoiceHelper.add(
{ invoiceAccountId: 'b0b75e7a-e80a-4c28-9ac9-33b3a850722b' },
{ billingBatchId }
)
const { billingInvoiceLicenceId } = await BillingInvoiceLicenceHelper.add(
{},
{ licenceId },
{ billingInvoiceId }
const billingInvoiceLicenceId = await _createBillingBatchInvoiceAndLicence(
'b0b75e7a-e80a-4c28-9ac9-33b3a850722b',
licenceId
)
await BillingTransactionHelper.add({ billingInvoiceLicenceId })
})
Expand All @@ -135,3 +169,15 @@ describe('Fetch Previous Billing Transactions service', () => {
})
})
})

async function _createBillingBatchInvoiceAndLicence (invoiceAccountId, licenceId) {
const { billingBatchId } = await BillingBatchHelper.add({ status: 'sent' })
const { billingInvoiceId } = await BillingInvoiceHelper.add({ invoiceAccountId }, { billingBatchId })
const { billingInvoiceLicenceId } = await BillingInvoiceLicenceHelper.add(
{},
{ licenceId },
{ billingInvoiceId }
)

return billingInvoiceLicenceId
}

0 comments on commit 6df4b18

Please sign in to comment.