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

New 'import' job to trigger return log and supplementary flag checks #1453

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
ada1f84
New 'import' job to trigger return log and supplementary flag checks
jonathangoulding Oct 29, 2024
d836274
fix: js doc syntax
jonathangoulding Oct 29, 2024
cdf70e2
fix: js doc syntax
jonathangoulding Oct 29, 2024
c581418
feat: add batching to process the licence refs in promise all
jonathangoulding Oct 29, 2024
b5b127e
fix: log message
jonathangoulding Oct 29, 2024
44b764b
refactor: batch map into promise all
jonathangoulding Oct 29, 2024
aa0ab6f
refactor: remove unneeded return
jonathangoulding Oct 29, 2024
cca3bb8
fix: stub in import licence test
jonathangoulding Oct 29, 2024
d9cc30b
chore: pre pr checks
jonathangoulding Oct 29, 2024
8660dcb
fix: licence ref from the licence
jonathangoulding Oct 29, 2024
a0e47b7
fix: licence ref from the licence
jonathangoulding Oct 29, 2024
0029a4c
refactor: import service to use only the services needed
jonathangoulding Oct 30, 2024
2a71f8b
refactor: import service to use only the services needed
jonathangoulding Oct 30, 2024
c0345fd
feat: add timer
jonathangoulding Oct 30, 2024
610245d
chore: pre pr checks
jonathangoulding Oct 30, 2024
b8acdc8
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 4, 2024
dcbb017
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 5, 2024
b24fb5a
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 6, 2024
501d1a0
chore: pr fixes
jonathangoulding Nov 7, 2024
55afb7c
Update app/services/jobs/import/import-licence.service.js
jonathangoulding Nov 7, 2024
cb1a033
chore: pr fixes
jonathangoulding Nov 7, 2024
07840a7
refactor: seperate process licences with per licence
jonathangoulding Nov 7, 2024
7c18695
refactor: add batch size to config
jonathangoulding Nov 7, 2024
116e436
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 13, 2024
e504bf5
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 13, 2024
1c2c907
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 15, 2024
0b42ed8
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 18, 2024
bb3bb39
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 18, 2024
c39ee02
refactor: process import licences into the import licences service
jonathangoulding Nov 18, 2024
7a85f7b
feat: add p map to handle concurrency
jonathangoulding Nov 20, 2024
869b4d9
Merge remote-tracking branch 'refs/remotes/origin/main' into feature-…
jonathangoulding Nov 20, 2024
9c2d096
feat: add p map to handle concurrency
jonathangoulding Nov 20, 2024
1c8132c
feat: add p map to handle concurrency
jonathangoulding Nov 20, 2024
a69e9f2
chore: pre pr check
jonathangoulding Nov 20, 2024
666d2f4
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 21, 2024
7f2783e
Merge branch 'main' into feature-import-job-to-trigger
Cruikshanks Nov 24, 2024
6650833
Prettified!
Cruikshanks Nov 24, 2024
1f6bef0
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 25, 2024
56e3fb4
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 26, 2024
00b60c2
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Nov 27, 2024
93176cb
merge from main
robertparkinson Dec 13, 2024
000aefc
Merge remote-tracking branch 'refs/remotes/origin/main' into feature-…
jonathangoulding Dec 13, 2024
269df0f
refactor: logic to use new interfaces
jonathangoulding Dec 13, 2024
24ce7ef
refactor: logic to use new interfaces
jonathangoulding Dec 13, 2024
0d23e02
chore: pre pr checks
jonathangoulding Dec 13, 2024
dc34e65
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Dec 13, 2024
b2bc8ce
Merge branch 'main' into feature-import-job-to-trigger
jonathangoulding Dec 13, 2024
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
28 changes: 18 additions & 10 deletions app/controllers/jobs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
*/

const ExportService = require('../services/jobs/export/export.service.js')
const ImportLicence = require('../services/jobs/import/import-licence.service.js')
const ProcessLicenceUpdates = require('../services/jobs/licence-updates/process-licence-updates.js')
const ProcessReturnLogsService = require('../services/jobs/return-logs/process-return-logs.service.js')
const ProcessSessionStorageCleanupService = require('../services/jobs/session-cleanup/process-session-storage-cleanup.service.js')
const ProcessTimeLimitedLicencesService = require('../services/jobs/time-limited/process-time-limited-licences.service.js')
const ProcessReturnLogsService = require('../services/jobs/return-logs/process-return-logs.service.js')

const redirectStatusCode = 204
const notFoundStatusCode = 404
const NO_CONTENT_STATUS_CODE = 204
const NOT_FOUND_STATUS_CODE = 404

