diff --git a/app/models/licence.model.js b/app/models/licence.model.js index a83110a4e6..f746ef607f 100644 --- a/app/models/licence.model.js +++ b/app/models/licence.model.js @@ -72,6 +72,14 @@ class LicenceModel extends BaseModel { to: 'returnLogs.licenceRef' } }, + returnVersions: { + relation: Model.HasManyRelation, + modelClass: 'return-version.model', + join: { + from: 'licences.id', + to: 'returnVersions.licenceId' + } + }, reviewLicences: { relation: Model.HasManyRelation, modelClass: 'review-licence.model', diff --git a/app/models/purpose.model.js b/app/models/purpose.model.js index 0d4a9d02b5..de976e60f5 100644 --- a/app/models/purpose.model.js +++ b/app/models/purpose.model.js @@ -39,6 +39,14 @@ class PurposeModel extends BaseModel { from: 'purposes.id', to: 'licenceVersionPurposes.purposeId' } + }, + returnRequirementPurposes: { + relation: Model.HasManyRelation, + modelClass: 'return-requirement-purpose.model', + join: { + from: 'purposes.id', + to: 'returnRequirementPurposes.purposeId' + } } } } diff --git a/app/models/return-requirement-point.model.js b/app/models/return-requirement-point.model.js new file mode 100644 index 0000000000..29080627ad --- /dev/null +++ b/app/models/return-requirement-point.model.js @@ -0,0 +1,31 @@ +'use strict' + +/** + * Model for return_requirement_points (water.return_requirement_points) + * @module ReturnRequirementPointModel + */ + +const { Model } = require('objection') + +const BaseModel = require('./base.model.js') + +class ReturnRequirementPointModel extends BaseModel { + static get tableName () { + return 'returnRequirementPoints' + } + + static get relationMappings () { + return { + returnRequirement: { + relation: Model.BelongsToOneRelation, + modelClass: 'return-requirement.model', + join: { + from: 'returnRequirementPoints.returnRequirementId', + to: 'returnRequirements.id' + } + } + } + } +} + +module.exports = ReturnRequirementPointModel diff --git a/app/models/return-requirement-purpose.model.js b/app/models/return-requirement-purpose.model.js new file mode 100644 index 0000000000..c634519e9d --- /dev/null +++ b/app/models/return-requirement-purpose.model.js @@ -0,0 +1,39 @@ +'use strict' + +/** + * Model for return_requirement_purposes (water.return_requirement_purposes) + * @module ReturnRequirementPurposeModel + */ + +const { Model } = require('objection') + +const BaseModel = require('./base.model.js') + +class ReturnRequirementPurposeModel extends BaseModel { + static get tableName () { + return 'returnRequirementPurposes' + } + + static get relationMappings () { + return { + purpose: { + relation: Model.BelongsToOneRelation, + modelClass: 'purpose.model', + join: { + from: 'returnRequirementPurposes.purposeId', + to: 'purposes.id' + } + }, + returnRequirement: { + relation: Model.BelongsToOneRelation, + modelClass: 'return-requirement.model', + join: { + from: 'returnRequirementPurposes.returnRequirementId', + to: 'returnRequirements.id' + } + } + } + } +} + +module.exports = ReturnRequirementPurposeModel diff --git a/app/models/return-requirement.model.js b/app/models/return-requirement.model.js new file mode 100644 index 0000000000..507cc7143d --- /dev/null +++ b/app/models/return-requirement.model.js @@ -0,0 +1,47 @@ +'use strict' + +/** + * Model for return_requirements (water.return_requirements) + * @module ReturnRequirementModel + */ + +const { Model } = require('objection') + +const BaseModel = require('./base.model.js') + +class ReturnRequirementModel extends BaseModel { + static get tableName () { + return 'returnRequirements' + } + + static get relationMappings () { + return { + returnRequirementPoints: { + relation: Model.HasManyRelation, + modelClass: 'return-requirement-point.model', + join: { + from: 'returnRequirements.id', + to: 'returnRequirementPoints.returnRequirementId' + } + }, + returnRequirementPurposes: { + relation: Model.HasManyRelation, + modelClass: 'return-requirement-purpose.model', + join: { + from: 'returnRequirements.id', + to: 'returnRequirementPurposes.returnRequirementId' + } + }, + returnVersion: { + relation: Model.BelongsToOneRelation, + modelClass: 'return-version.model', + join: { + from: 'returnRequirements.returnVersionId', + to: 'returnVersions.id' + } + } + } + } +} + +module.exports = ReturnRequirementModel diff --git a/app/models/return-version.model.js b/app/models/return-version.model.js new file mode 100644 index 0000000000..1f4edd7fff --- /dev/null +++ b/app/models/return-version.model.js @@ -0,0 +1,39 @@ +'use strict' + +/** + * Model for return_versions (water.return_versions) + * @module ReturnVersionModel + */ + +const { Model } = require('objection') + +const BaseModel = require('./base.model.js') + +class ReturnVersionModel extends BaseModel { + static get tableName () { + return 'returnVersions' + } + + static get relationMappings () { + return { + licence: { + relation: Model.BelongsToOneRelation, + modelClass: 'licence.model', + join: { + from: 'returnVersions.licenceId', + to: 'licences.id' + } + }, + returnRequirements: { + relation: Model.HasManyRelation, + modelClass: 'return-requirement.model', + join: { + from: 'returnVersions.id', + to: 'returnRequirements.returnVersionId' + } + } + } + } +} + +module.exports = ReturnVersionModel diff --git a/db/migrations/legacy/20221108007032_water-company-contacts.js b/db/migrations/legacy/20221108003009_crm-v2-company-contacts.js similarity index 100% rename from db/migrations/legacy/20221108007032_water-company-contacts.js rename to db/migrations/legacy/20221108003009_crm-v2-company-contacts.js diff --git a/db/migrations/legacy/20221108007023_water-return-versions.js b/db/migrations/legacy/20221108007023_water-return-versions.js index 0e29f5f5ac..7534dc4065 100644 --- a/db/migrations/legacy/20221108007023_water-return-versions.js +++ b/db/migrations/legacy/20221108007023_water-return-versions.js @@ -15,12 +15,15 @@ exports.up = function (knex) { table.integer('version_number').notNullable() table.date('start_date').notNullable() table.date('end_date') - table.string('status water').notNullable() + table.string('status').notNullable() table.string('external_id') + table.text('reason') + table.boolean('multiple_upload').notNullable().defaultTo(false) + table.text('notes') // Legacy timestamps - table.timestamp('date_created', { useTz: false }).notNullable() - table.timestamp('date_updated', { useTz: false }) + table.timestamp('date_created', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + table.timestamp('date_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now()) // Constraints table.unique(['external_id'], { useConstraint: true }) diff --git a/db/migrations/legacy/20221108007024_water-return-requirements.js b/db/migrations/legacy/20221108007024_water-return-requirements.js index abfe78396b..cd640a5718 100644 --- a/db/migrations/legacy/20221108007024_water-return-requirements.js +++ b/db/migrations/legacy/20221108007024_water-return-requirements.js @@ -13,8 +13,8 @@ exports.up = function (knex) { // Data table.uuid('return_version_id').notNullable() table.string('returns_frequency').notNullable() - table.boolean('is_summer').notNullable() - table.boolean('is_upload').notNullable() + table.boolean('is_summer').notNullable().defaultTo(false) + table.boolean('is_upload').notNullable().defaultTo(false) table.smallint('abstraction_period_start_day') table.smallint('abstraction_period_start_month') table.smallint('abstraction_period_end_day') @@ -23,10 +23,15 @@ exports.up = function (knex) { table.string('description') table.integer('legacy_id') table.string('external_id') + table.text('collection_frequency').notNullable().defaultTo('day') + table.boolean('gravity_fill').notNullable().defaultTo(false) + table.boolean('reabstraction').notNullable().defaultTo(false) + table.boolean('two_part_tariff').notNullable().defaultTo(false) + table.boolean('fifty_six_exception').notNullable().defaultTo(false) // Legacy timestamps - table.timestamp('date_created', { useTz: false }).notNullable() - table.timestamp('date_updated', { useTz: false }) + table.timestamp('date_created', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + table.timestamp('date_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now()) // Constraints table.unique(['external_id'], { useConstraint: true }) diff --git a/db/migrations/legacy/20221108007025_water-return-requirement-purposes.js b/db/migrations/legacy/20221108007025_water-return-requirement-purposes.js index 3b1c1772a5..749a1736b4 100644 --- a/db/migrations/legacy/20221108007025_water-return-requirement-purposes.js +++ b/db/migrations/legacy/20221108007025_water-return-requirement-purposes.js @@ -19,8 +19,8 @@ exports.up = function (knex) { table.string('external_id') // Legacy timestamps - table.timestamp('date_created', { useTz: false }).notNullable() - table.timestamp('date_updated', { useTz: false }) + table.timestamp('date_created', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + table.timestamp('date_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now()) // Constraints table.unique(['external_id'], { useConstraint: true }) diff --git a/db/migrations/legacy/20221108007034_water-return-requirement-points.js b/db/migrations/legacy/20221108007034_water-return-requirement-points.js new file mode 100644 index 0000000000..55f1d4ec69 --- /dev/null +++ b/db/migrations/legacy/20221108007034_water-return-requirement-points.js @@ -0,0 +1,37 @@ +'use strict' + +const tableName = 'return_requirement_points' + +exports.up = function (knex) { + return knex + .schema + .withSchema('water') + .createTable(tableName, (table) => { + // Primary Key + table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()')) + + // Data + table.uuid('return_requirement_id').notNullable() + table.text('description') + table.text('ngr_1').notNullable() + table.text('ngr_2') + table.text('ngr_3') + table.text('ngr_4') + table.text('external_id') + table.integer('nald_point_id') + + // Legacy timestamps + table.timestamp('date_created', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + table.timestamp('date_updated', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + + // Constraints + table.unique(['external_id'], { useConstraint: true }) + }) +} + +exports.down = function (knex) { + return knex + .schema + .withSchema('water') + .dropTableIfExists(tableName) +} diff --git a/db/migrations/public/20240606103641_create-return-versions-view.js b/db/migrations/public/20240606103641_create-return-versions-view.js new file mode 100644 index 0000000000..0806e55fb3 --- /dev/null +++ b/db/migrations/public/20240606103641_create-return-versions-view.js @@ -0,0 +1,30 @@ +'use strict' + +const viewName = 'return_versions' + +exports.up = function (knex) { + return knex + .schema + .createView(viewName, (view) => { + view.as(knex('return_versions').withSchema('water').select([ + 'return_version_id AS id', + 'licence_id', + 'version_number AS version', + 'start_date', + 'end_date', + 'status', + 'external_id', + 'reason', + 'multiple_upload', + 'notes', + 'date_created AS created_at', + 'date_updated AS updated_at' + ])) + }) +} + +exports.down = function (knex) { + return knex + .schema + .dropViewIfExists(viewName) +} diff --git a/db/migrations/public/20240606104018_create-return-requirements-view.js b/db/migrations/public/20240606104018_create-return-requirements-view.js new file mode 100644 index 0000000000..9a322d880d --- /dev/null +++ b/db/migrations/public/20240606104018_create-return-requirements-view.js @@ -0,0 +1,37 @@ +'use strict' + +const viewName = 'return_requirements' + +exports.up = function (knex) { + return knex + .schema + .createView(viewName, (view) => { + view.as(knex('return_requirements').withSchema('water').select([ + 'return_requirement_id AS id', + 'return_version_id', + 'returns_frequency', + 'is_summer AS summer', + 'is_upload AS upload', + 'abstraction_period_start_day', + 'abstraction_period_start_month', + 'abstraction_period_end_day', + 'abstraction_period_end_month', + 'site_description', + 'legacy_id', + 'external_id', + 'collection_frequency', + 'gravity_fill', + 'reabstraction', + 'two_part_tariff', + 'fifty_six_exception', + 'date_created AS created_at', + 'date_updated AS updated_at' + ])) + }) +} + +exports.down = function (knex) { + return knex + .schema + .dropViewIfExists(viewName) +} diff --git a/db/migrations/public/20240606104927_create-return-requirement-purposes-view.js b/db/migrations/public/20240606104927_create-return-requirement-purposes-view.js new file mode 100644 index 0000000000..0659ef52dd --- /dev/null +++ b/db/migrations/public/20240606104927_create-return-requirement-purposes-view.js @@ -0,0 +1,27 @@ +'use strict' + +const viewName = 'return_requirement_purposes' + +exports.up = function (knex) { + return knex + .schema + .createView(viewName, (view) => { + view.as(knex('return_requirement_purposes').withSchema('water').select([ + 'return_requirement_purpose_id AS id', + 'return_requirement_id', + 'purpose_primary_id', + 'purpose_secondary_id', + 'purpose_use_id AS purpose_id', + 'purpose_alias AS alias', + 'external_id', + 'date_created AS created_at', + 'date_updated AS updated_at' + ])) + }) +} + +exports.down = function (knex) { + return knex + .schema + .dropViewIfExists(viewName) +} diff --git a/db/migrations/public/20240606105250_create-return-requirement-points-view.js b/db/migrations/public/20240606105250_create-return-requirement-points-view.js new file mode 100644 index 0000000000..e0ce85f7f0 --- /dev/null +++ b/db/migrations/public/20240606105250_create-return-requirement-points-view.js @@ -0,0 +1,29 @@ +'use strict' + +const viewName = 'return_requirement_points' + +exports.up = function (knex) { + return knex + .schema + .createView(viewName, (view) => { + view.as(knex('return_requirement_points').withSchema('water').select([ + 'id', + 'return_requirement_id', + 'description', + 'ngr_1', + 'ngr_2', + 'ngr_3', + 'ngr_4', + 'external_id', + 'nald_point_id', + 'date_created AS created_at', + 'date_updated AS updated_at' + ])) + }) +} + +exports.down = function (knex) { + return knex + .schema + .dropViewIfExists(viewName) +} diff --git a/test/models/licence.model.test.js b/test/models/licence.model.test.js index 4de63cc74b..85eeedf943 100644 --- a/test/models/licence.model.test.js +++ b/test/models/licence.model.test.js @@ -28,6 +28,8 @@ const RegionHelper = require('../support/helpers/region.helper.js') const RegionModel = require('../../app/models/region.model.js') const ReturnLogHelper = require('../support/helpers/return-log.helper.js') const ReturnLogModel = require('../../app/models/return-log.model.js') +const ReturnVersionHelper = require('../support/helpers/return-version.helper.js') +const ReturnVersionModel = require('../../app/models/return-version.model.js') const RegisteredToAndLicenceNameSeeder = require('../support/seeders/registered-to-and-licence-name.seeder.js') const ReviewLicenceHelper = require('../support/helpers/review-licence.helper.js') const ReviewLicenceModel = require('../../app/models/review-licence.model.js') @@ -271,7 +273,7 @@ describe('Licence model', () => { expect(query).to.exist() }) - it('can eager load the workflows', async () => { + it('can eager load the return logs', async () => { const result = await LicenceModel.query() .findById(testRecord.id) .withGraphFetched('returnLogs') @@ -286,6 +288,41 @@ describe('Licence model', () => { }) }) + describe('when linking to return versions', () => { + let testReturnVersions + + beforeEach(async () => { + const { id: licenceId } = testRecord + + testReturnVersions = [] + for (let i = 0; i < 2; i++) { + const returnVersion = await ReturnVersionHelper.add({ licenceId }) + testReturnVersions.push(returnVersion) + } + }) + + it('can successfully run a related query', async () => { + const query = await LicenceModel.query() + .innerJoinRelated('returnVersions') + + expect(query).to.exist() + }) + + it('can eager load the return versions', async () => { + const result = await LicenceModel.query() + .findById(testRecord.id) + .withGraphFetched('returnVersions') + + expect(result).to.be.instanceOf(LicenceModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnVersions).to.be.an.array() + expect(result.returnVersions[0]).to.be.an.instanceOf(ReturnVersionModel) + expect(result.returnVersions).to.include(testReturnVersions[0]) + expect(result.returnVersions).to.include(testReturnVersions[1]) + }) + }) + describe('when linking to review licences', () => { let testReviewLicences diff --git a/test/models/purpose.model.test.js b/test/models/purpose.model.test.js index 3cf5192d5d..4d78ec4338 100644 --- a/test/models/purpose.model.test.js +++ b/test/models/purpose.model.test.js @@ -13,7 +13,11 @@ const ChargeElementModel = require('../../app/models/charge-element.model.js') const ChargeReferenceHelper = require('../support/helpers/charge-reference.helper.js') const ChargeReferenceModel = require('../../app/models/charge-reference.model.js') const DatabaseSupport = require('../support/database.js') +const LicenceVersionPurposeHelper = require('../support/helpers/licence-version-purpose.helper.js') +const LicenceVersionPurposeModel = require('../../app/models/licence-version-purpose.model.js') const PurposeHelper = require('../support/helpers/purpose.helper.js') +const ReturnRequirementPurposeHelper = require('../support/helpers/return-requirement-purpose.helper.js') +const ReturnRequirementPurposeModel = require('../../app/models/return-requirement-purpose.model.js') // Thing under test const PurposeModel = require('../../app/models/purpose.model.js') @@ -23,11 +27,13 @@ describe('Purpose model', () => { beforeEach(async () => { await DatabaseSupport.clean() - - testRecord = await PurposeHelper.add() }) describe('Basic query', () => { + beforeEach(async () => { + testRecord = await PurposeHelper.add() + }) + it('can successfully run a basic query', async () => { const result = await PurposeModel.query().findById(testRecord.id) @@ -41,11 +47,11 @@ describe('Purpose model', () => { let testChargeElements beforeEach(async () => { - const { id } = testRecord + testRecord = await PurposeHelper.add() testChargeElements = [] for (let i = 0; i < 2; i++) { - const chargeElement = await ChargeElementHelper.add({ purposeId: id }) + const chargeElement = await ChargeElementHelper.add({ purposeId: testRecord.id }) testChargeElements.push(chargeElement) } }) @@ -76,11 +82,11 @@ describe('Purpose model', () => { let testChargeReferences beforeEach(async () => { - const { id } = testRecord + testRecord = await PurposeHelper.add() testChargeReferences = [] for (let i = 0; i < 2; i++) { - const chargeReference = await ChargeReferenceHelper.add({ purposeId: id }) + const chargeReference = await ChargeReferenceHelper.add({ purposeId: testRecord.id }) testChargeReferences.push(chargeReference) } }) @@ -106,5 +112,75 @@ describe('Purpose model', () => { expect(result.chargeReferences).to.include(testChargeReferences[1]) }) }) + + describe('when linking to licence version purposes', () => { + let testLicenceVersionPurposes + + beforeEach(async () => { + testRecord = await PurposeHelper.add() + + testLicenceVersionPurposes = [] + for (let i = 0; i < 2; i++) { + const licenceVersionPurpose = await LicenceVersionPurposeHelper.add({ purposeId: testRecord.id }) + testLicenceVersionPurposes.push(licenceVersionPurpose) + } + }) + + it('can successfully run a related query', async () => { + const query = await PurposeModel.query() + .innerJoinRelated('licenceVersionPurposes') + + expect(query).to.exist() + }) + + it('can eager load the licence version purposes', async () => { + const result = await PurposeModel.query() + .findById(testRecord.id) + .withGraphFetched('licenceVersionPurposes') + + expect(result).to.be.instanceOf(PurposeModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.licenceVersionPurposes).to.be.an.array() + expect(result.licenceVersionPurposes[0]).to.be.an.instanceOf(LicenceVersionPurposeModel) + expect(result.licenceVersionPurposes).to.include(testLicenceVersionPurposes[0]) + expect(result.licenceVersionPurposes).to.include(testLicenceVersionPurposes[1]) + }) + }) + + describe('when linking to return requirement purposes', () => { + let testReturnRequirementPurposes + + beforeEach(async () => { + testRecord = await PurposeHelper.add() + + testReturnRequirementPurposes = [] + for (let i = 0; i < 2; i++) { + const returnRequirementPurpose = await ReturnRequirementPurposeHelper.add({ purposeId: testRecord.id }) + testReturnRequirementPurposes.push(returnRequirementPurpose) + } + }) + + it('can successfully run a related query', async () => { + const query = await PurposeModel.query() + .innerJoinRelated('returnRequirementPurposes') + + expect(query).to.exist() + }) + + it('can eager load the return requirement purposes', async () => { + const result = await PurposeModel.query() + .findById(testRecord.id) + .withGraphFetched('returnRequirementPurposes') + + expect(result).to.be.instanceOf(PurposeModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnRequirementPurposes).to.be.an.array() + expect(result.returnRequirementPurposes[0]).to.be.an.instanceOf(ReturnRequirementPurposeModel) + expect(result.returnRequirementPurposes).to.include(testReturnRequirementPurposes[0]) + expect(result.returnRequirementPurposes).to.include(testReturnRequirementPurposes[1]) + }) + }) }) }) diff --git a/test/models/return-requirement-point.model.test.js b/test/models/return-requirement-point.model.test.js new file mode 100644 index 0000000000..c91f5b7834 --- /dev/null +++ b/test/models/return-requirement-point.model.test.js @@ -0,0 +1,70 @@ +'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 DatabaseSupport = require('../support/database.js') +const ReturnRequirementHelper = require('../support/helpers/return-requirement.helper.js') +const ReturnRequirementModel = require('../../app/models/return-requirement.model.js') +const ReturnRequirementPointHelper = require('../support/helpers/return-requirement-point.helper.js') + +// Thing under test +const ReturnRequirementPointModel = require('../../app/models/return-requirement-point.model.js') + +describe('Return Requirement Point model', () => { + let testRecord + + beforeEach(async () => { + await DatabaseSupport.clean() + }) + + describe('Basic query', () => { + beforeEach(async () => { + testRecord = await ReturnRequirementPointHelper.add() + }) + + it('can successfully run a basic query', async () => { + const result = await ReturnRequirementPointModel.query().findById(testRecord.id) + + expect(result).to.be.an.instanceOf(ReturnRequirementPointModel) + expect(result.id).to.equal(testRecord.id) + }) + }) + + describe('Relationships', () => { + describe('when linking to return requirement', () => { + let testReturnRequirement + + beforeEach(async () => { + testReturnRequirement = await ReturnRequirementHelper.add() + + const { id: returnRequirementId } = testReturnRequirement + testRecord = await ReturnRequirementPointHelper.add({ returnRequirementId }) + }) + + it('can successfully run a related query', async () => { + const query = await ReturnRequirementPointModel.query() + .innerJoinRelated('returnRequirement') + + expect(query).to.exist() + }) + + it('can eager load the charge reference', async () => { + const result = await ReturnRequirementPointModel.query() + .findById(testRecord.id) + .withGraphFetched('returnRequirement') + + expect(result).to.be.instanceOf(ReturnRequirementPointModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnRequirement).to.be.an.instanceOf(ReturnRequirementModel) + expect(result.returnRequirement).to.equal(testReturnRequirement) + }) + }) + }) +}) diff --git a/test/models/return-requirement-purpose.model.test.js b/test/models/return-requirement-purpose.model.test.js new file mode 100644 index 0000000000..756ee1e097 --- /dev/null +++ b/test/models/return-requirement-purpose.model.test.js @@ -0,0 +1,102 @@ +'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 DatabaseSupport = require('../support/database.js') +const PurposeModel = require('../../app/models/purpose.model.js') +const PurposeHelper = require('../support/helpers/purpose.helper.js') +const ReturnRequirementHelper = require('../support/helpers/return-requirement.helper.js') +const ReturnRequirementModel = require('../../app/models/return-requirement.model.js') +const ReturnRequirementPurposeHelper = require('../support/helpers/return-requirement-purpose.helper.js') + +// Thing under test +const ReturnRequirementPurposeModel = require('../../app/models/return-requirement-purpose.model.js') + +describe('Return Requirement Purpose model', () => { + let testRecord + + beforeEach(async () => { + await DatabaseSupport.clean() + }) + + describe('Basic query', () => { + beforeEach(async () => { + testRecord = await ReturnRequirementPurposeHelper.add() + }) + + it('can successfully run a basic query', async () => { + const result = await ReturnRequirementPurposeModel.query().findById(testRecord.id) + + expect(result).to.be.an.instanceOf(ReturnRequirementPurposeModel) + expect(result.id).to.equal(testRecord.id) + }) + }) + + describe('Relationships', () => { + describe('when linking to purpose', () => { + let testPurpose + + beforeEach(async () => { + testPurpose = await PurposeHelper.add() + + const { id: purposeId } = testPurpose + testRecord = await ReturnRequirementPurposeHelper.add({ purposeId }) + }) + + it('can successfully run a related query', async () => { + const query = await ReturnRequirementPurposeModel.query() + .innerJoinRelated('purpose') + + expect(query).to.exist() + }) + + it('can eager load the purposes use', async () => { + const result = await ReturnRequirementPurposeModel.query() + .findById(testRecord.id) + .withGraphFetched('purpose') + + expect(result).to.be.instanceOf(ReturnRequirementPurposeModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.purpose).to.be.an.instanceOf(PurposeModel) + expect(result.purpose).to.equal(testPurpose) + }) + }) + + describe('when linking to return requirement', () => { + let testReturnRequirement + + beforeEach(async () => { + testReturnRequirement = await ReturnRequirementHelper.add() + + const { id: returnRequirementId } = testReturnRequirement + testRecord = await ReturnRequirementPurposeHelper.add({ returnRequirementId }) + }) + + it('can successfully run a related query', async () => { + const query = await ReturnRequirementPurposeModel.query() + .innerJoinRelated('returnRequirement') + + expect(query).to.exist() + }) + + it('can eager load the charge reference', async () => { + const result = await ReturnRequirementPurposeModel.query() + .findById(testRecord.id) + .withGraphFetched('returnRequirement') + + expect(result).to.be.instanceOf(ReturnRequirementPurposeModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnRequirement).to.be.an.instanceOf(ReturnRequirementModel) + expect(result.returnRequirement).to.equal(testReturnRequirement) + }) + }) + }) +}) diff --git a/test/models/return-requirement.model.test.js b/test/models/return-requirement.model.test.js new file mode 100644 index 0000000000..a388b1151f --- /dev/null +++ b/test/models/return-requirement.model.test.js @@ -0,0 +1,146 @@ +'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 DatabaseSupport = require('../support/database.js') +const ReturnRequirementHelper = require('../support/helpers/return-requirement.helper.js') +const ReturnRequirementPointHelper = require('../support/helpers/return-requirement-point.helper.js') +const ReturnRequirementPointModel = require('../../app/models/return-requirement-point.model.js') +const ReturnRequirementPurposeHelper = require('../support/helpers/return-requirement-purpose.helper.js') +const ReturnRequirementPurposeModel = require('../../app/models/return-requirement-purpose.model.js') +const ReturnVersionHelper = require('../support/helpers/return-version.helper.js') +const ReturnVersionModel = require('../../app/models/return-version.model.js') + +// Thing under test +const ReturnRequirementModel = require('../../app/models/return-requirement.model.js') + +describe('Return Requirement model', () => { + let testRecord + + beforeEach(async () => { + await DatabaseSupport.clean() + }) + + describe('Basic query', () => { + beforeEach(async () => { + testRecord = await ReturnRequirementHelper.add() + }) + + it('can successfully run a basic query', async () => { + const result = await ReturnRequirementModel.query().findById(testRecord.id) + + expect(result).to.be.an.instanceOf(ReturnRequirementModel) + expect(result.id).to.equal(testRecord.id) + }) + }) + + describe('Relationships', () => { + describe('when linking to return requirement points', () => { + let testReturnRequirementPoints + + beforeEach(async () => { + testRecord = await ReturnRequirementHelper.add() + + testReturnRequirementPoints = [] + for (let i = 0; i < 2; i++) { + const returnRequirementPoint = await ReturnRequirementPointHelper.add( + { description: `TEST RET PNT ${i}`, returnRequirementId: testRecord.id } + ) + testReturnRequirementPoints.push(returnRequirementPoint) + } + }) + + it('can successfully run a related query', async () => { + const query = await ReturnRequirementModel.query() + .innerJoinRelated('returnRequirementPoints') + + expect(query).to.exist() + }) + + it('can eager load the return requirement points', async () => { + const result = await ReturnRequirementModel.query() + .findById(testRecord.id) + .withGraphFetched('returnRequirementPoints') + + expect(result).to.be.instanceOf(ReturnRequirementModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnRequirementPoints).to.be.an.array() + expect(result.returnRequirementPoints[0]).to.be.an.instanceOf(ReturnRequirementPointModel) + expect(result.returnRequirementPoints).to.include(testReturnRequirementPoints[0]) + expect(result.returnRequirementPoints).to.include(testReturnRequirementPoints[1]) + }) + }) + + describe('when linking to return requirement purposes', () => { + let testReturnRequirementPurposes + + beforeEach(async () => { + testRecord = await ReturnRequirementHelper.add() + + testReturnRequirementPurposes = [] + for (let i = 0; i < 2; i++) { + const returnRequirementPurpose = await ReturnRequirementPurposeHelper.add( + { alias: `TEST RET REQ ${i}`, returnRequirementId: testRecord.id } + ) + testReturnRequirementPurposes.push(returnRequirementPurpose) + } + }) + + it('can successfully run a related query', async () => { + const query = await ReturnRequirementModel.query() + .innerJoinRelated('returnRequirementPurposes') + + expect(query).to.exist() + }) + + it('can eager load the return requirement purposes', async () => { + const result = await ReturnRequirementModel.query() + .findById(testRecord.id) + .withGraphFetched('returnRequirementPurposes') + + expect(result).to.be.instanceOf(ReturnRequirementModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnRequirementPurposes).to.be.an.array() + expect(result.returnRequirementPurposes[0]).to.be.an.instanceOf(ReturnRequirementPurposeModel) + expect(result.returnRequirementPurposes).to.include(testReturnRequirementPurposes[0]) + expect(result.returnRequirementPurposes).to.include(testReturnRequirementPurposes[1]) + }) + }) + + describe('when linking to return version', () => { + let testReturnVersion + + beforeEach(async () => { + testReturnVersion = await ReturnVersionHelper.add() + testRecord = await ReturnRequirementHelper.add({ returnVersionId: testReturnVersion.id }) + }) + + it('can successfully run a related query', async () => { + const query = await ReturnRequirementModel.query() + .innerJoinRelated('returnVersion') + + expect(query).to.exist() + }) + + it('can eager load the charge version', async () => { + const result = await ReturnRequirementModel.query() + .findById(testRecord.id) + .withGraphFetched('returnVersion') + + expect(result).to.be.instanceOf(ReturnRequirementModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnVersion).to.be.an.instanceOf(ReturnVersionModel) + expect(result.returnVersion).to.equal(testReturnVersion) + }) + }) + }) +}) diff --git a/test/models/return-version.model.test.js b/test/models/return-version.model.test.js new file mode 100644 index 0000000000..b6a8288780 --- /dev/null +++ b/test/models/return-version.model.test.js @@ -0,0 +1,109 @@ +'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 DatabaseSupport = require('../support/database.js') +const LicenceHelper = require('../support/helpers/licence.helper.js') +const LicenceModel = require('../../app/models/licence.model.js') +const ReturnRequirementHelper = require('../support/helpers/return-requirement.helper.js') +const ReturnRequirementModel = require('../../app/models/return-requirement.model.js') +const ReturnVersionHelper = require('../support/helpers/return-version.helper.js') + +// Thing under test +const ReturnVersionModel = require('../../app/models/return-version.model.js') + +describe('Return Version model', () => { + let testRecord + + beforeEach(async () => { + await DatabaseSupport.clean() + }) + + describe('Basic query', () => { + beforeEach(async () => { + testRecord = await ReturnVersionHelper.add() + }) + + it('can successfully run a basic query', async () => { + const result = await ReturnVersionModel.query().findById(testRecord.id) + + expect(result).to.be.an.instanceOf(ReturnVersionModel) + expect(result.id).to.equal(testRecord.id) + }) + }) + + describe('Relationships', () => { + describe('when linking to licence', () => { + let testLicence + + beforeEach(async () => { + testLicence = await LicenceHelper.add() + + const { id: licenceId } = testLicence + testRecord = await ReturnVersionHelper.add({ licenceId }) + }) + + it('can successfully run a related query', async () => { + const query = await ReturnVersionModel.query() + .innerJoinRelated('licence') + + expect(query).to.exist() + }) + + it('can eager load the licence', async () => { + const result = await ReturnVersionModel.query() + .findById(testRecord.id) + .withGraphFetched('licence') + + expect(result).to.be.instanceOf(ReturnVersionModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.licence).to.be.an.instanceOf(LicenceModel) + expect(result.licence).to.equal(testLicence) + }) + }) + + describe('when linking to return requirements', () => { + let testReturnRequirements + + beforeEach(async () => { + testRecord = await ReturnVersionHelper.add() + + testReturnRequirements = [] + for (let i = 0; i < 2; i++) { + const returnRequirement = await ReturnRequirementHelper.add( + { siteDescription: `TEST RTN REQ ${i}`, returnVersionId: testRecord.id } + ) + testReturnRequirements.push(returnRequirement) + } + }) + + it('can successfully run a related query', async () => { + const query = await ReturnVersionModel.query() + .innerJoinRelated('returnRequirements') + + expect(query).to.exist() + }) + + it('can eager load the return requirements', async () => { + const result = await ReturnVersionModel.query() + .findById(testRecord.id) + .withGraphFetched('returnRequirements') + + expect(result).to.be.instanceOf(ReturnVersionModel) + expect(result.id).to.equal(testRecord.id) + + expect(result.returnRequirements).to.be.an.array() + expect(result.returnRequirements[0]).to.be.an.instanceOf(ReturnRequirementModel) + expect(result.returnRequirements).to.include(testReturnRequirements[0]) + expect(result.returnRequirements).to.include(testReturnRequirements[1]) + }) + }) + }) +}) diff --git a/test/support/helpers/purpose.helper.js b/test/support/helpers/purpose.helper.js index c37749def2..c116b65e69 100644 --- a/test/support/helpers/purpose.helper.js +++ b/test/support/helpers/purpose.helper.js @@ -39,7 +39,7 @@ function add (data = {}) { */ function defaults (data = {}) { const defaults = { - legacyId: generateLegacyId(), + legacyId: generatePurposeCode(), description: 'Spray Irrigation - Storage', lossFactor: 'high', twoPartTariff: true @@ -51,7 +51,7 @@ function defaults (data = {}) { } } -function generateLegacyId () { +function generatePurposeCode () { const numbering = randomInteger(1, 999) return `${numbering}0` @@ -59,5 +59,6 @@ function generateLegacyId () { module.exports = { add, - defaults + defaults, + generatePurposeCode } diff --git a/test/support/helpers/return-requirement-point.helper.js b/test/support/helpers/return-requirement-point.helper.js new file mode 100644 index 0000000000..cb13c30098 --- /dev/null +++ b/test/support/helpers/return-requirement-point.helper.js @@ -0,0 +1,75 @@ +'use strict' + +/** + * @module ReturnRequirementPointHelper + */ + +const { generateUUID } = require('../../../app/lib/general.lib.js') +const { randomInteger } = require('../general.js') +const ReturnRequirementPointModel = require('../../../app/models/return-requirement-point.model.js') + +/** + * Add a new return requirement point + * + * If no `data` is provided, default values will be used. These are + * + * - `externalId` - [randomly generated - 9:99999:100414] + * - `naldPointId` - [randomly generated - 100414] + * - `ngr1` - [randomly generated - TL 5143 7153] + * - `returnRequirementId` - [random UUID] + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + * + * @returns {Promise} The instance of the newly created record + */ +function add (data = {}) { + const insertData = defaults(data) + + return ReturnRequirementPointModel.query() + .insert({ ...insertData }) + .returning('*') +} + +/** + * Returns the defaults used + * + * 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 naldPointId = data.naldPointId ? data.naldPointId : generateNaldPointId() + const ngr1 = data.ngr1 ? data.ngr1 : generateNationalGridReference() + + const defaults = { + externalId: `9:${randomInteger(100, 99999)}:${naldPointId}`, + naldPointId, + ngr1, + returnRequirementId: generateUUID() + } + + return { + ...defaults, + ...data + } +} + +function generateNationalGridReference () { + // NOTE: These are taken from https://en.wikipedia.org/wiki/Ordnance_Survey_National_Grid and are the 100KM + // square references that cover the majority of the UK (sorry far North!) + const codes = ['SD', 'SE', 'SJ', 'SK', 'SO', 'SP', 'ST', 'SU', 'SY', 'SZ', 'TA', 'TF', 'TL', 'TQ', 'TV', 'TG', 'TM'] + + return `${codes[randomInteger(0, 16)]} ${randomInteger(100, 999)} ${randomInteger(100, 999)}` +} + +function generateNaldPointId () { + return randomInteger(1, 9999) +} + +module.exports = { + add, + defaults, + generateNationalGridReference, + generateNaldPointId +} diff --git a/test/support/helpers/return-requirement-purpose.helper.js b/test/support/helpers/return-requirement-purpose.helper.js new file mode 100644 index 0000000000..b0acf9ac0e --- /dev/null +++ b/test/support/helpers/return-requirement-purpose.helper.js @@ -0,0 +1,77 @@ +'use strict' + +/** + * @module ReturnRequirementPurposeHelper + */ + +const { generateUUID } = require('../../../app/lib/general.lib.js') +const { randomInteger } = require('../general.js') +const { generatePurposeCode } = require('./purpose.helper.js') +const ReturnRequirementPurposeModel = require('../../../app/models/return-requirement-purpose.model.js') + +/** + * Add a new return requirement purpose + * + * If no `data` is provided, default values will be used. These are + * + * - `externalId` - [randomly generated - 9:99999:A:AGR:400] + * - `purposeId` - [random UUID] + * - `purposePrimaryId` - [random UUID] + * - `purposeSecondaryId` - [random UUID] + * - `returnRequirementId` - [random UUID] + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + * + * @returns {Promise} The instance of the newly created record + */ +function add (data = {}) { + const insertData = defaults(data) + + return ReturnRequirementPurposeModel.query() + .insert({ ...insertData }) + .returning('*') +} + +/** + * Returns the defaults used + * + * 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 externalId = `9:${randomInteger(100, 99999)}:${_generatePrimaryCode()}:${_generateSecondaryCode()}:${generatePurposeCode()}` + + const defaults = { + externalId, + purposeId: generateUUID(), + purposePrimaryId: generateUUID(), + purposeSecondaryId: generateUUID(), + returnRequirementId: generateUUID() + } + + return { + ...defaults, + ...data + } +} + +function _generatePrimaryCode () { + // NOTE: Taken from water.purposes_primary + const codes = ['A', 'E', 'I', 'M', 'P', 'W', 'X', 'C'] + + return codes[randomInteger(0, 7)] +} + +function _generateSecondaryCode () { + // NOTE: This is only a subset. There 63 of these codes that could be used. Taken from water.purposes_secondary + const codes = ['AGR', 'AQF', 'AQP', 'BRW', 'BUS', 'CHE', 'CON', 'CRN', 'DAR', 'ELC', 'EXT', 'FAD', 'FOR', 'GOF'] + + return codes[randomInteger(0, 13)] +} + +module.exports = { + add, + defaults +} diff --git a/test/support/helpers/return-requirement.helper.js b/test/support/helpers/return-requirement.helper.js new file mode 100644 index 0000000000..8adb3384b9 --- /dev/null +++ b/test/support/helpers/return-requirement.helper.js @@ -0,0 +1,70 @@ +'use strict' + +/** + * @module ReturnRequirementHelper + */ + +const { generateUUID } = require('../../../app/lib/general.lib.js') +const { randomInteger } = require('../general.js') +const ReturnRequirementModel = require('../../../app/models/return-requirement.model.js') + +/** + * Add a new return requirement + * + * If no `data` is provided, default values will be used. These are + * + * - `abstractionPeriodStartDay` - 1 + * - `abstractionPeriodStartMonth` - 4 + * - `abstractionPeriodEndDay` - 31 + * - `abstractionPeriodEndMonth` - 3 + * - `externalId` - [randomly generated - 9:99999] + * - `legacyId` - [randomly generated - 99999] + * - `returnsFrequency` - day + * - `returnVersionId` - [random UUID] + * - `siteDescription` - BOREHOLE AT AVALON + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + * + * @returns {Promise} The instance of the newly created record + */ +function add (data = {}) { + const insertData = defaults(data) + + return ReturnRequirementModel.query() + .insert({ ...insertData }) + .returning('*') +} + +/** + * Returns the defaults used + * + * 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 legacyId = data.legacyId ? data.legacyId : randomInteger(100, 99999) + + const defaults = { + abstractionPeriodStartDay: 1, + abstractionPeriodStartMonth: 4, + abstractionPeriodEndDay: 31, + abstractionPeriodEndMonth: 3, + externalId: `9:${legacyId}`, + legacyId, + returnsFrequency: 'day', + returnVersionId: generateUUID(), + siteDescription: 'BOREHOLE AT AVALON' + } + + return { + ...defaults, + ...data + } +} + +module.exports = { + add, + defaults +} diff --git a/test/support/helpers/return-version.helper.js b/test/support/helpers/return-version.helper.js new file mode 100644 index 0000000000..d83417b6ea --- /dev/null +++ b/test/support/helpers/return-version.helper.js @@ -0,0 +1,64 @@ +'use strict' + +/** + * @module ReturnVersionHelper + */ + +const { generateUUID } = require('../../../app/lib/general.lib.js') +const { randomInteger } = require('../general.js') +const ReturnVersionModel = require('../../../app/models/return-version.model.js') + +/** + * Add a new return version + * + * If no `data` is provided, default values will be used. These are + * + * - `externalId` - [randomly generated - 9:99999:100] + * - `licenceId` - [random UUID] + * - `reason` - new-licence + * - `startDate` - 2022-04-01 + * - `status` - current + * - `version` - 100 + * + * @param {Object} [data] Any data you want to use instead of the defaults used here or in the database + * + * @returns {Promise} The instance of the newly created record + */ +function add (data = {}) { + const insertData = defaults(data) + + return ReturnVersionModel.query() + .insert({ ...insertData }) + .returning('*') +} + +/** + * Returns the defaults used + * + * 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 version = data.version ? data.version : 100 + + const defaults = { + externalId: `9:${randomInteger(100, 99999)}:${version}`, + licenceId: generateUUID(), + reason: 'new-licence', + startDate: new Date('2022-04-01'), + status: 'current', + version + } + + return { + ...defaults, + ...data + } +} + +module.exports = { + add, + defaults +}