From 7917151e442ac0c2920037b0a8bf607da9dadf89 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 20 Feb 2024 21:42:33 +0000 Subject: [PATCH 1/3] Add relationship - billing acc. <-> chg. version 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 could simplify the implementation and improve performance if we extracted the billing account details at the same time as the charge versions to be billed. When we implemented the SROC supplementary billing engine we were directly working with the legacy schemas and tables. This meant we couldn't create relationships in models that sat in different schemas. But thanks to [Create water schema views](https://github.com/DEFRA/water-abstraction-system/pull/551) and [Create crm_v2 schema views](https://github.com/DEFRA/water-abstraction-system/pull/556) they are hidden away from us. We can now work as if the legacy schemas are a single schema. So, this change updates the `ChargeVersionModel` and `BillingAccountModel` to add a relationship between them which we can then exploit with our [Objection.js queries](https://vincit.github.io/objection.js/). From 21e172967e822c31937285b58e62a430f0ba24dd Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 20 Feb 2024 21:55:42 +0000 Subject: [PATCH 2/3] Add relationship to BillingAccountModel --- app/models/billing-account.model.js | 8 +++ test/models/billing-account.model.test.js | 86 ++++++++++++++++------- 2 files changed, 70 insertions(+), 24 deletions(-) diff --git a/app/models/billing-account.model.js b/app/models/billing-account.model.js index fb55f93629..cebcde6e21 100644 --- a/app/models/billing-account.model.js +++ b/app/models/billing-account.model.js @@ -24,6 +24,14 @@ class BillingAccountModel extends BaseModel { to: 'billingAccountAddresses.billingAccountId' } }, + chargeVersions: { + relation: Model.HasManyRelation, + modelClass: 'charge-version.model', + join: { + from: 'billingAccounts.id', + to: 'chargeVersions.billingAccountId' + } + }, company: { relation: Model.BelongsToOneRelation, modelClass: 'company.model', diff --git a/test/models/billing-account.model.test.js b/test/models/billing-account.model.test.js index a3fb7b548b..1298b441e1 100644 --- a/test/models/billing-account.model.test.js +++ b/test/models/billing-account.model.test.js @@ -11,6 +11,8 @@ const { expect } = Code const BillingAccountAddressHelper = require('../support/helpers/billing-account-address.helper.js') const BillingAccountAddressModel = require('../../app/models/billing-account-address.model.js') const BillingAccountHelper = require('../support/helpers/billing-account.helper.js') +const ChargeVersionHelper = require('../support/helpers/charge-version.helper.js') +const ChargeVersionModel = require('../../app/models/charge-version.model.js') const CompanyHelper = require('../support/helpers/company.helper.js') const CompanyModel = require('../../app/models/company.model.js') const DatabaseHelper = require('../support/helpers/database.helper.js') @@ -39,70 +41,106 @@ describe('Billing Account model', () => { }) describe('Relationships', () => { - describe('when linking to company', () => { - let testCompany + describe('when linking to billing account addresses', () => { + let testBillingAccountAddresses beforeEach(async () => { - testCompany = await CompanyHelper.add() - testRecord = await BillingAccountHelper.add({ companyId: testCompany.id }) + testRecord = await BillingAccountHelper.add() + const { id: billingAccountId } = testRecord + + testBillingAccountAddresses = [] + for (let i = 0; i < 2; i++) { + // NOTE: A constraint in the invoice_account_addresses table means you cannot have 2 records with the same + // billingAccountId and start date + const startDate = i === 0 ? new Date(2023, 8, 4) : new Date(2023, 8, 3) + const billingAccountAddress = await BillingAccountAddressHelper.add({ startDate, billingAccountId }) + testBillingAccountAddresses.push(billingAccountAddress) + } }) it('can successfully run a related query', async () => { const query = await BillingAccountModel.query() - .innerJoinRelated('company') + .innerJoinRelated('billingAccountAddresses') expect(query).to.exist() }) - it('can eager load the company', async () => { + it('can eager load the billing account addresses', async () => { const result = await BillingAccountModel.query() .findById(testRecord.id) - .withGraphFetched('company') + .withGraphFetched('billingAccountAddresses') expect(result).to.be.instanceOf(BillingAccountModel) expect(result.id).to.equal(testRecord.id) - expect(result.company).to.be.an.instanceOf(CompanyModel) - expect(result.company).to.equal(testCompany) + expect(result.billingAccountAddresses).to.be.an.array() + expect(result.billingAccountAddresses[0]).to.be.an.instanceOf(BillingAccountAddressModel) + expect(result.billingAccountAddresses).to.include(testBillingAccountAddresses[0]) + expect(result.billingAccountAddresses).to.include(testBillingAccountAddresses[1]) }) }) - describe('when linking to billing account addresses', () => { - let testBillingAccountAddresses + describe('when linking to charge versions', () => { + let testChargeVersions beforeEach(async () => { testRecord = await BillingAccountHelper.add() const { id: billingAccountId } = testRecord - testBillingAccountAddresses = [] + testChargeVersions = [] for (let i = 0; i < 2; i++) { - // NOTE: A constraint in the invoice_account_addresses table means you cannot have 2 records with the same - // billingAccountId and start date - const startDate = i === 0 ? new Date(2023, 8, 4) : new Date(2023, 8, 3) - const billingAccountAddress = await BillingAccountAddressHelper.add({ startDate, billingAccountId }) - testBillingAccountAddresses.push(billingAccountAddress) + const chargeVersion = await ChargeVersionHelper.add({ billingAccountId }) + testChargeVersions.push(chargeVersion) } }) it('can successfully run a related query', async () => { const query = await BillingAccountModel.query() - .innerJoinRelated('billingAccountAddresses') + .innerJoinRelated('chargeVersions') expect(query).to.exist() }) - it('can eager load the billing account addresses', async () => { + it('can eager load the charge versions', async () => { const result = await BillingAccountModel.query() .findById(testRecord.id) - .withGraphFetched('billingAccountAddresses') + .withGraphFetched('chargeVersions') expect(result).to.be.instanceOf(BillingAccountModel) expect(result.id).to.equal(testRecord.id) - expect(result.billingAccountAddresses).to.be.an.array() - expect(result.billingAccountAddresses[0]).to.be.an.instanceOf(BillingAccountAddressModel) - expect(result.billingAccountAddresses).to.include(testBillingAccountAddresses[0]) - expect(result.billingAccountAddresses).to.include(testBillingAccountAddresses[1]) + expect(result.chargeVersions).to.be.an.array() + expect(result.chargeVersions[0]).to.be.an.instanceOf(ChargeVersionModel) + expect(result.chargeVersions).to.include(testChargeVersions[0]) + expect(result.chargeVersions).to.include(testChargeVersions[1]) + }) + }) + + describe('when linking to company', () => { + let testCompany + + beforeEach(async () => { + testCompany = await CompanyHelper.add() + testRecord = await BillingAccountHelper.add({ companyId: testCompany.id }) + }) + + it('can successfully run a related query', async () => { + const query = await BillingAccountModel.query() + .innerJoinRelated('company') + + expect(query).to.exist() + }) + + it('can eager load the company', async () => { + const result = await BillingAccountModel.query() + .findById(testRecord.id) + .withGraphFetched('company') + + expect(result).to.be.instanceOf(BillingAccountModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.company).to.be.an.instanceOf(CompanyModel) + expect(result.company).to.equal(testCompany) }) }) }) From e785ed64f27f51261848389f32817fdf36c0245c Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Tue, 20 Feb 2024 22:28:19 +0000 Subject: [PATCH 3/3] Add relationship to ChargeVersionModel --- app/models/charge-version.model.js | 8 ++++++ test/models/charge-version.model.test.js | 32 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/app/models/charge-version.model.js b/app/models/charge-version.model.js index 72613fdcc8..bb8df7f515 100644 --- a/app/models/charge-version.model.js +++ b/app/models/charge-version.model.js @@ -16,6 +16,14 @@ class ChargeVersionModel extends BaseModel { static get relationMappings () { return { + billingAccount: { + relation: Model.BelongsToOneRelation, + modelClass: 'billing-account.model', + join: { + from: 'chargeVersions.billingAccountId', + to: 'billingAccounts.id' + } + }, licence: { relation: Model.BelongsToOneRelation, modelClass: 'licence.model', diff --git a/test/models/charge-version.model.test.js b/test/models/charge-version.model.test.js index 5b91e03f56..49df96a5a2 100644 --- a/test/models/charge-version.model.test.js +++ b/test/models/charge-version.model.test.js @@ -8,6 +8,8 @@ const { describe, it, beforeEach } = exports.lab = Lab.script() const { expect } = Code // Test helpers +const BillingAccountHelper = require('../support/helpers/billing-account.helper.js') +const BillingAccountModel = require('../../app/models/billing-account.model.js') const ChangeReasonHelper = require('../support/helpers/change-reason.helper.js') const ChangeReasonModel = require('../../app/models/change-reason.model.js') const ChargeReferenceHelper = require('../support/helpers/charge-reference.helper.js') @@ -39,6 +41,36 @@ describe('Charge Version model', () => { }) describe('Relationships', () => { + describe('when linking to billing account', () => { + let testBillingAccount + + beforeEach(async () => { + testBillingAccount = await BillingAccountHelper.add() + + const { id: billingAccountId } = testBillingAccount + testRecord = await ChargeVersionHelper.add({ billingAccountId }) + }) + + it('can successfully run a related query', async () => { + const query = await ChargeVersionModel.query() + .innerJoinRelated('billingAccount') + + expect(query).to.exist() + }) + + it('can eager load the billing account', async () => { + const result = await ChargeVersionModel.query() + .findById(testRecord.id) + .withGraphFetched('billingAccount') + + expect(result).to.be.instanceOf(ChargeVersionModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.billingAccount).to.be.an.instanceOf(BillingAccountModel) + expect(result.billingAccount).to.equal(testBillingAccount) + }) + }) + describe('when linking to licence', () => { let testLicence