/**
* Triggers export of all relevant tables to CSV and then uploads them to S3
Expand All @@ -26,32 +27,32 @@ const notFoundStatusCode = 404
async function exportDb (_request, h) {
ExportService.go()

return h.response().code(redirectStatusCode)
return h.response().code(NO_CONTENT_STATUS_CODE)
}

async function licenceUpdates (_request, h) {
ProcessLicenceUpdates.go()

return h.response().code(redirectStatusCode)
return h.response().code(NO_CONTENT_STATUS_CODE)
}

async function sessionCleanup (_request, h) {
ProcessSessionStorageCleanupService.go()

return h.response().code(redirectStatusCode)
return h.response().code(NO_CONTENT_STATUS_CODE)
}

async function timeLimited (_request, h) {
ProcessTimeLimitedLicencesService.go()

return h.response().code(redirectStatusCode)
return h.response().code(NO_CONTENT_STATUS_CODE)
}

async function returnLogs (request, h) {
const { cycle } = request.params

if (!['summer', 'all-year'].includes(cycle)) {
return h.response().code(notFoundStatusCode)
return h.response().code(NOT_FOUND_STATUS_CODE)
}

let licenceReference
Expand All @@ -62,13 +63,20 @@ async function returnLogs (request, h) {

ProcessReturnLogsService.go(cycle, licenceReference)

return h.response().code(redirectStatusCode)
return h.response().code(NO_CONTENT_STATUS_CODE)
}

async function importLicence (_request, h) {
ImportLicence.go()

return h.response().code(NO_CONTENT_STATUS_CODE)
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
}

module.exports = {
exportDb,
licenceUpdates,
returnLogs,
sessionCleanup,
timeLimited
timeLimited,
importLicence
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
}
14 changes: 14 additions & 0 deletions app/routes/jobs.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ const routes = [
}
}
},
{
method: 'POST',
path: '/jobs/import-licence',
options: {
handler: JobsController.importLicence,
app: {
plainOutput: true
},
auth: false,
plugins: {
crumb: false
}
}
},
{
method: 'POST',
path: '/jobs/licence-updates',
Expand Down
40 changes: 40 additions & 0 deletions app/services/jobs/import/fetch-licences.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict'

/**
* Fetches all licences that are in NALD and WRLS
* @module FetchLicences
*/

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

/**
* Fetches all licences that are in NALD and WRLS
*
* A licence is valid if at least one licence version is not in draft
*
* @returns {Promise<object[]>} - An array of licences
*/
async function go () {
const query = `
SELECT DISTINCT ON (nal."LIC_NO")
l.id as id,
TO_DATE(NULLIF(nal."EXPIRY_DATE", 'null'), 'DD/MM/YYYY') AS expired_date,
TO_DATE(NULLIF(nal."LAPSED_DATE", 'null'), 'DD/MM/YYYY') AS lapsed_date,
TO_DATE(NULLIF(nal."EXPIRY_DATE", 'null'), 'DD/MM/YYYY') AS revoked_date
FROM import."NALD_ABS_LIC_VERSIONS" nalv
INNER JOIN import."NALD_ABS_LICENCES" nal
ON nal."ID" = nalv."AABL_ID"
AND nal."FGAC_REGION_CODE" = nalv."FGAC_REGION_CODE"
INNER JOIN
public.licences l ON l.licence_ref = nal."LIC_NO"
WHERE nalv."STATUS" <> 'DRAFT'
`

const { rows } = await db.raw(query)

return rows
}

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

/**
* Extracts and imports licence from NALD
* @module ImportLicence
*/

const FetchLicences = require('./fetch-licences.service.js')
const ProcessImportLicence = require('./process-import-licence.service.js')
const { calculateAndLogTimeTaken, currentTimeInNanoseconds } = require('../../../lib/general.lib.js')

/**
* Extracts and imports licence from NALD
*
* If a licence in NALD does not have a status of DRAFT, and at least one non-draft licence version
* then it will be extracted
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
*
*/
async function go () {
try {
const startTime = currentTimeInNanoseconds()

const licences = await FetchLicences.go()

ProcessImportLicence.go(licences)

calculateAndLogTimeTaken(startTime, `Importing ${licences.length} licences from NALD`)
} catch (error) {
global.GlobalNotifier.omfg('Importing Licence job failed', null, error)
}
}

module.exports = {
go
}
50 changes: 50 additions & 0 deletions app/services/jobs/import/process-import-licence.service.js
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict'

/**
* Process import licence
* @module ProcessImportLicence
*/

