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

Import company data for a licence #1304

Merged
merged 13 commits into from
Sep 6, 2024
Merged
26 changes: 26 additions & 0 deletions app/presenters/import/legacy/company.presenter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict'

/**
* Maps the legacy NALD company data to the WRLS format
* @module CompanyPresenter
*/

/**
* Maps the legacy NALD company data to the WRLS format
*
* @param {ImportLegacyCompanyType} company - the legacy NALD company
*
* @returns {object} the NALD company data transformed into the WRLS format for a company
* ready for validation and persisting
*/
function go (company) {
return {
name: company.name,
type: company.type,
externalId: company.external_id
}
}

module.exports = {
go
}
106 changes: 106 additions & 0 deletions app/services/import/legacy/fetch-company.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
'use strict'

/**
* Fetches the company data from the import.NALD_PARTIES table for the licence ref
* @module FetchCompanyService
*/

const { db } = require('../../../../db/db.js')

/**
* Fetches the licence data from the import.NALD_PARTIES table for the licence ref
*
* From this point parties will be referred to as companies and a party will be known as a company
*
* @param {string} regionCode - The NALD region code
* @param {string} licenceId - The NALD licence ID
*
* @returns {Promise<ImportLegacyCompanyType[]>}
*/
async function go (regionCode, licenceId) {
const query = _query()

const { rows } = await db.raw(query, [regionCode, licenceId, regionCode, licenceId])

return rows
}

function _query () {
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
return `
SELECT DISTINCT ON (np."ID")
(concat_ws(':', np."FGAC_REGION_CODE", np."ID")) AS external_id,
(
CASE np."SALUTATION"
WHEN 'null' THEN NULL
ELSE np."SALUTATION"
END
) AS salutation,
(
CASE np."FORENAME"
WHEN 'null' THEN NULL
ELSE np."FORENAME"
END
) AS firstName,
(
CASE np."NAME"
WHEN 'null' THEN NULL
ELSE np."NAME"
END
) AS lastName,
(
CASE np."APAR_TYPE"
WHEN 'PER' THEN 'person'
ELSE 'organisation'
END
) AS type,
TRIM(BOTH ' ' FROM (
CASE
-- If FORENAME or INITIALS are NULL, use NAME directly
WHEN np."FORENAME" = 'null' AND np."INITIALS" = 'null' THEN np."NAME"
ELSE CONCAT_WS(' ',
CASE
WHEN np."SALUTATION" = 'null' THEN NULL
ELSE np."SALUTATION"
END,
CASE
WHEN np."FORENAME" = 'null' THEN np."INITIALS"
ELSE np."FORENAME"
END,
CASE
WHEN np."NAME" = 'null' THEN NULL
ELSE np."NAME"
END
)
END
)) AS name,
np."ID" as id
FROM import."NALD_PARTIES" np
LEFT JOIN import."NALD_ABS_LIC_VERSIONS" nalv
ON nalv."ACON_APAR_ID" = np."ID"
AND nalv."FGAC_REGION_CODE" = np."FGAC_REGION_CODE"
LEFT JOIN import."NALD_LIC_ROLES" nlr
ON nlr."ACON_APAR_ID" = np."ID"
AND nlr."FGAC_REGION_CODE" = np."FGAC_REGION_CODE"
WHERE
(nalv."FGAC_REGION_CODE" = ? AND nalv."AABL_ID" = ?)
OR
(nlr."FGAC_REGION_CODE" = ? AND nlr."AABL_ID" = ?)
`
}

module.exports = {
go
}

/**
* @typedef {object} ImportLegacyCompanyType
*
* @property {string} - The party id
* @property {string|null} salutation - The salutation of the person, or null if not applicable.
* @property {string|null} firstName - The first name of the person, or null if not applicable.
* @property {string|null} lastName - The last name of the person, or null if not applicable.
* @property {string} type - Indicates whether the entry is a 'person' or an 'organisation'.
* @property {string|null} name - The full name, concatenated from salutation, forename/initials, and name.
* @property {string} external_id - The external ID, formatted as 'FGAC_REGION_CODE:ID'.
*
*/
6 changes: 5 additions & 1 deletion app/services/import/legacy/process-licence.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

