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.
feat(cb2-9114): create amend vin end point (#71)
- Loading branch information
1 parent
39e6d0f
commit a202703
Showing
17 changed files
with
356 additions
and
26 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,74 @@ | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; | ||
import 'dotenv/config'; | ||
import { UpdateVinBody } from '../models/updateVin'; | ||
import { setCreatedAuditDetails, setLastUpdatedAuditDetails } from '../services/audit'; | ||
import { getBySystemNumberAndCreatedTimestamp, updateVehicle } from '../services/database'; | ||
import { getUserDetails } from '../services/user'; | ||
import { ERRORS, StatusCode } from '../util/enum'; | ||
import { formatErrorMessage } from '../util/errorMessage'; | ||
import { addHttpHeaders } from '../util/httpHeaders'; | ||
import logger from '../util/logger'; | ||
import { createPartialVin } from '../util/partialVin'; | ||
import { checkStatusCodeValidity } from '../validators/update'; | ||
import { validateAmendVinPayloadErrors } from '../validators/updateVin'; | ||
import { checkVinValidity } from '../validators/vinValidity'; | ||
|
||
export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { | ||
try { | ||
logger.debug('Amend VIN Called'); | ||
|
||
const amendVinPayloadErrors = validateAmendVinPayloadErrors(event); | ||
|
||
if (amendVinPayloadErrors) return addHttpHeaders(amendVinPayloadErrors); | ||
|
||
const userDetails = getUserDetails(event.headers.Authorization ?? ''); | ||
const systemNumber = decodeURIComponent(event.pathParameters?.systemNumber ?? ''); | ||
const createdTimestamp = decodeURIComponent(event.pathParameters?.createdTimestamp ?? ''); | ||
const body = await JSON.parse(event.body ?? '') as UpdateVinBody; | ||
|
||
const recordFromDB = await getBySystemNumberAndCreatedTimestamp(systemNumber, createdTimestamp); | ||
|
||
const statusCodeErrors = checkStatusCodeValidity(recordFromDB.techRecord_statusCode); | ||
if (statusCodeErrors) return addHttpHeaders(statusCodeErrors); | ||
|
||
const vinValidityErrors = checkVinValidity(recordFromDB.vin, body.newVin); | ||
if (vinValidityErrors) return addHttpHeaders(vinValidityErrors); | ||
|
||
const partialVin = createPartialVin(body.newVin); | ||
|
||
const updatedRecord = { | ||
...recordFromDB, vin: body.newVin.toUpperCase(), partialVin, techRecord_reasonForCreation: 'VIN updated.', | ||
}; | ||
|
||
const date = new Date().toISOString(); | ||
const updatedNewRecord = setCreatedAuditDetails( | ||
updatedRecord, | ||
userDetails.username, | ||
userDetails.msOid, | ||
date, | ||
updatedRecord.techRecord_statusCode as StatusCode, | ||
); | ||
|
||
const updatedRecordFromDB = setLastUpdatedAuditDetails( | ||
recordFromDB, | ||
userDetails.username, | ||
userDetails.msOid, | ||
date, | ||
StatusCode.ARCHIVED, | ||
); | ||
|
||
await updateVehicle([updatedRecordFromDB], [updatedNewRecord]); | ||
logger.debug(JSON.stringify(updatedNewRecord)); | ||
|
||
return addHttpHeaders({ | ||
statusCode: 200, | ||
body: JSON.stringify(updatedNewRecord), | ||
}); | ||
} catch (err) { | ||
return addHttpHeaders({ | ||
statusCode: 500, | ||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions | ||
body: formatErrorMessage(ERRORS.FAILED_UPDATE_MESSAGE), | ||
}); | ||
} | ||
}; |
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,3 @@ | ||
export type UpdateVinBody = { | ||
newVin: string; | ||
}; |
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
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,6 @@ | ||
export const createPartialVin = (vin: string): string => { | ||
if (vin.length < 6) { | ||
return vin.toUpperCase(); | ||
} | ||
return vin.substring(Math.max(vin.length - 6)).toUpperCase(); | ||
}; |
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,37 @@ | ||
import { APIGatewayProxyEvent } from 'aws-lambda'; | ||
import { UpdateVinBody } from '../models/updateVin'; | ||
import { ERRORS } from '../util/enum'; | ||
import { formatErrorMessage } from '../util/errorMessage'; | ||
import { validateSysNumTimestampPathParams } from './sysNumTimestamp'; | ||
|
||
export const validateAmendVinPayloadErrors = (event: APIGatewayProxyEvent) => { | ||
const pathParametersErrors = validateSysNumTimestampPathParams(event); | ||
|
||
if (pathParametersErrors) { | ||
return pathParametersErrors; | ||
} | ||
|
||
if (!event.body || !Object.keys(event.body).length) { | ||
return { | ||
statusCode: 400, | ||
body: formatErrorMessage(ERRORS.MISSING_PAYLOAD), | ||
}; | ||
} | ||
if (!event.headers.Authorization) { | ||
return { | ||
statusCode: 400, | ||
body: formatErrorMessage(ERRORS.MISSING_AUTH_HEADER), | ||
}; | ||
} | ||
|
||
const body = JSON.parse(event.body) as UpdateVinBody; | ||
|
||
if (!body.newVin) { | ||
return { | ||
statusCode: 400, | ||
body: formatErrorMessage('No new VIN provided'), | ||
}; | ||
} | ||
|
||
return undefined; | ||
}; |
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
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,101 @@ | ||
import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; | ||
import { seedTables } from '../../../scripts/setup-local-tables'; | ||
import { tableName } from '../../../src/config'; | ||
import techRecordData from '../../resources/technical-records-v3.json'; | ||
import { mockToken } from '../../unit/util/mockToken'; | ||
|
||
describe('updateVin', () => { | ||
beforeEach(async () => { | ||
await seedTables([{ | ||
table: tableName, | ||
data: techRecordData, | ||
}]); | ||
}); | ||
describe('happy path', () => { | ||
it('should update a vin and archive the old record', async () => { | ||
jest.setTimeout(20000); | ||
const systemNumber = '11000162'; | ||
const createdTimestamp = '2023-09-13T13:06:51.221Z'; | ||
|
||
const response = await fetch( | ||
`http:/127.0.0.1:3000/v3/technical-records/updateVin/${systemNumber}/${createdTimestamp}`, | ||
{ | ||
method: 'PATCH', | ||
body: JSON.stringify({ newVin: '123456789' }), | ||
headers: { | ||
Authorization: mockToken, | ||
}, | ||
}, | ||
); | ||
|
||
const json = await response.json() as TechRecordType<'get'>; | ||
|
||
expect(json.vin).toBe('123456789'); | ||
expect(json.techRecord_statusCode).toBe('provisional'); | ||
|
||
const checkOldRecord = await fetch( | ||
`http:/127.0.0.1:3000/v3/technical-records/${systemNumber}/${createdTimestamp}`, | ||
{ | ||
method: 'GET', | ||
headers: { | ||
Authorization: mockToken, | ||
}, | ||
}, | ||
); | ||
|
||
const jsonOldRecord = await checkOldRecord.json() as TechRecordType<'get'>; | ||
|
||
console.log(jsonOldRecord); | ||
|
||
expect(jsonOldRecord.vin).not.toBe('123456789'); | ||
expect(jsonOldRecord.techRecord_statusCode).toBe('archived'); | ||
}); | ||
}); | ||
|
||
describe('unhappy path', () => { | ||
it('should error if the record is already archived', async () => { | ||
const systemNumber = '8AJWFM00066'; | ||
const createdTimestamp = '2019-06-15T10:36:12.903Z'; | ||
|
||
const response = await fetch( | ||
`http:/127.0.0.1:3000/v3/technical-records/updateVin/${systemNumber}/${createdTimestamp}`, | ||
{ | ||
method: 'PATCH', | ||
body: JSON.stringify({ newVin: '123456789' }), | ||
headers: { | ||
Authorization: mockToken, | ||
}, | ||
}, | ||
); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
const json = await response.json(); | ||
|
||
expect(json).toEqual({ errors: ['Cannot update an archived record'] }); | ||
expect(response.status).toBe(400); | ||
}); | ||
}); | ||
|
||
it('should error if the VIN is invalid', async () => { | ||
const systemNumber = '11100136'; | ||
const createdTimestamp = '2023-09-20T15:56:43.608Z'; | ||
|
||
const response = await fetch( | ||
`http:/127.0.0.1:3000/v3/technical-records/updateVin/${systemNumber}/${createdTimestamp}`, | ||
{ | ||
method: 'PATCH', | ||
body: JSON.stringify({ newVin: 'OIQ123' }), | ||
headers: { | ||
Authorization: mockToken, | ||
}, | ||
}, | ||
); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
const json = await response.json(); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access | ||
expect(json).toEqual({ errors: ['New VIN is invalid'] }); | ||
expect(response.status).toBe(400); | ||
}); | ||
}); |
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
Oops, something went wrong.