const DetermineSupplementaryBillingFlagsService = require('../../import/determine-supplementary-billing-flags.service.js')
const ProcessLicenceReturnLogsService = require('../return-logs/process-licence-return-logs.service.js')
const { currentTimeInNanoseconds, calculateAndLogTimeTaken } = require('../../../lib/general.lib.js')

/**
* Process import licence
*
* Batches the licences process into small chunks to reduce strain on the system
*
* @param {object[]} licences - an array of licences
*/
async function go (licences) {
const batchSize = 10
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved

const startTime = currentTimeInNanoseconds()

for (let i = 0; i < licences.length; i += batchSize) {
const batch = licences.slice(i, i + batchSize)

await _processBatch(batch)
}

calculateAndLogTimeTaken(startTime, `Finished importing ${licences.length} licences from NALD`)
jonathangoulding marked this conversation as resolved.
Show resolved Hide resolved
}

async function _processBatch (batch) {
await Promise.all(
batch.map(async (
licence) => {
await DetermineSupplementaryBillingFlagsService.go(
{
expiredDate: licence.expired_date,
lapsedDate: licence.lapsed_date,
revokedDate: licence.revoked_date
}, licence.id)
await ProcessLicenceReturnLogsService.go(licence.id)
})
)
}

module.exports = {
go
}
23 changes: 22 additions & 1 deletion test/controllers/jobs.controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ const { expect } = Code

// Things we need to stub
const ExportService = require('../../app/services/jobs/export/export.service.js')
const ImportLicence = require('../../app/services/jobs/import/import-licence.service.js')
const ProcessLicenceUpdatesService = require('../../app/services/jobs/licence-updates/process-licence-updates.js')
const ProcessReturnLogsService = require('../../app/services/jobs/return-logs/process-return-logs.service.js')
const ProcessSessionStorageCleanupService = require('../../app/services/jobs/session-cleanup/process-session-storage-cleanup.service.js')
const ProcessTimeLimitedLicencesService = require('../../app/services/jobs/time-limited/process-time-limited-licences.service.js')
const ProcessReturnLogsService = require('../../app/services/jobs/return-logs/process-return-logs.service.js')

// For running our service
const { init } = require('../../app/server.js')
Expand Down Expand Up @@ -58,6 +59,26 @@ describe('Jobs controller', () => {
})
})

describe('/jobs/import-licence', () => {
describe('POST', () => {
beforeEach(() => {
options = { method: 'POST', url: '/jobs/import-licence' }
})

describe('when the request succeeds', () => {
beforeEach(async () => {
Sinon.stub(ImportLicence, 'go').resolves()
})

it('returns a 204 response', async () => {
const response = await server.inject(options)

expect(response.statusCode).to.equal(204)
})
})
})
})

describe('/jobs/licence-updates', () => {
describe('POST', () => {
beforeEach(() => {
Expand Down
55 changes: 55 additions & 0 deletions test/services/jobs/import/import-licence.service.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict'

// Test framework dependencies
const Lab = require('@hapi/lab')
const Code = require('@hapi/code')
const Sinon = require('sinon')

const { describe, it, beforeEach, afterEach } = exports.lab = Lab.script()
const { expect } = Code

// Things we need to stub
const FetchLicences = require('../../../../app/services/jobs/import/fetch-licences.service.js')
const ProcessImportLicence = require('../../../../app/services/jobs/import/process-import-licence.service.js')
const { generateUUID } = require('../../../../app/lib/general.lib.js')

// Thing under test
const ImportLicence = require('../../../../app/services/jobs/import/import-licence.service.js')

describe('Import Licence Service', () => {
let stubFetchLicences
let stubProcessImportLicence
let notifierStub
let licences

beforeEach(async () => {
licences = [[{ id: generateUUID(), expired_date: null, lapsed_date: null, revoked_date: null }]]

stubFetchLicences = Sinon.stub(FetchLicences, 'go').resolves(licences)
stubProcessImportLicence = Sinon.stub(ProcessImportLicence, 'go').resolves()

notifierStub = { omg: Sinon.stub(), omfg: Sinon.stub() }
global.GlobalNotifier = notifierStub
})

afterEach(() => {
Sinon.restore()
delete global.GlobalNotifier
})

it('fetches the nald licence data and starts the process to import the licences', async () => {
await ImportLicence.go()

expect(stubFetchLicences.calledOnce).to.be.true()
expect(stubProcessImportLicence.calledWith(licences)).to.be.true()
})

it('logs to highlight the amount of licences being imported', async () => {
await ImportLicence.go()

const args = notifierStub.omg.firstCall.args

expect(args[0]).to.equal('Importing 1 licences from NALD')
expect(args[1].timeTakenMs).to.exist()
})
})
Loading
Loading