generated from dvsa/dvsa-lambda-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/feature/CB2-13670' into feature/…
…CB2-13861
- Loading branch information
Showing
15 changed files
with
613 additions
and
274 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { | ||
TechRecordType as TechRecordTypeByVehicle, | ||
} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; | ||
import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; | ||
import 'dotenv/config'; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
import { SQSEvent } from 'aws-lambda'; | ||
import { PlateReasonForIssue, Plates } from '../models/plate'; | ||
import { DocumentName, SQSRequestBody } from '../models/sqsPayload'; | ||
import { getBySystemNumberAndCreatedTimestamp, inPlaceRecordUpdate } from '../services/database'; | ||
import { addToSqs } from '../services/sqs'; | ||
import { StatusCode } from '../util/enum'; | ||
import { flattenArrays, formatTechRecord } from '../util/formatTechRecord'; | ||
import logger, { logError } from '../util/logger'; | ||
import { BatchPlateData } from '../models/batchPlate'; | ||
|
||
export const handler = async (event: SQSEvent): Promise<void> => { | ||
const batchIssuerName = 'CVS Batch Plate Generation'; | ||
let numberOfRecordsUpdated = 0; | ||
let numberOfSqsAdded = 0; | ||
|
||
try { | ||
const processPromises = event.Records.map(async ({ body }) => { | ||
const data: BatchPlateData = JSON.parse(body) as BatchPlateData; | ||
const { systemNumber, createdTimestamp } = data; | ||
|
||
logger.info(`Processing record: sysNum ${systemNumber}, timestamp ${createdTimestamp}`); | ||
|
||
const dbRecord = await getBySystemNumberAndCreatedTimestamp(systemNumber, createdTimestamp); | ||
|
||
if (!dbRecord || !Object.keys(dbRecord).length) { | ||
throw new Error(`Missing record: sysNum ${systemNumber}, timestamp ${createdTimestamp}`); | ||
} | ||
|
||
if (dbRecord.techRecord_statusCode !== StatusCode.CURRENT) { | ||
throw new Error(`Non current record: statusCode ${dbRecord.techRecord_statusCode}`); | ||
} | ||
if (dbRecord.techRecord_vehicleType !== 'trl' && dbRecord.techRecord_vehicleType !== 'hgv') { | ||
throw new Error(`Invalid vehicle type: ${dbRecord.techRecord_vehicleType}`); | ||
} | ||
|
||
const newPlate: Plates = { | ||
plateSerialNumber: uuidv4(), | ||
plateIssueDate: new Date().toISOString(), | ||
plateReasonForIssue: PlateReasonForIssue.REPLACEMENT, | ||
plateIssuer: batchIssuerName, | ||
}; | ||
|
||
const formattedTechRecord = formatTechRecord<TechRecordTypeByVehicle<'hgv' | 'trl'>>(dbRecord); | ||
|
||
if (formattedTechRecord.techRecord_plates?.some((plate) => plate.plateIssuer === batchIssuerName) ?? false) { | ||
logger.info(`Plate already issued for: sysNum ${systemNumber}, timestamp ${createdTimestamp}`); | ||
return; | ||
} | ||
|
||
if (formattedTechRecord.techRecord_plates) { | ||
formattedTechRecord.techRecord_plates.push(newPlate); | ||
} else { | ||
formattedTechRecord.techRecord_plates = [newPlate]; | ||
} | ||
const flattenedTechRecord = flattenArrays(formattedTechRecord) as TechRecordType<'get'>; | ||
await inPlaceRecordUpdate(flattenedTechRecord); | ||
numberOfRecordsUpdated++; | ||
|
||
const plateSqsPayload: SQSRequestBody = { | ||
techRecord: formattedTechRecord, | ||
plate: newPlate, | ||
documentName: DocumentName.MINISTRY, | ||
recipientEmailAddress: '', | ||
}; | ||
logger.debug('Sending to Doc Gen Queue', JSON.stringify(plateSqsPayload)); | ||
await addToSqs(plateSqsPayload, process.env.DOC_GEN_SQS_QUEUE ?? ''); | ||
|
||
numberOfSqsAdded++; | ||
|
||
logger.info(`Successfully processed: sysNum ${systemNumber}, timestamp ${createdTimestamp}`); | ||
}); | ||
|
||
await Promise.all(processPromises); | ||
|
||
logger.info(`Batch Plate: Updated ${numberOfRecordsUpdated} tech records and added ${numberOfSqsAdded} to SQS`); | ||
} catch (err: unknown) { | ||
logError('Error in batch processing', err); | ||
throw (err); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { | ||
S3Client, GetObjectCommand, CopyObjectCommand, DeleteObjectCommand, | ||
} from '@aws-sdk/client-s3'; | ||
import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs'; | ||
import { S3Event } from 'aws-lambda'; | ||
import { BatchPlateData } from '../models/batchPlate'; | ||
import logger, { logError } from '../util/logger'; | ||
|
||
const s3Client = new S3Client({ region: process.env.DYNAMO_AWS_REGION }); | ||
const sqsClient = new SQSClient({ region: process.env.DYNAMO_AWS_REGION }); | ||
|
||
export const handler = async (event: S3Event): Promise<void> => { | ||
logger.info('Update end point called'); | ||
|
||
try { | ||
await Promise.all(event.Records.map(processRecord)); | ||
logger.info(`Successfully processed ${event.Records.length} files.`); | ||
} catch (error) { | ||
logError('Failed to process one or more files', error); | ||
throw error; | ||
} | ||
}; | ||
async function processRecord(record: S3Event['Records'][0]): Promise<void> { | ||
const bucket = record.s3.bucket.name; | ||
const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' ')); | ||
|
||
logger.info(`Processing file: ${key} from ${bucket}`); | ||
|
||
try { | ||
const data = await retrieveJSON(bucket, key); | ||
await Promise.all(data.map((item) => sendToQueue(item))); | ||
await moveProcessedFile(bucket, key); | ||
logger.info(`Successfully processed and moved file: ${key}}`); | ||
} catch (error) { | ||
logError(`Error processing file ${key}`, error); | ||
throw error; | ||
} | ||
} | ||
|
||
/** | ||
* This function will retrieve the json file from the provided s3 bucket | ||
* Then, extract and validate the json file content | ||
* @param bucket | ||
* @param key | ||
*/ | ||
async function retrieveJSON(bucket: string, key: string): Promise<BatchPlateData[]> { | ||
const command = new GetObjectCommand({ Bucket: bucket, Key: key }); | ||
const response = await s3Client.send(command); | ||
const bodyContents = await response.Body?.transformToString(); | ||
|
||
if (!bodyContents) { | ||
throw new Error('Empty JSON file'); | ||
} | ||
|
||
try { | ||
return JSON.parse(bodyContents) as BatchPlateData[]; | ||
} catch (error) { | ||
throw new Error(`Invalid JSON in file: ${error instanceof Error ? error.message : (error as string)}`); | ||
} | ||
} | ||
|
||
/** | ||
* This function will send the systemNumber and createdTimestamp to the doc-gen service. | ||
* @param item | ||
*/ | ||
async function sendToQueue(item: BatchPlateData): Promise<void> { | ||
const command = new SendMessageCommand({ | ||
QueueUrl: process.env.SQS_QUEUE_URL, | ||
MessageBody: JSON.stringify(item), | ||
}); | ||
|
||
await sqsClient.send(command); | ||
} | ||
|
||
/** | ||
* This function will copy the file that has been processed and move it to the processed folder | ||
* Then, it will delete the original. | ||
* @param bucket | ||
* @param key | ||
*/ | ||
async function moveProcessedFile(bucket: string, key: string): Promise<void> { | ||
const newKey = `processed/${key}`; | ||
|
||
const copyCommand = new CopyObjectCommand({ | ||
Bucket: bucket, | ||
CopySource: `${bucket}/${key}`, | ||
Key: newKey, | ||
}); | ||
await s3Client.send(copyCommand); | ||
|
||
const deleteCommand = new DeleteObjectCommand({ | ||
Bucket: bucket, | ||
Key: key, | ||
}); | ||
await s3Client.send(deleteCommand); | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.