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 registered user modifier to LicenceModel #693

Merged
merged 13 commits into from
Jan 29, 2024
64 changes: 64 additions & 0 deletions app/models/licence.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,28 @@ class LicenceModel extends BaseModel {
'suffix'
])
})
},
/**
* registeredToAndLicenceName modifier fetches the linked `licenceDocumentHeader` which holds the licence name and
* adds to it the registered user's email address if one is set.
*/
registeredToAndLicenceName (query) {
query
.withGraphFetched('licenceDocumentHeader')
.modifyGraph('licenceDocumentHeader', (builder) => {
builder.select([
'licenceDocumentHeaders.id',
'licenceDocumentHeaders.licenceName',
'licenceEntityRoles.role',
'licenceEntities.name AS registeredTo'
])
.leftJoin('licenceEntityRoles', function () {
this
.on('licenceEntityRoles.companyEntityId', '=', 'licenceDocumentHeaders.companyEntityId')
.andOn('licenceEntityRoles.role', '=', Model.raw('?', ['primary_user']))
})
.leftJoin('licenceEntities', 'licenceEntities.id', 'licenceEntityRoles.licenceEntityId')
})
}
}
}
Expand Down Expand Up @@ -230,6 +252,48 @@ class LicenceModel extends BaseModel {

return company.name
}

/**
* Determine the licence name for the licence
*
* > We recommend adding the `registeredToAndLicenceName` modifier to your query to ensure the joined records are
* > available to determine this
*
* If set this is visible on the view licence page above the licence reference and on the legacy external view as a
* field in the summary tab.
*
* The licence name is a custom name the registered user of the licence can set. So, you will only see a licence name
* if the licence is registered to a user and they have chosen to set a name for it via the external UI.
*
* @returns {(string|null)} `null` if this instance does not have the additional properties needed to determine the
* licence name else the licence's custom name
*/
$licenceName () {
const licenceName = this?.licenceDocumentHeader?.licenceName

return licenceName || null
}

/**
* Determine who the licence is registered to
*
* > We recommend adding the `registeredToAndLicenceName` modifier to your query to ensure the joined records are
* > available to determine this
*
* If set this is visible on the view licence page below the licence reference.
*
* When an external user has an account they can add a licence via the external UI. We'll generate a letter with a
* code which gets sent to the licence's address. Once they receive it they can enter the code in the UI and they
* then become the registered user for it.
*
* @returns {(string|null)} `null` if this instance does not have the additional properties needed to determine who
* the licence is registered to else the email of the user
*/
$registeredTo () {
const registeredUserName = this?.licenceDocumentHeader?.registeredTo

return registeredUserName || null
}
}

module.exports = LicenceModel
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict'

const viewName = 'licence_document_headers'

exports.up = function (knex) {
return knex
.schema
.dropView(viewName)
.createView(viewName, (view) => {
view.as(knex('document_header').withSchema('crm').select([
'document_id AS id',
// This could be ignored as it is always set to the same ID. But that id comes from a single record in the
// crm.entity table which has the `entity_type` regime. So, for the purposes of testing we just have to live
// with always populating it even though we don't care about it.
'regime_entity_id',
// 'system_id',
'system_internal_id AS nald_id',
'system_external_id AS licence_ref',
'metadata',
'company_entity_id',
// 'verification_id',
'document_name AS licence_name',
'date_created AS created_at',
'date_updated AS updated_at',
'date_deleted AS deleted_at'
]))
})
}

exports.down = function (knex) {
return knex
.schema
.dropView(viewName)
.createView(viewName, (view) => {
// NOTE: We have commented out unused columns from the source table
view.as(knex('document_header').withSchema('crm').select([
'document_id AS id',
// This could be ignored as it is always set to the same ID. But that id comes from a single record in the
// crm.entity table which has the `entity_type` regime. So, for the purposes of testing we just have to live
// with always populating it even though we don't care about it.
'regime_entity_id',
// 'system_id',
'system_internal_id AS nald_id',
'system_external_id AS licence_ref',
'metadata',
// 'company_entity_id',
// 'verification_id',
// 'document_name',
'date_created AS created_at',
'date_updated AS updated_at',
'date_deleted AS deleted_at'
]))
})
}
53 changes: 53 additions & 0 deletions test/models/licence.model.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const LicenceVersionHelper = require('../support/helpers/licence-version.helper.
const LicenceVersionModel = require('../../app/models/licence-version.model.js')
const RegionHelper = require('../support/helpers/region.helper.js')
const RegionModel = require('../../app/models/region.model.js')
const RegisteredToAndLicenceNameSeeder = require('../support/seeders/registered-to-and-licence-name.seeder.js')
const WorkflowHelper = require('../support/helpers/workflow.helper.js')
const WorkflowModel = require('../../app/models/workflow.model.js')

Expand Down Expand Up @@ -562,4 +563,56 @@ describe('Licence model', () => {
})
})
})

