Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SROC Supplementary Billing Invoice Service #119

Merged
merged 23 commits into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions app/models/crm-v2/crm-v2-base.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

/**
* Base class for all models based on the legacy 'crm_v2' schema
* @module CrmV2BaseModel
*/

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'
}
}

module.exports = CrmV2BaseModel
27 changes: 27 additions & 0 deletions app/models/crm-v2/invoice-account.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict'

/**
* Model for invoiceAccounts
* @module InvoiceAccountModel
*/

const CrmV2BaseModel = require('./crm-v2-base.model.js')

class InvoiceAccountModel extends CrmV2BaseModel {
static get tableName () {
return 'invoiceAccounts'
}

static get idColumn () {
return 'invoiceAccountId'
}

static get translations () {
return [
{ database: 'dateCreated', model: 'createdAt' },
{ database: 'dateUpdated', model: 'updatedAt' }
]
}
}

module.exports = InvoiceAccountModel
3 changes: 2 additions & 1 deletion app/models/legacy-base.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ 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,
licenceId: licence.licenceId
})
.returning('*')

return event
return billingInvoiceLicence
}

module.exports = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict'

/**
* Creates a billing invoice record
*
* @module CreateBillingInvoiceService
*/

const BillingInvoiceModel = require('../../models/water/billing-invoice.model.js')
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 {string} billingBatchId GUID of the billing batch
*
* @returns {Object} The newly-created billing invoice record
*/
async function go (chargeVersion, billingPeriod, billingBatchId) {
const billingInvoice = await BillingInvoiceModel.query()
.insert({
invoiceAccountId: chargeVersion.invoiceAccountId,
address: {}, // Address is set to an empty object for SROC billing invoices
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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'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().findById(invoiceAccountId)

return result
}

module.exports = {
go
}
13 changes: 13 additions & 0 deletions db/migrations/20230221135143_create-crm-v2-schema.js
Original file line number Diff line number Diff line change
@@ -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";
`)
}
32 changes: 32 additions & 0 deletions db/migrations/20230221140243_create-crm-v2-invoice-accounts.js
Original file line number Diff line number Diff line change
@@ -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)
}
51 changes: 51 additions & 0 deletions db/migrations/20230221161454_alter-water-billing-invoices.js
Original file line number Diff line number Diff line change
@@ -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'
)
})
}
23 changes: 23 additions & 0 deletions db/migrations/20230223124044_alter-water-charge-versions.js
Original file line number Diff line number Diff line change
@@ -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'
)
})
}
34 changes: 34 additions & 0 deletions test/models/crm-v2/invoice-account.model.test.js
Original file line number Diff line number Diff line change
@@ -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)
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'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') }

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 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)
})
})
Loading