const LicenceStructureValidator = require('../../../validators/import/licence-structure.validator.js')
const PersistLicenceService = require('../persist-licence.service.js')
const TransformCompaniesService = require('./transform-companies.service.js')
const TransformLicenceService = require('./transform-licence.service.js')
const TransformLicenceVersionPurposeConditionsService = require('./transform-licence-version-purpose-conditions.service.js')
const TransformLicenceVersionPurposesService = require('./transform-licence-version-purposes.service.js')
Expand All @@ -32,11 +33,14 @@ async function go (licenceRef) {
await TransformLicenceVersionPurposesService.go(regionCode, naldLicenceId, transformedLicence)
await TransformLicenceVersionPurposeConditionsService.go(regionCode, naldLicenceId, transformedLicence)

// Transform the company data
const { transformedCompanies } = await TransformCompaniesService.go(regionCode, naldLicenceId)
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved

// Ensure the built licence has all the valid child records we require
LicenceStructureValidator.go(transformedLicence)

// Either insert or update the licence in WRLS
const licenceId = await PersistLicenceService.go(transformedLicence)
const licenceId = await PersistLicenceService.go(transformedLicence, transformedCompanies)

calculateAndLogTimeTaken(startTime, 'Legacy licence import complete', { licenceId, licenceRef })
} catch (error) {
Expand Down
42 changes: 42 additions & 0 deletions app/services/import/legacy/transform-companies.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict'

/**
* Transforms NALD company data into a valid object that matches the WRLS structure
* @module ImportLegacyTransformCompaniesService
*/

const FetchCompanyService = require('./fetch-company.service.js')
const CompanyPresenter = require('../../../presenters/import/legacy/company.presenter.js')
const ImportCompanyValidator = require('../../../validators/import/company.validator.js')

/**
* Transforms NALD company data into a validated object that matches the WRLS structure
*
* @param {string} regionCode - The NALD region code
* @param {string} licenceId - The NALD licence ID
*
* @returns {Promise<object>} an object representing an array of valid WRLS transformed companies and
* an array of companies from the db
*/
async function go (regionCode, licenceId) {
const companies = await FetchCompanyService.go(regionCode, licenceId)

const transformedCompanies = []

companies.forEach((company) => {
const transformedCompany = CompanyPresenter.go(company)

ImportCompanyValidator.go(transformedCompany)

transformedCompanies.push(transformedCompany)
})

return {
transformedCompanies,
companies
}
}

module.exports = {
go
}
26 changes: 25 additions & 1 deletion app/services/import/persist-licence.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,25 @@ const LicenceModel = require('../../models/licence.model.js')
const LicenceVersionModel = require('../../models/licence-version.model.js')
const LicenceVersionPurposeModel = require('../../models/licence-version-purpose.model.js')
const LicenceVersionPurposeConditionModel = require('../../models/licence-version-purpose-condition.model.js')
const CompanyModel = require('../../models/company.model.js')

/**
* Creates or updates an imported licence and its child entities that have been transformed and validated
*
* @param {object} transformedLicence - An object representing a valid WRLS licence
* @param {object[]} transformedCompanies - an array of companies representing a WRLS company
*
* @returns {Promise<object>}
*/
async function go (transformedLicence) {
async function go (transformedLicence, transformedCompanies) {
return LicenceModel.transaction(async (trx) => {
const updatedAt = timestampForPostgres()
const { id } = await _persistLicence(trx, updatedAt, transformedLicence)

await _persistLicenceVersions(trx, updatedAt, transformedLicence.licenceVersions, id)

await _persistCompanies(trx, updatedAt, transformedCompanies)

return id
})
}
Expand Down Expand Up @@ -132,6 +136,26 @@ async function _persistLicenceVersionPurposeCondition (
.returning('id')
}

// Companies
async function _persistCompanies (trx, updatedAt, companies) {
for (const company of companies) {
await _persistCompany(trx, updatedAt, company)
}
}

async function _persistCompany (trx, updatedAt, company) {
const { ...propertiesToPersist } = company

return CompanyModel.query(trx)
.insert({ ...propertiesToPersist, updatedAt })
.onConflict('externalId')
.merge([
'name',
'type',
'updatedAt'
])
}

module.exports = {
go
}
37 changes: 37 additions & 0 deletions app/validators/import/company.validator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict'

/**
* @module ImportCompanyValidator
*/

const Joi = require('joi')

/**
* Checks that the imported company data has been transformed and is valid for persisting to WRLS
*
* @param {object} company - The transformed company data
*
* @throws {Joi.ValidationError} - throws a Joi validation error if the validation fails
*/
function go (company) {
const schema = Joi.object({
name: Joi.string().required(),
type: Joi.string().valid('organisation', 'person').required(),
externalId: Joi.string()
.pattern(/^\d:\d+$/) // One digit, colon, and one or more digits ('1:234')
.required()
.messages({
'string.pattern.base': '"externalId" must be in the format X:YYYY, where X is a single digit and YYYY are digits.'
})
})

const result = schema.validate(company, { convert: false })

if (result.error) {
throw result.error
}
}

module.exports = {
go
}
37 changes: 37 additions & 0 deletions test/presenters/import/legacy/company.presenter.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'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

// Thing under test
const CompanyPresenter = require('../../../../app/presenters/import/legacy/company.presenter.js')

describe('Import Legacy Company presenter', () => {
let legacyCompany

beforeEach(() => {
legacyCompany = _legacyCompany()
})

it('correctly transforms the data', () => {
const result = CompanyPresenter.go(legacyCompany)

expect(result).to.equal({
externalId: '1:1940',
name: 'ACME',
type: 'organisation'
})
})
})

function _legacyCompany () {
return {
name: 'ACME',
type: 'organisation',
external_id: '1:1940'
}
}
Loading
Loading