-
Notifications
You must be signed in to change notification settings - Fork 5
feat(DTFS2-7793): add update amendment status endpoint to dtfs-central #4193
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
Merged
MarRobSoftwire
merged 37 commits into
main
from
feat/DTFS2-7793/submit-amendment-to-checker-endpoint-dtfs-central
Feb 10, 2025
Merged
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
d9c9ec2
feat(DTFS2-7793): add submit amendment to checker endpoint
d0e77a4
feat(DTFS2-7793): add service unit tests
17304f9
feat(DTFS2-7793): add controller unit tests
2efda19
feat(DTFS2-7793): add api test (wip)
061733b
feat(DTFS2-7793): refactor to make service more DRY
8bc059c
feat(DTFS2-7793): validate that the amendment is of an expected status
5ba2e55
feat(DTFS2-7793): generate valid amendment structure
b0ffdaf
feat(DTFS2-7793): add validateAmendmentIsComplete function to amendme…
372d93a
feat(DTFS2-7793): add jsdoc
be71521
feat(DTFS2-7793): update updatePortalFacilityAmendmentByAmendmentId u…
fed066a
feat(DTFS2-7793): update service unit tests
2539c9d
feat(DTFS2-7793): add unit tests for validateAmendmentIsComplete serv…
52d682b
feat(DTFS2-7793): add unit tests for generatePortalFacilityAmendment
2597927
feat(DTFS2-7793): update typo in controller unit test
dc8051d
feat(DTFS2-7793): add error unit tests
48f786f
feat(DTFS2-7793): refactor to post status endpoint
622e302
feat(DTFS2-7793): rename files & update swagger
74eea25
feat(DTFS2-7793): update api test
0851d4b
feat(DTFS2-7793): update view model types
fb4eddc
feat(DTFS2-7793): update method to PATCH
39c3abf
feat(DTFS2-7793): use payload rather than path params
1a191cc
feat(DTFS2-7793): update api test
86a85e7
feat(DTFS2-7793): update test describe
86507f9
feat(DTFS2-7793): update timestamp discrepancy in unit test
d123c3c
feat(DTFS2-7793): update amendment status controller and unit test
e5b70b8
feat(DTFS2-7793): update unit test describe
eb77c17
feat(DTFS2-7793): remove duplicate effectiveDate in mock
4ea8a37
feat(DTFS2-7793): add middleware unit tests
bdf7d6b
feat(DTFS2-7793): remove obsolete tests from portal api middleware va…
e0cba89
Merge branch 'main' into feat/DTFS2-7793/submit-amendment-to-checker-…
MarRobSoftwire 7016b1c
feat(DTFS2-7793): check no other amendments submitted on deal
88112aa
feat(DTFS2-7793): fix duplicate import after merge
27e7d84
feat(DTFS2-7793): update service unit test
72a7a91
feat(DTFS2-7793): update api test
8209148
feat(DTFS2-7793): code review
fa22f35
feat(DTFS2-7793): add validateNoOtherAmendmentsUnderWayOnDeal unit te…
8c102f0
feat(DTFS2-7793): update test description
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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
233 changes: 233 additions & 0 deletions
233
dtfs-central-api/api-tests/v1/portal-facility-amendments/amendment-status-patch.api-test.ts
This file contains hidden or 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,233 @@ | ||
import { Response } from 'supertest'; | ||
import { ObjectId } from 'mongodb'; | ||
import { HttpStatusCode } from 'axios'; | ||
import { AnyObject, API_ERROR_CODE, DEAL_SUBMISSION_TYPE, DEAL_TYPE, FACILITY_TYPE, MONGO_DB_COLLECTIONS, PORTAL_AMENDMENT_STATUS } from '@ukef/dtfs2-common'; | ||
import { generatePortalAuditDetails } from '@ukef/dtfs2-common/change-stream'; | ||
import { aPortalFacilityAmendmentUserValues } from '@ukef/dtfs2-common/mock-data-backend'; | ||
import wipeDB from '../../wipeDB'; | ||
import { testApi } from '../../test-api'; | ||
import { createDeal, submitDealToTfm } from '../../helpers/create-deal'; | ||
import aDeal from '../deal-builder'; | ||
import { aPortalUser } from '../../mocks/test-users/portal-user'; | ||
import { createPortalUser } from '../../helpers/create-portal-user'; | ||
import { createPortalFacilityAmendment } from '../../helpers/create-portal-facility-amendment'; | ||
import { mongoDbClient as db } from '../../../src/drivers/db-client'; | ||
import { amendmentsEligibilityCriteria } from '../../../test-helpers/test-data/eligibility-criteria-amendments'; | ||
|
||
const originalEnv = { ...process.env }; | ||
|
||
interface ErrorResponse extends Response { | ||
body: { status?: number; message: string; code?: string }; | ||
} | ||
|
||
const generateUrl = (facilityId: string, amendmentId: string): string => { | ||
return `/v1/portal/facilities/${facilityId}/amendments/${amendmentId}/status`; | ||
}; | ||
|
||
const newDeal = aDeal({ | ||
dealType: DEAL_TYPE.GEF, | ||
submissionType: DEAL_SUBMISSION_TYPE.AIN, | ||
}) as AnyObject; | ||
|
||
describe('PATCH /v1/portal/facilities/:facilityId/amendments/:amendmentId/status', () => { | ||
let dealId: string; | ||
let facilityId: string; | ||
let portalUserId: string; | ||
|
||
beforeAll(async () => { | ||
await wipeDB.wipe([MONGO_DB_COLLECTIONS.FACILITIES, MONGO_DB_COLLECTIONS.TFM_FACILITIES, MONGO_DB_COLLECTIONS.ELIGIBILITY_CRITERIA_AMENDMENTS]); | ||
await db | ||
.getCollection(MONGO_DB_COLLECTIONS.ELIGIBILITY_CRITERIA_AMENDMENTS) | ||
.then((collection) => collection.insertOne(amendmentsEligibilityCriteria(1, [FACILITY_TYPE.CASH, FACILITY_TYPE.CONTINGENT]))); | ||
|
||
portalUserId = (await createPortalUser())._id; | ||
}); | ||
|
||
beforeEach(async () => { | ||
const createDealResponse: { body: { _id: string } } = await createDeal({ deal: newDeal, user: aPortalUser() }); | ||
dealId = createDealResponse.body._id; | ||
|
||
const createFacilityResponse: { body: { _id: string } } = await testApi | ||
.post({ dealId, type: FACILITY_TYPE.CASH, hasBeenIssued: false }) | ||
.to('/v1/portal/gef/facilities'); | ||
|
||
facilityId = createFacilityResponse.body._id; | ||
|
||
await submitDealToTfm({ dealId, dealSubmissionType: DEAL_SUBMISSION_TYPE.AIN, dealType: DEAL_TYPE.GEF }); | ||
}); | ||
|
||
afterAll(() => { | ||
process.env = originalEnv; | ||
}); | ||
|
||
describe('when FF_PORTAL_FACILITY_AMENDMENTS_ENABLED is set to `false`', () => { | ||
beforeAll(() => { | ||
process.env.FF_PORTAL_FACILITY_AMENDMENTS_ENABLED = 'false'; | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.NotFound}`, async () => { | ||
const amendmentId = new ObjectId().toString(); | ||
|
||
const { status } = await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus: 'a new status' }) | ||
.to(generateUrl(facilityId, amendmentId)); | ||
|
||
expect(status).toEqual(HttpStatusCode.NotFound); | ||
}); | ||
}); | ||
|
||
describe('when FF_PORTAL_FACILITY_AMENDMENTS_ENABLED is set to `true`', () => { | ||
let amendmentId: string; | ||
|
||
beforeAll(() => { | ||
process.env.FF_PORTAL_FACILITY_AMENDMENTS_ENABLED = 'true'; | ||
}); | ||
|
||
beforeEach(async () => { | ||
const existingAmendment = await createPortalFacilityAmendment({ | ||
facilityId, | ||
dealId, | ||
userId: portalUserId, | ||
amendment: { | ||
...aPortalFacilityAmendmentUserValues(), | ||
eligibilityCriteria: { | ||
criteria: [{ id: 1, text: 'item 1', answer: true }], | ||
version: 1, | ||
}, | ||
}, | ||
}); | ||
|
||
amendmentId = existingAmendment.amendmentId.toString(); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.BadRequest} when the facility id is invalid`, async () => { | ||
const anInvalidFacilityId = 'InvalidId'; | ||
|
||
const { body, status } = (await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus: 'a new status' }) | ||
.to(generateUrl(anInvalidFacilityId, amendmentId))) as ErrorResponse; | ||
|
||
expect(status).toEqual(HttpStatusCode.BadRequest); | ||
|
||
expect(body).toEqual({ | ||
message: "Expected path parameter 'facilityId' to be a valid mongo id", | ||
code: API_ERROR_CODE.INVALID_MONGO_ID_PATH_PARAMETER, | ||
}); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.BadRequest} when the amendment id is invalid`, async () => { | ||
const anInvalidAmendmentId = 'InvalidId'; | ||
|
||
const { body, status } = (await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus: 'a new status' }) | ||
.to(generateUrl(facilityId, anInvalidAmendmentId))) as ErrorResponse; | ||
|
||
expect(status).toEqual(HttpStatusCode.BadRequest); | ||
|
||
expect(body).toEqual({ | ||
message: "Expected path parameter 'amendmentId' to be a valid mongo id", | ||
code: API_ERROR_CODE.INVALID_MONGO_ID_PATH_PARAMETER, | ||
}); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.BadRequest} when the deal id is invalid`, async () => { | ||
const anInvalidDealId = 'dealId'; | ||
|
||
const { body, status } = (await testApi | ||
.patch({ | ||
dealId: anInvalidDealId, | ||
auditDetails: generatePortalAuditDetails(portalUserId), | ||
newStatus: PORTAL_AMENDMENT_STATUS.READY_FOR_CHECKERS_APPROVAL, | ||
}) | ||
.to(generateUrl(facilityId, amendmentId))) as ErrorResponse; | ||
|
||
expect(status).toEqual(HttpStatusCode.BadRequest); | ||
|
||
expect(body).toEqual({ | ||
status: HttpStatusCode.BadRequest, | ||
message: ['dealId: _id must be a valid mongo object id (custom)'], | ||
code: API_ERROR_CODE.INVALID_PAYLOAD, | ||
}); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.BadRequest} when the new status is invalid`, async () => { | ||
const anInvalidStatus = 'a new status'; | ||
|
||
const { body, status } = (await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus: anInvalidStatus }) | ||
.to(generateUrl(facilityId, amendmentId))) as ErrorResponse; | ||
|
||
expect(status).toEqual(HttpStatusCode.BadRequest); | ||
|
||
expect(body).toEqual({ | ||
status: HttpStatusCode.BadRequest, | ||
code: 'INVALID_PAYLOAD', | ||
message: [ | ||
`newStatus: Invalid enum value. Expected '${PORTAL_AMENDMENT_STATUS.READY_FOR_CHECKERS_APPROVAL}', received '${anInvalidStatus}' (invalid_enum_value)`, | ||
], | ||
}); | ||
}); | ||
|
||
describe(`when newStatus is ${PORTAL_AMENDMENT_STATUS.READY_FOR_CHECKERS_APPROVAL}`, () => { | ||
const newStatus = PORTAL_AMENDMENT_STATUS.READY_FOR_CHECKERS_APPROVAL; | ||
|
||
it(`should return ${HttpStatusCode.NotFound} when the facility does not exist`, async () => { | ||
const aValidButNonExistentFacilityId = new ObjectId().toString(); | ||
|
||
const { body, status } = (await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus }) | ||
.to(generateUrl(aValidButNonExistentFacilityId, amendmentId))) as ErrorResponse; | ||
|
||
expect(status).toEqual(HttpStatusCode.NotFound); | ||
expect(body).toEqual({ | ||
status: HttpStatusCode.NotFound, | ||
message: `Facility not found: ${aValidButNonExistentFacilityId}`, | ||
}); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.NotFound} when the amendment does not exist`, async () => { | ||
const aValidButNonExistentAmendmentId = new ObjectId().toString(); | ||
|
||
const { body, status } = (await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus }) | ||
.to(generateUrl(facilityId, aValidButNonExistentAmendmentId))) as ErrorResponse; | ||
|
||
expect(status).toEqual(HttpStatusCode.NotFound); | ||
expect(body).toEqual({ | ||
status: HttpStatusCode.NotFound, | ||
message: `Amendment not found: ${aValidButNonExistentAmendmentId} on facility: ${facilityId}`, | ||
}); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.Conflict} when the amendment is incomplete`, async () => { | ||
// Arrange | ||
const anIncompleteAmendment = await createPortalFacilityAmendment({ | ||
facilityId, | ||
dealId, | ||
userId: portalUserId, | ||
}); | ||
const incompleteAmendmentId = anIncompleteAmendment.amendmentId.toString(); | ||
|
||
// Act | ||
const { body, status } = (await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus }) | ||
.to(generateUrl(facilityId, incompleteAmendmentId))) as ErrorResponse; | ||
|
||
// Assert | ||
expect(status).toEqual(HttpStatusCode.Conflict); | ||
expect(body).toEqual({ | ||
status: HttpStatusCode.Conflict, | ||
message: `Amendment ${incompleteAmendmentId} on facility ${facilityId} is incomplete: neither changeCoverEndDate nor changeFacilityValue is true`, | ||
}); | ||
}); | ||
|
||
it(`should return ${HttpStatusCode.Ok} when the payload is valid & the amendment exists`, async () => { | ||
const { status } = await testApi | ||
.patch({ dealId, auditDetails: generatePortalAuditDetails(portalUserId), newStatus }) | ||
.to(generateUrl(facilityId, amendmentId)); | ||
|
||
expect(status).toEqual(HttpStatusCode.Ok); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains hidden or 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 hidden or 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.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.