describe('$licenceName', () => {
describe('when instance has not been set with the additional properties needed', () => {
it('returns null', () => {
const result = testRecord.$licenceName()

expect(result).to.be.null()
})
})

describe('when the instance has been set with the additional properties needed', () => {
beforeEach(async () => {
const licence = await LicenceHelper.add()

await RegisteredToAndLicenceNameSeeder.seed(licence)

testRecord = await LicenceModel.query().findById(licence.id).modify('registeredToAndLicenceName')
})

it('returns the licence name', async () => {
const result = testRecord.$licenceName()

expect(result).to.equal('My custom licence name')
})
})
})

describe('$registeredTo', () => {
describe('when instance has not been set with the additional properties needed', () => {
it('returns null', () => {
const result = testRecord.$registeredTo()

expect(result).to.be.null()
})
})

describe('when the instance has been set with the additional properties needed', () => {
beforeEach(async () => {
const licence = await LicenceHelper.add()

await RegisteredToAndLicenceNameSeeder.seed(licence)

testRecord = await LicenceModel.query().findById(licence.id).modify('registeredToAndLicenceName')
})

it('returns who the licence is registered to', async () => {
const result = testRecord.$registeredTo()

expect(result).to.equal('[email protected]')
})
})
})
})
6 changes: 3 additions & 3 deletions test/support/helpers/licence-entity.helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const LicenceEntityModel = require('../../../app/models/licence-entity.model.js'
* If no `data` is provided, default values will be used. These are
*
* - `id` - [random UUID]
* - `name` - Grace Hopper
* - `name` - [email protected]
* - `type` - individual
*
* @param {Object} [data] Any data you want to use instead of the defaults used here or in the database
Expand All @@ -39,8 +39,8 @@ async function add (data = {}) {
function defaults (data = {}) {
const defaults = {
id: generateUUID(),
name: 'Grace Hopper',
type: 'Licence Holder'
name: '[email protected]',
type: 'individual'
}

return {
Expand Down
47 changes: 47 additions & 0 deletions test/support/seeders/registered-to-and-licence-name.seeder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict'

/**
* Seeder to setup registered to and licence name details for a LicenceModel
* @module RegisteredToAndLicenceNameSeeder
*/

const LicenceDocumentHeaderHelper = require('../helpers/licence-document-header.helper.js')
const LicenceEntityRoleHelper = require('../helpers/licence-entity-role.helper.js')
const LicenceEntityHelper = require('../helpers/licence-entity.helper.js')

/**
* Sets up the additional records needed for `$licenceName()` and `%registeredTo()` on the licence to return values
*
* The registered to and licence name details are seen on the view licence page (if a licence has them). Unfortunately,
* we have to link through a number of the legacy tables to extract the data.
*
* This seeder ensures the records needed are created and specifically support the `registeredToAndLicenceName()`
* modifier on the `LicenceModel`.
*
* @param {module:LicenceModel} licence - The licence instance we are setting up the records for
* @param {String} [licenceName] The custom licence name to use
*/
async function seed (licence, licenceName = 'My custom licence name') {
const { licenceRef } = licence

// We get from the licence to the registered user via LicenceDocumentHeader and LicenceEntityRole which are linked
// by the same companyEntityId
const companyEntityId = 'c960a4a1-94f9-4c05-9db1-a70ce5d08738'

// Create a licence document header record
await LicenceDocumentHeaderHelper.add({
companyEntityId,
licenceName,
licenceRef
})

// Create the licence entity record. It's `name` field holds the user email that the licence is registered to
const { id: licenceEntityId } = await LicenceEntityHelper.add()

// Create the licence entity role record that is the part of the link between the licence and the user email
await LicenceEntityRoleHelper.add({ companyEntityId, licenceEntityId })
}

module.exports = {
seed
}
Loading