diff --git a/package-lock.json b/package-lock.json index 3bade06..7c49f87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@aws-sdk/types": "^3.535.0", "@aws-sdk/util-dynamodb": "^3.609.0", "@dvsa/cvs-microservice-common": "^1.1.0", - "@dvsa/cvs-type-definitions": "7.1.0", + "@dvsa/cvs-type-definitions": "7.2.0", "@smithy/util-utf8": "^2.3.0", "aws-sdk-client-mock": "^4.0.0", "aws-xray-sdk": "^3.3.4", @@ -3990,9 +3990,9 @@ } }, "node_modules/@dvsa/cvs-type-definitions": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@dvsa/cvs-type-definitions/-/cvs-type-definitions-7.1.0.tgz", - "integrity": "sha512-zvuzyBNu30wmjo9vkjmXTokoy3Gvii9Sj7y+AmQeqe0fp1HbJRF27nu68n457VHyQf+rDQACIVvDksGVXY8Cqg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@dvsa/cvs-type-definitions/-/cvs-type-definitions-7.2.0.tgz", + "integrity": "sha512-xgJ1WpIpKkUkKrCtle9OqDbnmpm9VZ8ePdl+QPvayRHxGpDgLTTgj9wyhsz9+XW2bqOepAGbBM1jO+JMPLZAog==", "dependencies": { "ajv": "^8.12.0", "json-schema-deref-sync": "^0.14.0", @@ -5045,26 +5045,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@serverless/platform-client/node_modules/ws": { - "version": "7.5.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@serverless/utils": { "version": "6.15.0", "dev": true, @@ -6567,12 +6547,6 @@ "node": "^4.7 || >=6.9 || >=7.3" } }, - "node_modules/async-limiter": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/async-settle": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz", @@ -7221,12 +7195,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -9372,9 +9346,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -15060,9 +15034,10 @@ } }, "node_modules/serverless-offline/node_modules/ws": { - "version": "8.16.0", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -15227,26 +15202,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/serverless/node_modules/ws": { - "version": "7.5.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/set-function-name": { "version": "2.0.1", "dev": true, @@ -16938,12 +16893,24 @@ } }, "node_modules/ws": { - "version": "5.2.3", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "async-limiter": "~1.0.0" + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/xml2js": { diff --git a/package.json b/package.json index fb8fc67..ee020ae 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@aws-sdk/types": "^3.535.0", "@aws-sdk/util-dynamodb": "^3.609.0", "@dvsa/cvs-microservice-common": "^1.1.0", - "@dvsa/cvs-type-definitions": "7.1.0", + "@dvsa/cvs-type-definitions": "7.2.0", "@smithy/util-utf8": "^2.3.0", "aws-sdk-client-mock": "^4.0.0", "aws-xray-sdk": "^3.3.4", diff --git a/src/functions/retroGen.ts b/src/functions/retroGen.ts index 6f1e770..9b5fcf2 100644 --- a/src/functions/retroGen.ts +++ b/src/functions/retroGen.ts @@ -1,21 +1,19 @@ -import { unmarshall } from "@aws-sdk/util-dynamodb"; -import { LambdaClient } from "@aws-sdk/client-lambda"; +import {unmarshall} from "@aws-sdk/util-dynamodb"; +import {LambdaClient} from "@aws-sdk/client-lambda"; import * as rp from "request-promise"; -import { ERRORS } from "../assets/Enum"; -import { RetroGenerationService } from "../services/RetroGenerationService"; -import { SharePointAuthenticationService } from "../services/SharePointAuthenticationService"; -import { SharePointService } from "../services/SharePointService"; -import { TestResultsService } from "../services/TestResultsService"; -import { ActivitiesService } from "../services/ActivitiesService"; -import { LambdaService } from "../services/LambdaService"; -import { PutObjectCommandOutput } from "@aws-sdk/client-s3"; -import { credentials } from "../handler"; +import {ERRORS} from "../assets/Enum"; +import {RetroGenerationService} from "../services/RetroGenerationService"; +import {SharePointAuthenticationService} from "../services/SharePointAuthenticationService"; +import {SharePointService} from "../services/SharePointService"; +import {TestResultsService} from "../services/TestResultsService"; +import {ActivitiesService} from "../services/ActivitiesService"; +import {LambdaService} from "../services/LambdaService"; +import {PutObjectCommandOutput} from "@aws-sdk/client-s3"; +import {credentials} from "../handler"; /** * λ function to process a DynamoDB stream of test results into a queue for certificate generation. * @param event - DynamoDB Stream event - * @param context - λ Context - * @param callback - callback function */ const retroGen = async (event: any): Promise => { if (!event || !event.Records || !Array.isArray(event.Records) || !event.Records.length) { @@ -35,8 +33,7 @@ const retroGen = async (event: any): Promise => const retroUploadPromise = retroService.generateRetroReport(visit).then(async (generationServiceResponse: { fileName: string; fileBuffer: Buffer }) => { const tokenResponse = await sharepointAuthenticationService.getToken(); const accessToken = JSON.parse(tokenResponse).access_token; - const sharePointResponse = await sharePointService.upload(generationServiceResponse.fileName, generationServiceResponse.fileBuffer, accessToken); - return sharePointResponse; + return await sharePointService.upload(generationServiceResponse.fileName, generationServiceResponse.fileBuffer, accessToken); }); retroUploadPromises.push(retroUploadPromise); diff --git a/src/services/RetroGenerationService.ts b/src/services/RetroGenerationService.ts index 98f9339..5b62e3b 100644 --- a/src/services/RetroGenerationService.ts +++ b/src/services/RetroGenerationService.ts @@ -5,8 +5,9 @@ import { IActivitiesList } from "../models"; import { ActivitiesService } from "./ActivitiesService"; import { TestResultsService } from "./TestResultsService"; import moment = require("moment-timezone"); -import {ActivitySchema} from "@dvsa/cvs-type-definitions/types/v1/activity"; -import {TestResultSchema, TestTypeSchema} from "@dvsa/cvs-type-definitions/types/v1/test-result"; +import { ActivitySchema} from "@dvsa/cvs-type-definitions/types/v1/activity"; +import { TestResultSchema, TestTypeSchema} from "@dvsa/cvs-type-definitions/types/v1/test-result"; +import { ModTypeSchema} from "@dvsa/cvs-type-definitions/types/v1/test-type"; class RetroGenerationService { private readonly testResultsService: TestResultsService; @@ -40,7 +41,7 @@ class RetroGenerationService { testStationPNumber: activity.testStationPNumber, activityType: "wait", }) - .then((waitActivities: any[]) => { + .then((waitActivities: ActivitySchema[]) => { const totalActivitiesLen = testResults.length + waitActivities.length; // Fetch and populate the Retrokey template return this.fetchRetroTemplate(totalActivitiesLen).then((template: { workbook: Excel.Workbook; reportTemplate: any }) => { @@ -66,9 +67,9 @@ class RetroGenerationService { if (event.activityType === ActivityType.TEST) { // Populate activity report const detailsTemplate: any = template.reportTemplate.activityDetails[i]; - const testResult: any = event.activity; - const testType: any = testResult.testTypes; - const additionalTestTypeNotes: string = testType.prohibitionIssued ? "Prohibition was issued" : "none"; + const testResult: TestResultSchema = event.activity; + const testType: TestTypeSchema[] = testResult.testTypes; + const additionalTestTypeNotes: string = testType[0].prohibitionIssued ? "Prohibition was issued" : "none"; let defects: string = ""; let reasonForAbandoning: string = ""; let additionalCommentsAbandon: string = ""; @@ -76,8 +77,8 @@ class RetroGenerationService { let defectsDetails: string = ""; let prsString: string = ""; - for (const key of Object.keys(testType.defects)) { - if (testType.defects[key].prs) { + for (const [, defectValue] of Object.entries(testType[0]?.defects || {})) { + if (defectValue.prs) { prsString = ", PRS"; } else { prsString = ""; @@ -86,36 +87,36 @@ class RetroGenerationService { defectsDetails = defectsDetails + " " + - testType.defects[key].deficiencyRef + + testType[0].defects[0].deficiencyRef + " (" + - testType.defects[key].deficiencyCategory + + testType[0].defects[0].deficiencyCategory + prsString + - (testType.defects[key].additionalInformation.notes ? ", " + testType.defects[key].additionalInformation.notes : "") + - (testType.defects[key].prohibitionIssued ? ", Prohibition was issued" : ", Prohibition was not issued") + + (testType[0].defects[0].additionalInformation.notes ? ", " + testType[0].defects[0].additionalInformation.notes : "") + + (testType[0].defects[0].prohibitionIssued ? ", Prohibition was issued" : ", Prohibition was not issued") + ")"; } if (defectsDetails) { defects = `Defects: ${defectsDetails};\r\n`; } - if (testType.reasonForAbandoning) { - reasonForAbandoning = `Reason for abandoning: ${testType.reasonForAbandoning};\r\n`; + if (testType[0].reasonForAbandoning) { + reasonForAbandoning = `Reason for abandoning: ${testType[0].reasonForAbandoning};\r\n`; } - if (testType.additionalCommentsForAbandon) { - additionalCommentsAbandon = `Additional comments for abandon: ${testType.additionalCommentsForAbandon};\r\n`; + if (testType[0].additionalCommentsForAbandon) { + additionalCommentsAbandon = `Additional comments for abandon: ${testType[0].additionalCommentsForAbandon};\r\n`; } if (this.isPassingLECTestType(testType)) { - LECNotes = "Modification type: " + testType.modType.code.toUpperCase() + "\r\n" + "Fuel type: " + testType.fuelType + "\r\n" + "Emission standards: " + testType.emissionStandard + "\r\n"; + LECNotes = "Modification type: " + (testType[0].modType! as ModTypeSchema).code.toUpperCase() + "\r\n" + "Fuel type: " + testType[0].fuelType + "\r\n" + "Emission standards: " + testType[0].emissionStandard + "\r\n"; } detailsTemplate.activity.value = activity.activityType === "visit" ? ActivityType.TEST : ActivityType.WAIT_TIME; - detailsTemplate.startTime.value = moment(testType.testTypeStartTimestamp).tz(TimeZone.LONDON).format("HH:mm:ss"); - detailsTemplate.finishTime.value = moment(testType.testTypeEndTimestamp).tz(TimeZone.LONDON).format("HH:mm:ss"); + detailsTemplate.startTime.value = moment(testType[0].testTypeStartTimestamp).tz(TimeZone.LONDON).format("HH:mm:ss"); + detailsTemplate.finishTime.value = moment(testType[0].testTypeEndTimestamp).tz(TimeZone.LONDON).format("HH:mm:ss"); detailsTemplate.vrm.value = testResult.vehicleType === VEHICLE_TYPES.TRL ? testResult.trailerId : testResult.vrm; detailsTemplate.chassisNumber.value = testResult.vin; - detailsTemplate.testType.value = testType.testCode.toUpperCase(); + detailsTemplate.testType.value = (testType[0] as TestTypeSchema).testCode?.toUpperCase(); detailsTemplate.seatsAndAxles.value = testResult.vehicleType === VEHICLE_TYPES.PSV ? testResult.numberOfSeats : testResult.noOfAxles; - detailsTemplate.result.value = testType.testResult; - detailsTemplate.certificateNumber.value = testType.certificateNumber; - detailsTemplate.expiryDate.value = testType.testExpiryDate ? moment(testType.testExpiryDate).tz(TimeZone.LONDON).format("DD/MM/YYYY") : ""; + detailsTemplate.result.value = testType[0].testResult; + detailsTemplate.certificateNumber.value = testType[0].certificateNumber; + detailsTemplate.expiryDate.value = testType[0].testExpiryDate ? moment(testType[0].testExpiryDate).tz(TimeZone.LONDON).format("DD/MM/YYYY") : ""; detailsTemplate.preparerId.value = testResult.preparerId; detailsTemplate.failureAdvisoryItemsQAIComments.value = defects + @@ -125,12 +126,12 @@ class RetroGenerationService { "Additional test type notes: " + additionalTestTypeNotes + ";\r\n" + - (testType.additionalNotesRecorded ? testType.additionalNotesRecorded + ";" : ""); + (testType[0].additionalNotesRecorded ? testType[0].additionalNotesRecorded + ";" : ""); } if (event.activityType === ActivityType.TIME_NOT_TESTING) { // Populate wait activities in the report const detailsTemplate: any = template.reportTemplate.activityDetails[i]; - const waitActivityResult: any = event.activity; + const waitActivityResult: ActivitySchema = event.activity; let waitReasons: string = ""; let additionalNotes: string = ""; @@ -171,16 +172,16 @@ class RetroGenerationService { /** * Method to collate testResults and waitActivities into a common list * and then sort them on startTime to display the activities in a sequence. - * @param testResultsList: testResults list - * @param waitActivitiesList: wait activities list + * @param testResultsList + * @param waitActivitiesList */ public computeActivitiesList(testResultsList: TestResultSchema[], waitActivitiesList: ActivitySchema[]) { const list: IActivitiesList[] = []; // Adding Test results to the list for (const testResult of testResultsList) { - const testResultTestType = testResult.testTypes as unknown as TestTypeSchema; + const testResultTestType = testResult.testTypes as TestTypeSchema[]; const act: IActivitiesList = { - startTime: testResultTestType.testTypeStartTimestamp!, + startTime: testResultTestType[0].testTypeStartTimestamp!, activityType: ActivityType.TEST, activity: testResult, }; @@ -196,7 +197,8 @@ class RetroGenerationService { list.push(act); } // Sorting the list by StartTime - const sortDateAsc = (date1: any, date2: any) => { + const sortDateAsc = (date1: IActivitiesList, date2: IActivitiesList) => { + console.log(date1) const date = new Date(date1.startTime).toISOString(); const dateToCompare = new Date(date2.startTime).toISOString(); if (date > dateToCompare) { diff --git a/src/services/TestResultsService.ts b/src/services/TestResultsService.ts index 3473c31..7f8ac4a 100644 --- a/src/services/TestResultsService.ts +++ b/src/services/TestResultsService.ts @@ -3,7 +3,7 @@ import { InvocationResponse } from "@aws-sdk/client-lambda"; import { LambdaService } from "./LambdaService"; import { Configuration } from "../utils/Configuration"; import moment from "moment"; -import {TestResultSchema} from "@dvsa/cvs-type-definitions/types/v1/test-result"; +import {TestResultSchema, TestTypeSchema} from "@dvsa/cvs-type-definitions/types/v1/test-result"; class TestResultsService { private readonly lambdaClient: LambdaService; @@ -32,10 +32,10 @@ class TestResultsService { }; return this.lambdaClient.invoke(invokeParams).then((response: InvocationResponse) => { const payload: any = this.lambdaClient.validateInvocationResponse(response); // Response validation - const testResults: any[] = JSON.parse(payload.body); // Response conversion + const testResults: TestResultSchema[] = JSON.parse(payload.body); // Response conversion // Sort results by testEndTimestamp - testResults.sort((first: any, second: any): number => { + testResults.sort((first: TestResultSchema, second: TestResultSchema): number => { if (moment(first.testEndTimestamp).isBefore(second.testEndTimestamp)) { return -1; } @@ -56,24 +56,24 @@ class TestResultsService { * into multiple records with a single test type * @param testResults */ - public expandTestResults(testResults: any): any[] { + public expandTestResults(testResults: TestResultSchema[]): any[] { return testResults - .map((testResult: any) => { + .map((testResult: TestResultSchema) => { // Separate each test type in a record to form multiple test results - const splittedRecords: any[] = []; - const templateRecord: any = Object.assign({}, testResult); + const splittedRecords: TestResultSchema[] = []; + const templateRecord: TestResultSchema = Object.assign({}, testResult); Object.assign(templateRecord, {}); - testResult.testTypes.forEach((testType: any, i: number, array: any[]) => { - const clonedRecord: any = Object.assign({}, templateRecord); // Create test result from template - Object.assign(clonedRecord, { testTypes: testType }); // Assign it the test type + testResult.testTypes.forEach((testType: TestTypeSchema) => { + const clonedRecord: TestResultSchema = Object.assign({}, templateRecord); // Create test result from template + Object.assign(clonedRecord, { testTypes: [testType] }); // Assign it the test type splittedRecords.push(clonedRecord); }); return splittedRecords; }) - .reduce((acc: any[], val: any) => acc.concat(val), []); // Flatten the array + .reduce((acc: TestResultSchema[], val: any) => acc.concat(val), []); // Flatten the array } } diff --git a/tests/unit/TestResultsService.unitTest.ts b/tests/unit/TestResultsService.unitTest.ts index c745094..e9ada04 100644 --- a/tests/unit/TestResultsService.unitTest.ts +++ b/tests/unit/TestResultsService.unitTest.ts @@ -5,6 +5,7 @@ import mockConfig from "../util/mockConfig"; import testResults200 from "../resources/test-results-200-response.json"; import testResults200empty from "../resources/test-results-200-response-empty-body.json"; import testResults404 from "../resources/test-results-404-response.json"; +import {TestResultSchema} from "@dvsa/cvs-type-definitions/types/v1/test-result"; describe("TestResultsService", () => { mockConfig(); @@ -20,8 +21,8 @@ describe("TestResultsService", () => { }; }); const testResultsService: TestResultsService = new TestResultsService(new lambdaMock()); - return testResultsService.getTestResults({}).then((result: any) => { - const expectedResult: any = [ + return testResultsService.getTestResults({}).then((result: TestResultSchema[]) => { + const expectedResult = [ { testerStaffId: "1", vrm: "JY58FPP", @@ -29,7 +30,7 @@ describe("TestResultsService", () => { numberOfSeats: 45, testStartTimestamp: "2019-01-14T10:36:33.987Z", testEndTimestamp: "2019-01-14T10:36:33.987Z", - testTypes: { + testTypes: [{ prohibitionIssued: false, testCode: "aas", testNumber: "1", @@ -79,7 +80,7 @@ describe("TestResultsService", () => { name: "Annual test", certificateLink: "http://dvsagov.co.uk", testResult: "pass", - }, + }], vin: "XMGDE02FS0H012345", }, ];