diff --git a/app/models/water/charge-purpose.model.js b/app/models/water/charge-purpose.model.js index fdc6de58fb..9675266e42 100644 --- a/app/models/water/charge-purpose.model.js +++ b/app/models/water/charge-purpose.model.js @@ -34,6 +34,14 @@ class ChargePurposeModel extends WaterBaseModel { from: 'chargePurposes.chargeElementId', to: 'chargeElements.chargeElementId' } + }, + purposesUse: { + relation: Model.BelongsToOneRelation, + modelClass: 'purposes-use.model', + join: { + from: 'chargePurposes.purposeUseId', + to: 'purposesUses.purposeUseId' + } } } } diff --git a/app/models/water/purposes-use.model.js b/app/models/water/purposes-use.model.js new file mode 100644 index 0000000000..b327150f69 --- /dev/null +++ b/app/models/water/purposes-use.model.js @@ -0,0 +1,42 @@ +'use strict' + +/** + * Model for purposesUses + * @module PurposesUseModel + */ + +const { Model } = require('objection') + +const WaterBaseModel = require('./water-base.model.js') + +class PurposesUseModel extends WaterBaseModel { + static get tableName () { + return 'purposesUses' + } + + static get idColumn () { + return 'purposeUseId' + } + + static get translations () { + return [ + { database: 'dateCreated', model: 'createdAt' }, + { database: 'dateUpdated', model: 'updatedAt' } + ] + } + + static get relationMappings () { + return { + chargePurpose: { + relation: Model.BelongsToOneRelation, + modelClass: 'charge-purpose.model', + join: { + from: 'purposesUses.purposeUseId', + to: 'chargePurposes.purposeUseId' + } + } + } + } +} + +module.exports = PurposesUseModel diff --git a/db/migrations/20230802134043_create_returns_schema.js b/db/migrations/20230802134043_create-returns-schema.js similarity index 100% rename from db/migrations/20230802134043_create_returns_schema.js rename to db/migrations/20230802134043_create-returns-schema.js diff --git a/db/migrations/20230802134153_create_returns_returns.js b/db/migrations/20230802134153_create-returns-returns.js similarity index 56% rename from db/migrations/20230802134153_create_returns_returns.js rename to db/migrations/20230802134153_create-returns-returns.js index d8a2692e84..76e62c506e 100644 --- a/db/migrations/20230802134153_create_returns_returns.js +++ b/db/migrations/20230802134153_create-returns-returns.js @@ -11,21 +11,21 @@ exports.up = function (knex) { table.string('return_id').primary() // Data - table.string('regime') - table.string('licence_type') - table.string('licence_ref') - table.date('start_date') - table.date('end_date') - table.string('returns_frequency') - table.string('status') + table.string('regime').notNullable() + table.string('licence_type').notNullable() + table.string('licence_ref').notNullable() + table.date('start_date').notNullable() + table.date('end_date').notNullable() + table.string('returns_frequency').notNullable() + table.string('status').notNullable() table.string('source') table.jsonb('metadata') table.date('received_date') - table.string('return_requirement') - table.date('due_date') - table.boolean('under_query') + table.string('return_requirement').notNullable() + table.date('due_date').notNullable() + table.boolean('under_query').notNullable().defaultTo(false) table.string('under_query_comment') - table.boolean('is_test') + table.boolean('is_test').notNullable().defaultTo(false) table.uuid('return_cycle_id') // Legacy timestamps diff --git a/db/migrations/20230803160405_create-water-purposes-uses.js b/db/migrations/20230803160405_create-water-purposes-uses.js new file mode 100644 index 0000000000..b43ed851ac --- /dev/null +++ b/db/migrations/20230803160405_create-water-purposes-uses.js @@ -0,0 +1,31 @@ +'use strict' + +const tableName = 'purposes_uses' + +exports.up = function (knex) { + return knex + .schema + .withSchema('water') + .createTable(tableName, (table) => { + // Primary Key + table.uuid('purpose_use_id').primary().defaultTo(knex.raw('gen_random_uuid()')) + + // Data + table.string('legacy_id').notNullable().unique() + table.string('description').notNullable() + table.string('loss_factor').notNullable() + table.boolean('is_two_part_tariff').notNullable().defaultTo(false) + table.boolean('is_test').notNullable().defaultTo(false) + + // 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('water') + .dropTableIfExists(tableName) +} diff --git a/test/models/water/charge-purpose.model.test.js b/test/models/water/charge-purpose.model.test.js index 168e609831..d86e6a3246 100644 --- a/test/models/water/charge-purpose.model.test.js +++ b/test/models/water/charge-purpose.model.test.js @@ -12,6 +12,8 @@ const ChargeElementHelper = require('../../support/helpers/water/charge-element. const ChargeElementModel = require('../../../app/models/water/charge-element.model.js') const ChargePurposeHelper = require('../../support/helpers/water/charge-purpose.helper.js') const DatabaseHelper = require('../../support/helpers/database.helper.js') +const PurposesUseModel = require('../../../app/models/water/purposes-use.model.js') +const PurposesUseHelper = require('../../support/helpers/water/purposes-use.helper.js') // Thing under test const ChargePurposeModel = require('../../../app/models/water/charge-purpose.model.js') @@ -64,5 +66,35 @@ describe('Charge Purpose model', () => { expect(result.chargeElement).to.equal(testChargeElement) }) }) + + describe('when linking to purposes use', () => { + let testPurposesUse + + beforeEach(async () => { + testPurposesUse = await PurposesUseHelper.add() + + const { purposeUseId } = testPurposesUse + testRecord = await ChargePurposeHelper.add({ purposeUseId }) + }) + + it('can successfully run a related query', async () => { + const query = await ChargePurposeModel.query() + .innerJoinRelated('purposesUse') + + expect(query).to.exist() + }) + + it('can eager load the purposes use', async () => { + const result = await ChargePurposeModel.query() + .findById(testRecord.chargePurposeId) + .withGraphFetched('purposesUse') + + expect(result).to.be.instanceOf(ChargePurposeModel) + expect(result.chargePurposeId).to.equal(testRecord.chargePurposeId) + + expect(result.purposesUse).to.be.an.instanceOf(PurposesUseModel) + expect(result.purposesUse).to.equal(testPurposesUse) + }) + }) }) }) diff --git a/test/models/water/purposes-use.model.test.js b/test/models/water/purposes-use.model.test.js new file mode 100644 index 0000000000..d345d79645 --- /dev/null +++ b/test/models/water/purposes-use.model.test.js @@ -0,0 +1,67 @@ +'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 ChargePurposeHelper = require('../../support/helpers/water/charge-purpose.helper.js') +const ChargePurposeModel = require('../../../app/models/water/charge-purpose.model.js') +const DatabaseHelper = require('../../support/helpers/database.helper.js') +const PurposesUseHelper = require('../../support/helpers/water/purposes-use.helper.js') + +// Thing under test +const PurposesUseModel = require('../../../app/models/water/purposes-use.model.js') + +describe('Purposes Use model', () => { + let testRecord + + beforeEach(async () => { + await DatabaseHelper.clean() + + testRecord = await PurposesUseHelper.add() + }) + + describe('Basic query', () => { + it('can successfully run a basic query', async () => { + const result = await PurposesUseModel.query().findById(testRecord.purposeUseId) + + expect(result).to.be.an.instanceOf(PurposesUseModel) + expect(result.purposeUseId).to.equal(testRecord.purposeUseId) + }) + }) + + describe('Relationships', () => { + describe('when linking to charge purpose', () => { + let testChargePurpose + + beforeEach(async () => { + const { purposeUseId } = testRecord + + testChargePurpose = await ChargePurposeHelper.add({ purposeUseId }) + }) + + it('can successfully run a related query', async () => { + const query = await PurposesUseModel.query() + .innerJoinRelated('chargePurpose') + + expect(query).to.exist() + }) + + it('can eager load the charge purpose', async () => { + const result = await PurposesUseModel.query() + .findById(testRecord.purposeUseId) + .withGraphFetched('chargePurpose') + + expect(result).to.be.instanceOf(PurposesUseModel) + expect(result.purposeUseId).to.equal(testRecord.purposeUseId) + + expect(result.chargePurpose).to.be.an.instanceOf(ChargePurposeModel) + expect(result.chargePurpose).to.equal(testChargePurpose) + }) + }) + }) +}) diff --git a/test/support/helpers/returns/return.helper.js b/test/support/helpers/returns/return.helper.js index 245199f3e8..807eed9b67 100644 --- a/test/support/helpers/returns/return.helper.js +++ b/test/support/helpers/returns/return.helper.js @@ -50,6 +50,7 @@ function defaults (data = {}) { returnId: 'v1:1:9/99/99/99/9999:10021668:2022-04-01:2023-03-31', regime: 'water', licenceType: 'abstraction', + licenceRef: '9/99/99/99/9999', startDate: '2022-04-01', endDate: '2023-03-31', returnsFrequency: 'month', diff --git a/test/support/helpers/water/purposes-use.helper.js b/test/support/helpers/water/purposes-use.helper.js new file mode 100644 index 0000000000..1ce20200c5 --- /dev/null +++ b/test/support/helpers/water/purposes-use.helper.js @@ -0,0 +1,56 @@ +'use strict' + +/** + * @module PurposesUseHelper + */ + +const PurposesUseModel = require('../../../../app/models/water/purposes-use.model.js') + +/** + * Add a new purposes use + * + * If no `data` is provided, default values will be used. These are + * + * - `legacyId` - 420 + * - `description` - Spray Irrigation - Storage + * - `lossFactor` - high + * - `isTwoPartTariff` - true + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + * + * @returns {module:PurposesUseModel} The instance of the newly created record + */ +function add (data = {}) { + const insertData = defaults(data) + + return PurposesUseModel.query() + .insert({ ...insertData }) + .returning('*') +} + +/** + * Returns the defaults used when creating a new purposes use + * + * 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 = { + legacyId: '420', + description: 'Spray Irrigation - Storage', + lossFactor: 'high', + isTwoPartTariff: true + } + + return { + ...defaults, + ...data + } +} + +module.exports = { + add, + defaults +}