From 73faae8e285a264dad8d5f421b6d81c09f08e476 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Mon, 13 Feb 2023 09:22:49 +0000 Subject: [PATCH 01/20] Add SROC Supplementary Billing Invoice Service https://eaflood.atlassian.net/browse/WATER-3896 In order to 'piggy-back' onto the existing functions in the legacy service for reviewing, confirming, sending, viewing, deleting a bill run etc we need to create the same base database records as it does for a Bill run. This change will add a service to handle creating the `water.billing_batch_invoice` records in the DB. This is the link between the `billing_batch` and the invoice account, and from there to the licences included in the bill run. We'll need to dig into the legacy code to understand where the previous team extracts the data that forms the `billing_invoice` records. We'll then aim to replicate that here. From 51f03ab8ac823c210fa19bd8f1b5528504bcf5d9 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Tue, 21 Feb 2023 13:56:35 +0000 Subject: [PATCH 02/20] add migration to create crm_v2 schema --- .../20230221135143_create-crm-v2-schema.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 db/migrations/20230221135143_create-crm-v2-schema.js diff --git a/db/migrations/20230221135143_create-crm-v2-schema.js b/db/migrations/20230221135143_create-crm-v2-schema.js new file mode 100644 index 0000000000..f2c7d8d6fe --- /dev/null +++ b/db/migrations/20230221135143_create-crm-v2-schema.js @@ -0,0 +1,13 @@ +'use strict' + +exports.up = function (knex) { + return knex.raw(` + CREATE SCHEMA IF NOT EXISTS "crm_v2"; + `) +} + +exports.down = function (knex) { + return knex.raw(` + DROP SCHEMA IF EXISTS "crm_v2"; + `) +} From c7c0d191cc31671d9c439821c6eec020b333c663 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Tue, 21 Feb 2023 14:26:04 +0000 Subject: [PATCH 03/20] add migration to create invoice_accounts table --- .../20230221140243_create-invoice-accounts.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 db/migrations/20230221140243_create-invoice-accounts.js diff --git a/db/migrations/20230221140243_create-invoice-accounts.js b/db/migrations/20230221140243_create-invoice-accounts.js new file mode 100644 index 0000000000..ac2363eb1b --- /dev/null +++ b/db/migrations/20230221140243_create-invoice-accounts.js @@ -0,0 +1,32 @@ +'use strict' + +const tableName = 'invoice_accounts' + +exports.up = async function (knex) { + await knex + .schema + .withSchema('crm_v2') + .createTable(tableName, table => { + // Primary Key + table.uuid('invoice_account_id').primary().defaultTo(knex.raw('gen_random_uuid()')) + + // Data + table.uuid('company_id') + table.string('invoice_account_number') + table.date('start_date') + table.date('end_date') + table.string('last_transaction_file_reference') + table.timestamp('date_last_transaction_file_reference_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + + // Legacy timestamps + table.timestamp('date_created', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + table.timestamp('date_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + }) +} + +exports.down = function (knex) { + return knex + .schema + .withSchema('crm_v2') + .dropTableIfExists(tableName) +} From be2b4f5300061298b6c8b4c87c61f9386b48f602 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Tue, 21 Feb 2023 14:46:01 +0000 Subject: [PATCH 04/20] create invoice-account model and update related --- app/models/crm-v2/invoice-account.model.js | 42 ++++++++++++++++++++++ app/models/water/billing-invoice.model.js | 8 +++++ 2 files changed, 50 insertions(+) create mode 100644 app/models/crm-v2/invoice-account.model.js diff --git a/app/models/crm-v2/invoice-account.model.js b/app/models/crm-v2/invoice-account.model.js new file mode 100644 index 0000000000..642f435dea --- /dev/null +++ b/app/models/crm-v2/invoice-account.model.js @@ -0,0 +1,42 @@ +'use strict' + +/** + * Model for invoiceAccounts + * @module InvoiceAccountModel + */ + +const { Model } = require('objection') + +const WaterBaseModel = require('./water-base.model.js') + +class InvoiceAccountModel extends WaterBaseModel { + static get tableName () { + return 'invoiceAccounts' + } + + static get idColumn () { + return 'invoiceAccountId' + } + + static get translations () { + return [ + { database: 'dateCreated', model: 'createdAt' }, + { database: 'dateUpdated', model: 'updatedAt' } + ] + } + + static get relationMappings () { + return { + billingInvoices: { + relation: Model.HasManyRelation, + modelClass: 'billing-invoice.model', + join: { + from: 'invoiceAccounts.invoiceAccountId', + to: 'billingInvoices.invoiceAccountId' + } + } + } + } +} + +module.exports = InvoiceAccountModel diff --git a/app/models/water/billing-invoice.model.js b/app/models/water/billing-invoice.model.js index 3bf4256c09..b6bcb4e4e7 100644 --- a/app/models/water/billing-invoice.model.js +++ b/app/models/water/billing-invoice.model.js @@ -27,6 +27,14 @@ class BillingInvoiceModel extends WaterBaseModel { static get relationMappings () { return { + invoiceAccount: { + relation: Model.BelongsToOneRelation, + modelClass: 'invoice-account.model', + join: { + from: 'billingInvoices.invoiceAccountId', + to: 'invoiceAccounts.invoiceAccountId' + } + }, billingBatch: { relation: Model.BelongsToOneRelation, modelClass: 'billing-batch.model', From 1ab878bdabe211af02c4ef284c0eaa06932e66c5 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Tue, 21 Feb 2023 15:55:35 +0000 Subject: [PATCH 05/20] fix typo --- .../create-billing-invoice-licence.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/supplementary-billing/create-billing-invoice-licence.service.js b/app/services/supplementary-billing/create-billing-invoice-licence.service.js index 2ef39ceb17..1ef63d1d02 100644 --- a/app/services/supplementary-billing/create-billing-invoice-licence.service.js +++ b/app/services/supplementary-billing/create-billing-invoice-licence.service.js @@ -17,7 +17,7 @@ const BillingInvoiceLicenceModel = require('../../models/water/billing-invoice-l * @returns {Object} The newly-created billing invoice licence record */ async function go (billingInvoice, licence) { - const event = await BillingInvoiceLicenceModel.query() + const billingInvoiceLicence = await BillingInvoiceLicenceModel.query() .insert({ billingInvoiceId: billingInvoice.billingInvoiceId, licenceRef: licence.licenceRef, @@ -25,7 +25,7 @@ async function go (billingInvoice, licence) { }) .returning('*') - return event + return billingInvoiceLicence } module.exports = { From 4ab9dfbacbe0933bee222c869612ba14bf8c9e96 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Tue, 21 Feb 2023 16:12:47 +0000 Subject: [PATCH 06/20] rename invoice-accounts migration to include schema --- ...counts.js => 20230221140243_create-crm-v2-invoice-accounts.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/migrations/{20230221140243_create-invoice-accounts.js => 20230221140243_create-crm-v2-invoice-accounts.js} (100%) diff --git a/db/migrations/20230221140243_create-invoice-accounts.js b/db/migrations/20230221140243_create-crm-v2-invoice-accounts.js similarity index 100% rename from db/migrations/20230221140243_create-invoice-accounts.js rename to db/migrations/20230221140243_create-crm-v2-invoice-accounts.js From 24f20e119d31fbff54592f35149724ff20f0df89 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Tue, 21 Feb 2023 16:38:05 +0000 Subject: [PATCH 07/20] create migration to add columns to billing_invoices table --- ...0221161454_alter-water-billing-invoices.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 db/migrations/20230221161454_alter-water-billing-invoices.js diff --git a/db/migrations/20230221161454_alter-water-billing-invoices.js b/db/migrations/20230221161454_alter-water-billing-invoices.js new file mode 100644 index 0000000000..758bb871a8 --- /dev/null +++ b/db/migrations/20230221161454_alter-water-billing-invoices.js @@ -0,0 +1,51 @@ +'use strict' + +const tableName = 'billing_invoices' + +exports.up = async function (knex) { + await knex + .schema + .withSchema('water') + .alterTable(tableName, table => { + table.uuid('invoice_account_id') + table.jsonb('address') + table.string('invoice_account_number') + table.decimal('net_amount') + table.boolean('is_credit') + table.string('invoice_number') + table.string('legacy_id') + table.jsonb('metadata') + table.decimal('credit_note_value') + table.decimal('invoice_value') + table.boolean('is_de_minimis') + table.uuid('external_id') + table.boolean('is_flagged_for_rebilling') + table.uuid('original_billing_invoice_id') + table.string('rebilling_state') + }) +} + +exports.down = async function (knex) { + return knex + .schema + .withSchema('water') + .alterTable(tableName, table => { + table.dropColumns( + 'invoice_account_id', + 'address', + 'invoice_account_number', + 'net_amount', + 'is_credit', + 'invoice_number', + 'legacy_id', + 'metadata', + 'credit_note_value', + 'invoice_value', + 'is_de_minimis', + 'external_id', + 'is_flagged_for_rebilling', + 'original_billing_invoice_id', + 'rebilling_state' + ) + }) +} From cbc60fafe431f4e850a55e739f9dbe4b5851e84f Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Wed, 22 Feb 2023 14:23:53 +0000 Subject: [PATCH 08/20] create billing-invoice WIP --- .../create-billing-invoice.service.js | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 app/services/supplementary-billing/create-billing-invoice.service.js diff --git a/app/services/supplementary-billing/create-billing-invoice.service.js b/app/services/supplementary-billing/create-billing-invoice.service.js new file mode 100644 index 0000000000..0e3b5f7935 --- /dev/null +++ b/app/services/supplementary-billing/create-billing-invoice.service.js @@ -0,0 +1,36 @@ +'use strict' + +/** + * Creates a billing invoice record + * + * @module CreateBillingInvoiceService + */ + +const BillingInvoiceModel = require('../../models/water/billing-invoice.model.js') + +/** + * Create a billing invoice for the provided invoice account and billing batch + * + * @param {module:InvoiceAccountModel} invoiceAccount An instance of `InvoiceAccountModel` + * @param {Object} cmTransaction Data returned from the Charging Module relating to the transaction + * + * @returns {Object} The newly-created billing invoice record + */ +async function go (invoiceAccount, cmTransaction, billingBatchId) { + const billingInvoice = await BillingInvoiceModel.query() + .insert({ + invoiceAccountId: invoiceAccount.invoiceAccountId, + address: {}, + invoiceAccountNumber: invoiceAccount.invoiceAccountNumber, + netAmount: cmTransaction.netAmount, + isCredit: cmTransaction.netAmount === null ? null : cmTransaction.netAmount < 0, + billingBatchId + }) + .returning('*') + + return billingInvoice +} + +module.exports = { + go +} From a217efb7f84355135fed3fdc2ad517da00eb57fa Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Thu, 23 Feb 2023 12:51:37 +0000 Subject: [PATCH 09/20] include `invoiceAccountId` in charge version data --- .../fetch-charge-versions.service.js | 2 +- ...30223124044_alter-water-charge-versions.js | 23 +++++++++++++++++++ .../helpers/water/charge-version.helper.js | 4 +++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 db/migrations/20230223124044_alter-water-charge-versions.js diff --git a/app/services/supplementary-billing/fetch-charge-versions.service.js b/app/services/supplementary-billing/fetch-charge-versions.service.js index e78ed8bfc8..b5917f3996 100644 --- a/app/services/supplementary-billing/fetch-charge-versions.service.js +++ b/app/services/supplementary-billing/fetch-charge-versions.service.js @@ -27,7 +27,7 @@ async function go (regionId, billingPeriod) { async function _fetch (regionId, billingPeriod) { const chargeVersions = await ChargeVersion.query() - .select('chargeVersionId', 'scheme', 'chargeVersions.startDate', 'chargeVersions.endDate') + .select('chargeVersionId', 'scheme', 'chargeVersions.startDate', 'chargeVersions.endDate', 'invoiceAccountId') .innerJoinRelated('licence') .where('scheme', 'sroc') .where('includeInSupplementaryBilling', 'yes') diff --git a/db/migrations/20230223124044_alter-water-charge-versions.js b/db/migrations/20230223124044_alter-water-charge-versions.js new file mode 100644 index 0000000000..cfc81c706f --- /dev/null +++ b/db/migrations/20230223124044_alter-water-charge-versions.js @@ -0,0 +1,23 @@ +'use strict' + +const tableName = 'charge_versions' + +exports.up = async function (knex) { + await knex + .schema + .withSchema('water') + .alterTable(tableName, table => { + table.uuid('invoice_account_id') + }) +} + +exports.down = async function (knex) { + return knex + .schema + .withSchema('water') + .alterTable(tableName, table => { + table.dropColumns( + 'invoice_account_id' + ) + }) +} diff --git a/test/support/helpers/water/charge-version.helper.js b/test/support/helpers/water/charge-version.helper.js index 6b12f46947..1fb0564db6 100644 --- a/test/support/helpers/water/charge-version.helper.js +++ b/test/support/helpers/water/charge-version.helper.js @@ -18,6 +18,7 @@ const LicenceHelper = require('./licence.helper.js') * - `licenceRef` - 01/123 * - `scheme` - sroc * - `startDate` - 2022-04-01 + * - `invoiceAccountId` - 01931031-4680-4950-87d6-50f8fe784f6d * * See `LicenceHelper` for the licence defaults * @@ -58,7 +59,8 @@ function defaults (data = {}) { const defaults = { licenceRef: '01/123', scheme: 'sroc', - startDate: new Date('2022-04-01') + startDate: new Date('2022-04-01'), + invoiceAccountId: '01931031-4680-4950-87d6-50f8fe784f6d' } return { From af9d97f767df0c1c6ccd38ed24a15f7029bf74d9 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Thu, 23 Feb 2023 14:33:18 +0000 Subject: [PATCH 10/20] add fetch-invoice-account service --- .../fetch-invoice-account.service.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/services/supplementary-billing/fetch-invoice-account.service.js diff --git a/app/services/supplementary-billing/fetch-invoice-account.service.js b/app/services/supplementary-billing/fetch-invoice-account.service.js new file mode 100644 index 0000000000..9390dbbcfa --- /dev/null +++ b/app/services/supplementary-billing/fetch-invoice-account.service.js @@ -0,0 +1,33 @@ +'use strict' + +/** + * Fetches an `invoiceAccount` record based on the `invoiceAccountId` provided + * @module FetchInvoiceAccountService + */ + +const InvoiceAccountModel = require('../../models/crm-v2/invoice-account.model.js') + +/** + * Fetches the `invoiceAccount` with the matching `invoiceAccountId` + * + * @param {string} invoiceAccountId The ID of the `invoiceAccount` to be retrieved + * + * @returns {Object} Instance of `InvoiceAccountModel` with the matching `invoiceAccountId` + */ +async function go (invoiceAccountId) { + const invoiceAccount = await _fetch(invoiceAccountId) + + return invoiceAccount +} + +async function _fetch (invoiceAccountId) { + const result = await InvoiceAccountModel.query() + .where('invoiceAccountId', invoiceAccountId) + .first() + + return result +} + +module.exports = { + go +} From 4919140d32976cc85f0d62c2919fd6665944ce4d Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Thu, 23 Feb 2023 17:08:37 +0000 Subject: [PATCH 11/20] add crm-v2 base model and update related --- app/models/crm-v2/crm-v2-base.model.js | 16 ++++++++++++++++ app/models/crm-v2/invoice-account.model.js | 4 ++-- app/models/legacy-base.model.js | 3 ++- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 app/models/crm-v2/crm-v2-base.model.js diff --git a/app/models/crm-v2/crm-v2-base.model.js b/app/models/crm-v2/crm-v2-base.model.js new file mode 100644 index 0000000000..2de1519b34 --- /dev/null +++ b/app/models/crm-v2/crm-v2-base.model.js @@ -0,0 +1,16 @@ +'use strict' + +/** + * Base class for all models based on the legacy 'crm_v2' schema + * @module CrmV2BaseModel + */ + +const LegacyBaseModel = require('../legacy-base.model.js') + +class CrmV2BaseModel extends LegacyBaseModel { + static get schema () { + return 'crmV2' + } +} + +module.exports = CrmV2BaseModel diff --git a/app/models/crm-v2/invoice-account.model.js b/app/models/crm-v2/invoice-account.model.js index 642f435dea..1753090e06 100644 --- a/app/models/crm-v2/invoice-account.model.js +++ b/app/models/crm-v2/invoice-account.model.js @@ -7,9 +7,9 @@ const { Model } = require('objection') -const WaterBaseModel = require('./water-base.model.js') +const CrmV2BaseModel = require('./crm-v2-base.model.js') -class InvoiceAccountModel extends WaterBaseModel { +class InvoiceAccountModel extends CrmV2BaseModel { static get tableName () { return 'invoiceAccounts' } diff --git a/app/models/legacy-base.model.js b/app/models/legacy-base.model.js index 3cd69674e4..22adbf8619 100644 --- a/app/models/legacy-base.model.js +++ b/app/models/legacy-base.model.js @@ -24,7 +24,8 @@ class LegacyBaseModel extends BaseModel { const currentPath = __dirname return [ currentPath, - path.join(currentPath, 'water') + path.join(currentPath, 'water'), + path.join(currentPath, 'crm-v2') ] } From ba291585fa74f4f70fd3c372a08b1bfd21532888 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Thu, 23 Feb 2023 21:07:34 +0000 Subject: [PATCH 12/20] Remove incorrect relationship the invoiceAccountId whilst it exists in the billingInvoices table it is not a foreign key --- app/models/crm-v2/invoice-account.model.js | 15 --------------- app/models/water/billing-invoice.model.js | 8 -------- 2 files changed, 23 deletions(-) diff --git a/app/models/crm-v2/invoice-account.model.js b/app/models/crm-v2/invoice-account.model.js index 1753090e06..9818d90bf6 100644 --- a/app/models/crm-v2/invoice-account.model.js +++ b/app/models/crm-v2/invoice-account.model.js @@ -5,8 +5,6 @@ * @module InvoiceAccountModel */ -const { Model } = require('objection') - const CrmV2BaseModel = require('./crm-v2-base.model.js') class InvoiceAccountModel extends CrmV2BaseModel { @@ -24,19 +22,6 @@ class InvoiceAccountModel extends CrmV2BaseModel { { database: 'dateUpdated', model: 'updatedAt' } ] } - - static get relationMappings () { - return { - billingInvoices: { - relation: Model.HasManyRelation, - modelClass: 'billing-invoice.model', - join: { - from: 'invoiceAccounts.invoiceAccountId', - to: 'billingInvoices.invoiceAccountId' - } - } - } - } } module.exports = InvoiceAccountModel diff --git a/app/models/water/billing-invoice.model.js b/app/models/water/billing-invoice.model.js index b6bcb4e4e7..3bf4256c09 100644 --- a/app/models/water/billing-invoice.model.js +++ b/app/models/water/billing-invoice.model.js @@ -27,14 +27,6 @@ class BillingInvoiceModel extends WaterBaseModel { static get relationMappings () { return { - invoiceAccount: { - relation: Model.BelongsToOneRelation, - modelClass: 'invoice-account.model', - join: { - from: 'billingInvoices.invoiceAccountId', - to: 'invoiceAccounts.invoiceAccountId' - } - }, billingBatch: { relation: Model.BelongsToOneRelation, modelClass: 'billing-batch.model', From e8d6e527d369160aa009573c33b2568f0864fa56 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Thu, 23 Feb 2023 21:12:56 +0000 Subject: [PATCH 13/20] Fix crm-v2 base model A seperate PR will be going in to prevent knexSnakeCaseMappers from incorrectly formatting the schema name --- app/models/crm-v2/crm-v2-base.model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/crm-v2/crm-v2-base.model.js b/app/models/crm-v2/crm-v2-base.model.js index 2de1519b34..dac0223249 100644 --- a/app/models/crm-v2/crm-v2-base.model.js +++ b/app/models/crm-v2/crm-v2-base.model.js @@ -9,7 +9,7 @@ const LegacyBaseModel = require('../legacy-base.model.js') class CrmV2BaseModel extends LegacyBaseModel { static get schema () { - return 'crmV2' + return 'crm_v2' } } From b3b3dd177a1b2372c713ef22c25360582ecfd58b Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Fri, 24 Feb 2023 11:16:24 +0000 Subject: [PATCH 14/20] Update create-billing-service --- .../create-billing-invoice.service.js | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/app/services/supplementary-billing/create-billing-invoice.service.js b/app/services/supplementary-billing/create-billing-invoice.service.js index 0e3b5f7935..b8ca61403c 100644 --- a/app/services/supplementary-billing/create-billing-invoice.service.js +++ b/app/services/supplementary-billing/create-billing-invoice.service.js @@ -7,30 +7,38 @@ */ const BillingInvoiceModel = require('../../models/water/billing-invoice.model.js') +const FetchInvoiceAccountService = require('./fetch-invoice-account.service.js') /** - * Create a billing invoice for the provided invoice account and billing batch + * Create the initial billing invoice for the provided charge version, billing period and billing batch prior to + * transactions being sent to the charging module * - * @param {module:InvoiceAccountModel} invoiceAccount An instance of `InvoiceAccountModel` - * @param {Object} cmTransaction Data returned from the Charging Module relating to the transaction + * @param {Object[]} chargeVersion An Object containing the relevant charge version + * @param {Object[]} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period + * @param {string} billingBatchId GUID of the billing batch * * @returns {Object} The newly-created billing invoice record */ -async function go (invoiceAccount, cmTransaction, billingBatchId) { +async function go (chargeVersion, billingPeriod, billingBatchId) { const billingInvoice = await BillingInvoiceModel.query() .insert({ - invoiceAccountId: invoiceAccount.invoiceAccountId, - address: {}, - invoiceAccountNumber: invoiceAccount.invoiceAccountNumber, - netAmount: cmTransaction.netAmount, - isCredit: cmTransaction.netAmount === null ? null : cmTransaction.netAmount < 0, - billingBatchId + invoiceAccountId: chargeVersion.invoiceAccountId, + address: {}, // Have left empty as doesn't appear to be used for SROC + invoiceAccountNumber: await _getInvoiceAccountNumber(chargeVersion.invoiceAccountId), + billingBatchId, + financialYearEnding: billingPeriod.endDate.getFullYear() }) .returning('*') return billingInvoice } +async function _getInvoiceAccountNumber (invoiceAccountId) { + const invoiceAccount = await FetchInvoiceAccountService.go(invoiceAccountId) + + return invoiceAccount.invoiceAccountNumber +} + module.exports = { go } From 48bcb33cef7c9b6fd25e6db400264cc79dc85a40 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Fri, 24 Feb 2023 11:17:02 +0000 Subject: [PATCH 15/20] create unit tests --- .../crm-v2/invoice-account.model.test.js | 34 +++++++++++++ .../create-billing-invoice.service.test.js | 40 +++++++++++++++ .../fetch-invoice-account.service.test.js | 50 +++++++++++++++++++ .../helpers/crm-v2/invoice-account.helper.js | 50 +++++++++++++++++++ .../helpers/water/billing-invoice.helper.js | 8 +++ 5 files changed, 182 insertions(+) create mode 100644 test/models/crm-v2/invoice-account.model.test.js create mode 100644 test/services/supplementary-billing/create-billing-invoice.service.test.js create mode 100644 test/services/supplementary-billing/fetch-invoice-account.service.test.js create mode 100644 test/support/helpers/crm-v2/invoice-account.helper.js diff --git a/test/models/crm-v2/invoice-account.model.test.js b/test/models/crm-v2/invoice-account.model.test.js new file mode 100644 index 0000000000..7d76113ce0 --- /dev/null +++ b/test/models/crm-v2/invoice-account.model.test.js @@ -0,0 +1,34 @@ +'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 DatabaseHelper = require('../../support/helpers/database.helper.js') +const InvoiceAccountHelper = require('../../support/helpers/crm-v2/invoice-account.helper.js') + +// Thing under test +const InvoiceAccountModel = require('../../../app/models/crm-v2/invoice-account.model.js') + +describe('Invoice Account model', () => { + let testRecord + + beforeEach(async () => { + await DatabaseHelper.clean() + + testRecord = await InvoiceAccountHelper.add() + }) + + describe('Basic query', () => { + it('can successfully run a basic query', async () => { + const result = await InvoiceAccountModel.query().findById(testRecord.invoiceAccountId) + + expect(result).to.be.an.instanceOf(InvoiceAccountModel) + expect(result.invoiceAccountId).to.equal(testRecord.invoiceAccountId) + }) + }) +}) diff --git a/test/services/supplementary-billing/create-billing-invoice.service.test.js b/test/services/supplementary-billing/create-billing-invoice.service.test.js new file mode 100644 index 0000000000..56415e02ef --- /dev/null +++ b/test/services/supplementary-billing/create-billing-invoice.service.test.js @@ -0,0 +1,40 @@ +'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 BillingInvoiceModel = require('../../../app/models/water/billing-invoice.model.js') +const DatabaseHelper = require('../../support/helpers/database.helper.js') +const InvoiceAccountHelper = require('../../support/helpers/crm-v2/invoice-account.helper.js') + +// Thing under test +const CreateBillingInvoiceService = require('../../../app/services/supplementary-billing/create-billing-invoice.service.js') + +describe('Create Billing Invoice service', () => { + const billingBatchId = '95177485-bfe7-48ed-b2f0-dba5a5084b45' + const billingPeriod = { startDate: new Date('2022-04-01'), endDate: new Date('2023-03-31') } + + beforeEach(async () => { + await DatabaseHelper.clean() + }) + + it('returns the new billing invoice instance containing the correct data', async () => { + const invoiceAccount = await InvoiceAccountHelper.add({ invoiceAccountNumber: 'TEST12345A' }) + const chargeVersion = { invoiceAccountId: invoiceAccount.invoiceAccountId } + + const result = await CreateBillingInvoiceService.go(chargeVersion, billingPeriod, billingBatchId) + + expect(result).to.be.an.instanceOf(BillingInvoiceModel) + + expect(result.invoiceAccountId).to.equal(invoiceAccount.invoiceAccountId) + expect(result.address).to.equal({}) + expect(result.invoiceAccountNumber).to.equal(invoiceAccount.invoiceAccountNumber) + expect(result.billingBatchId).to.equal(billingBatchId) + expect(result.financialYearEnding).to.equal(2023) + }) +}) diff --git a/test/services/supplementary-billing/fetch-invoice-account.service.test.js b/test/services/supplementary-billing/fetch-invoice-account.service.test.js new file mode 100644 index 0000000000..392aea64a4 --- /dev/null +++ b/test/services/supplementary-billing/fetch-invoice-account.service.test.js @@ -0,0 +1,50 @@ +'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 DatabaseHelper = require('../../support/helpers/database.helper.js') +const InvoiceAccountHelper = require('../../support/helpers/crm-v2/invoice-account.helper.js') + +// Thing under test +const FetchInvoiceAccountService = require('../../../app/services/supplementary-billing/fetch-invoice-account.service.js') + +describe('Fetch Invoice Account service', () => { + let testInvoiceAccount + + beforeEach(async () => { + await DatabaseHelper.clean() + }) + + describe('when there is an invoice account with a matching invoice account id', () => { + beforeEach(async () => { + testInvoiceAccount = await InvoiceAccountHelper.add() + }) + + it('returns results', async () => { + const result = await FetchInvoiceAccountService.go(testInvoiceAccount.invoiceAccountId) + + expect(result.invoiceAccountId).to.equal(testInvoiceAccount.invoiceAccountId) + }) + }) + + describe('when there is no invoice account with a matching invoice account id', () => { + beforeEach(async () => { + InvoiceAccountHelper.add() + }) + + it('returns no results', async () => { + // A random uuid that will not exist in the invoice account table + const invoiceAccountId = 'f0b835d6-129a-4d90-a3b6-c59bc28d661d' + + const result = await FetchInvoiceAccountService.go(invoiceAccountId) + + expect(result).to.be.undefined() + }) + }) +}) diff --git a/test/support/helpers/crm-v2/invoice-account.helper.js b/test/support/helpers/crm-v2/invoice-account.helper.js new file mode 100644 index 0000000000..298035d4b0 --- /dev/null +++ b/test/support/helpers/crm-v2/invoice-account.helper.js @@ -0,0 +1,50 @@ +'use strict' + +/** + * @module InvoiceAccountHelper + */ + +const InvoiceAccountModel = require('../../../../app/models/crm-v2/invoice-account.model.js') + +/** + * Add a new invoice account + * + * If no `data` is provided, default values will be used. These are + * + * - `invoiceAccountNumber` - T12345678A + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + * + * @returns {module:InvoiceAccountModel} The instance of the newly created record + */ +function add (data = {}) { + const insertData = defaults(data) + + return InvoiceAccountModel.query() + .insert({ ...insertData }) + .returning('*') +} + +/** + * Returns the defaults used when creating a new region + * + * It will override or append to them any data provided. Mainly used by the `add()` method, we make it available + * for use in tests to avoid having to duplicate values. + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + */ +function defaults (data = {}) { + const defaults = { + invoiceAccountNumber: 'T12345678A' + } + + return { + ...defaults, + ...data + } +} + +module.exports = { + add, + defaults +} diff --git a/test/support/helpers/water/billing-invoice.helper.js b/test/support/helpers/water/billing-invoice.helper.js index dfe2b004f1..3c630f7334 100644 --- a/test/support/helpers/water/billing-invoice.helper.js +++ b/test/support/helpers/water/billing-invoice.helper.js @@ -17,6 +17,10 @@ const BillingBatchHelper = require('./billing-batch.helper.js') * * If no `data` is provided, default values will be used. These are * + * - `invoiceAccountId` - 396ee68f-d665-4770-b0ad-d70a007f9bd5 + * - `address` - {} + * - `invoiceAccountNumber` - T12345678A + * - `billingBatchId` - 1d9e3142-8893-4dff-9043-f4b3b34e230d * - `financialYearEnding` - 2023 * * See `BillingBatchHelper` for the billing batch defaults @@ -61,6 +65,10 @@ async function _billingBatchId (providedBillingBatch) { */ function defaults (data = {}) { const defaults = { + invoiceAccountId: '396ee68f-d665-4770-b0ad-d70a007f9bd5', + address: {}, + invoiceAccountNumber: 'T12345678A', + billingBatchId: '1d9e3142-8893-4dff-9043-f4b3b34e230d', financialYearEnding: 2023 } From a24d80d8c2b91089f4556b1d0029e3e52ad430d4 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Fri, 24 Feb 2023 11:38:08 +0000 Subject: [PATCH 16/20] Added comment to crm-v2 base model --- app/models/crm-v2/crm-v2-base.model.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/models/crm-v2/crm-v2-base.model.js b/app/models/crm-v2/crm-v2-base.model.js index dac0223249..7749edf7ff 100644 --- a/app/models/crm-v2/crm-v2-base.model.js +++ b/app/models/crm-v2/crm-v2-base.model.js @@ -7,6 +7,15 @@ const LegacyBaseModel = require('../legacy-base.model.js') +/** + * An issue with the way the standard implementation of the SnakeCase conversion was incorrectly handling the schema + * name of `crmV2` by converting it to `crm_v_2` has meant that a custom SnakeCase mapper has been created so that + * formatting is not applied to the `crm_v2` schema name. + * + * See `app/lib/legacy-db-snake-case-mappers.lib.js` or https://github.com/DEFRA/water-abstraction-system/pull/131 for + * more details. + */ + class CrmV2BaseModel extends LegacyBaseModel { static get schema () { return 'crm_v2' From 74c653ad2e54865792cf775f3049aaa58a61187f Mon Sep 17 00:00:00 2001 From: Jason Claxton <30830544+Jozzey@users.noreply.github.com> Date: Fri, 24 Feb 2023 12:34:49 +0000 Subject: [PATCH 17/20] Update query method Co-authored-by: Alan Cruikshanks --- .../supplementary-billing/fetch-invoice-account.service.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/services/supplementary-billing/fetch-invoice-account.service.js b/app/services/supplementary-billing/fetch-invoice-account.service.js index 9390dbbcfa..f6538ff3f7 100644 --- a/app/services/supplementary-billing/fetch-invoice-account.service.js +++ b/app/services/supplementary-billing/fetch-invoice-account.service.js @@ -21,9 +21,7 @@ async function go (invoiceAccountId) { } async function _fetch (invoiceAccountId) { - const result = await InvoiceAccountModel.query() - .where('invoiceAccountId', invoiceAccountId) - .first() + const result = await InvoiceAccountModel.query().findById(invoiceAccountId) return result } From 9367c56f466a26f7196190609ebd2490f4d9978e Mon Sep 17 00:00:00 2001 From: Jason Claxton <30830544+Jozzey@users.noreply.github.com> Date: Fri, 24 Feb 2023 12:36:27 +0000 Subject: [PATCH 18/20] Update documentation Co-authored-by: Alan Cruikshanks --- .../supplementary-billing/create-billing-invoice.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/supplementary-billing/create-billing-invoice.service.js b/app/services/supplementary-billing/create-billing-invoice.service.js index b8ca61403c..a09112f0c6 100644 --- a/app/services/supplementary-billing/create-billing-invoice.service.js +++ b/app/services/supplementary-billing/create-billing-invoice.service.js @@ -13,8 +13,8 @@ const FetchInvoiceAccountService = require('./fetch-invoice-account.service.js') * Create the initial billing invoice for the provided charge version, billing period and billing batch prior to * transactions being sent to the charging module * - * @param {Object[]} chargeVersion An Object containing the relevant charge version - * @param {Object[]} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period + * @param {Object} chargeVersion An Object containing the relevant charge version + * @param {Object} billingPeriod Object that has a `startDate` and `endDate` that defines the billing period * @param {string} billingBatchId GUID of the billing batch * * @returns {Object} The newly-created billing invoice record From a7e5ad1997d3775ddecffb541e8f293b218d84f5 Mon Sep 17 00:00:00 2001 From: Jason Claxton <30830544+Jozzey@users.noreply.github.com> Date: Fri, 24 Feb 2023 12:37:03 +0000 Subject: [PATCH 19/20] Update comment Co-authored-by: Alan Cruikshanks --- .../supplementary-billing/create-billing-invoice.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/supplementary-billing/create-billing-invoice.service.js b/app/services/supplementary-billing/create-billing-invoice.service.js index a09112f0c6..c11e6eef81 100644 --- a/app/services/supplementary-billing/create-billing-invoice.service.js +++ b/app/services/supplementary-billing/create-billing-invoice.service.js @@ -23,7 +23,7 @@ async function go (chargeVersion, billingPeriod, billingBatchId) { const billingInvoice = await BillingInvoiceModel.query() .insert({ invoiceAccountId: chargeVersion.invoiceAccountId, - address: {}, // Have left empty as doesn't appear to be used for SROC + address: {}, // Address is set to an empty object for SROC billing invoices invoiceAccountNumber: await _getInvoiceAccountNumber(chargeVersion.invoiceAccountId), billingBatchId, financialYearEnding: billingPeriod.endDate.getFullYear() From 99b4cecdb7eac7b703425fbab4fb04a07d93c840 Mon Sep 17 00:00:00 2001 From: Jason Claxton Date: Fri, 24 Feb 2023 12:48:03 +0000 Subject: [PATCH 20/20] Update test as per Alan's PR comment --- .../create-billing-invoice.service.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/services/supplementary-billing/create-billing-invoice.service.test.js b/test/services/supplementary-billing/create-billing-invoice.service.test.js index 56415e02ef..b64e4056ed 100644 --- a/test/services/supplementary-billing/create-billing-invoice.service.test.js +++ b/test/services/supplementary-billing/create-billing-invoice.service.test.js @@ -19,14 +19,17 @@ describe('Create Billing Invoice service', () => { const billingBatchId = '95177485-bfe7-48ed-b2f0-dba5a5084b45' const billingPeriod = { startDate: new Date('2022-04-01'), endDate: new Date('2023-03-31') } + let invoiceAccount + let chargeVersion + beforeEach(async () => { await DatabaseHelper.clean() + + invoiceAccount = await InvoiceAccountHelper.add({ invoiceAccountNumber: 'TEST12345A' }) + chargeVersion = { invoiceAccountId: invoiceAccount.invoiceAccountId } }) it('returns the new billing invoice instance containing the correct data', async () => { - const invoiceAccount = await InvoiceAccountHelper.add({ invoiceAccountNumber: 'TEST12345A' }) - const chargeVersion = { invoiceAccountId: invoiceAccount.invoiceAccountId } - const result = await CreateBillingInvoiceService.go(chargeVersion, billingPeriod, billingBatchId) expect(result).to.be.an.instanceOf(BillingInvoiceModel)