Skip to content

Commit bbb1a5c

Browse files
author
Zain Kassam
committed
Merge branch 'main' into feat/FN-3611
2 parents cdf1c4f + 942afea commit bbb1a5c

File tree

46 files changed

+2050
-54
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2050
-54
lines changed

dtfs-central-api/api-tests/v1/utilisation-reports/fee-record-corrections/put-fee-record-correction-transient-form-data.api-test.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { CustomErrorResponse } from '../../../helpers/custom-error-response';
2424
console.error = jest.fn();
2525

2626
interface PutFeeRecordCorrectionTransientFormDataResponse extends Response {
27-
body: RecordCorrectionFormValueValidationErrors | string | undefined;
27+
body: { validationErrors?: RecordCorrectionFormValueValidationErrors } | string;
2828
}
2929

3030
const BASE_URL = '/v1/bank/:bankId/fee-record-corrections/:correctionId/transient-form-data';
@@ -166,30 +166,40 @@ describe(`PUT ${BASE_URL}`, () => {
166166
.to(replaceUrlParameterPlaceholders(BASE_URL, { bankId, correctionId }))) as PutFeeRecordCorrectionTransientFormDataResponse;
167167

168168
// Assert
169-
const expectedBody: RecordCorrectionFormValueValidationErrors = {
169+
const validationErrors: RecordCorrectionFormValueValidationErrors = {
170170
facilityIdErrorMessage: 'You must enter a facility ID between 8 and 10 digits using the numbers 0-9 only',
171171
reportedCurrencyErrorMessage: 'You must select a currency',
172172
reportedFeeErrorMessage: 'You must enter the reported fee in a valid format',
173173
utilisationErrorMessage: 'You must enter the utilisation in a valid format',
174174
additionalCommentsErrorMessage: 'You must enter a comment',
175175
};
176176

177+
const expectedBody = {
178+
validationErrors,
179+
};
180+
177181
expect(status).toEqual(HttpStatusCode.Ok);
178182

179183
expect(body).toEqual(expectedBody);
180184
});
181185
});
182186

183187
describe('when there are no validation errors', () => {
184-
it(`should return '${HttpStatusCode.Ok}' if the correction exists`, async () => {
188+
it(`should return '${HttpStatusCode.Ok}' if the correction exists with an empty response body`, async () => {
185189
// Arrange
186190
const requestBody = aValidRequestBody();
187191

188192
// Act
189-
const { status } = await testApi.put(requestBody).to(replaceUrlParameterPlaceholders(BASE_URL, { bankId, correctionId }));
193+
const { status, body } = (await testApi
194+
.put(requestBody)
195+
.to(replaceUrlParameterPlaceholders(BASE_URL, { bankId, correctionId }))) as PutFeeRecordCorrectionTransientFormDataResponse;
190196

191197
// Assert
198+
const expectedBody = {};
199+
192200
expect(status).toEqual(HttpStatusCode.Ok);
201+
202+
expect(body).toEqual(expectedBody);
193203
});
194204
});
195205
});

dtfs-central-api/src/v1/controllers/utilisation-report-service/fee-record-correction/put-fee-record-correction-transient-form-data.controller/index.test.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,11 @@ describe('put-fee-record-correction-transient-form-data.controller', () => {
122122
additionalCommentsErrorMessage: 'You must enter a comment',
123123
};
124124

125-
expect(res._getData()).toEqual(expectedValidationErrors);
125+
const expectedResponse = {
126+
validationErrors: expectedValidationErrors,
127+
};
128+
129+
expect(res._getData()).toEqual(expectedResponse);
126130
});
127131

128132
it('should not call the correction repo to save the form data', async () => {
@@ -168,6 +172,21 @@ describe('put-fee-record-correction-transient-form-data.controller', () => {
168172
expect(mockSaveTransientFormData).toHaveBeenCalledTimes(1);
169173
expect(mockSaveTransientFormData).toHaveBeenCalledWith(expectedTransientFormDataEntity);
170174
});
175+
176+
it(`should respond with no validation errors in the response body`, async () => {
177+
// Arrange
178+
const correctionReasons = [RECORD_CORRECTION_REASON.OTHER];
179+
180+
mockFindCorrection.mockResolvedValue(FeeRecordCorrectionEntityMockBuilder.forIsCompleted(false).withReasons(correctionReasons).build());
181+
182+
req.body.formData = { additionalComments };
183+
184+
// Act
185+
await putFeeRecordCorrectionTransientFormData(req, res);
186+
187+
// Assert
188+
expect(res._getData()).toEqual({});
189+
});
171190
});
172191

173192
it("should respond with the specific error status if an 'ApiError' is thrown", async () => {

dtfs-central-api/src/v1/controllers/utilisation-report-service/fee-record-correction/put-fee-record-correction-transient-form-data.controller/index.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ApiError, FeeRecordCorrectionTransientFormDataEntity, REQUEST_PLATFORM_TYPE } from '@ukef/dtfs2-common';
1+
import { ApiError, FeeRecordCorrectionTransientFormDataEntity, RecordCorrectionFormValueValidationErrors, REQUEST_PLATFORM_TYPE } from '@ukef/dtfs2-common';
22
import { HttpStatusCode } from 'axios';
33
import { Response } from 'express';
44
import { CustomExpressRequest } from '../../../../../types/custom-express-request';
@@ -16,6 +16,12 @@ export type PutFeeRecordCorrectionTransientFormDataRequest = CustomExpressReques
1616
reqBody: PutFeeRecordCorrectionTransientFormDataPayload;
1717
}>;
1818

19+
type PutFeeRecordCorrectionTransientFormDataResponseBody = {
20+
validationErrors?: RecordCorrectionFormValueValidationErrors;
21+
};
22+
23+
type PutFeeRecordCorrectionTransientFormDataResponse = Response<PutFeeRecordCorrectionTransientFormDataResponseBody | string>;
24+
1925
/**
2026
* Controller for the PUT fee record correction transient form data route.
2127
*
@@ -26,9 +32,12 @@ export type PutFeeRecordCorrectionTransientFormDataRequest = CustomExpressReques
2632
* If there are no validation errors, creates a new fee record correction transient
2733
* form data entity with the correction id, user id and form data, and saves it.
2834
* @param req - The {@link PutFeeRecordCorrectionTransientFormDataRequest} request object
29-
* @param res - The response object
35+
* @param res - The {@link PutFeeRecordCorrectionTransientFormDataResponse} response object
3036
*/
31-
export const putFeeRecordCorrectionTransientFormData = async (req: PutFeeRecordCorrectionTransientFormDataRequest, res: Response) => {
37+
export const putFeeRecordCorrectionTransientFormData = async (
38+
req: PutFeeRecordCorrectionTransientFormDataRequest,
39+
res: PutFeeRecordCorrectionTransientFormDataResponse,
40+
) => {
3241
try {
3342
const { correctionId: correctionIdString, bankId } = req.params;
3443
const { user, formData } = req.body;
@@ -42,10 +51,10 @@ export const putFeeRecordCorrectionTransientFormData = async (req: PutFeeRecordC
4251
throw new NotFoundError(`Failed to find a correction with id '${correctionId}' for bank id '${bankId}'`);
4352
}
4453

45-
const { formHasErrors, errors } = await validateRecordCorrectionTransientFormValues(formData, correction.reasons);
54+
const { formHasErrors, errors: validationErrors } = await validateRecordCorrectionTransientFormValues(formData, correction.reasons);
4655

4756
if (formHasErrors) {
48-
return res.status(HttpStatusCode.Ok).send(errors);
57+
return res.status(HttpStatusCode.Ok).send({ validationErrors });
4958
}
5059

5160
const parsedFormData = parseValidatedRecordCorrectionTransientFormValues(formData);
@@ -62,7 +71,7 @@ export const putFeeRecordCorrectionTransientFormData = async (req: PutFeeRecordC
6271

6372
await FeeRecordCorrectionTransientFormDataRepo.save(newTransientFormData);
6473

65-
return res.sendStatus(HttpStatusCode.Ok);
74+
return res.status(HttpStatusCode.Ok).send({});
6675
} catch (error) {
6776
const errorMessage = 'Failed to put fee record correction transient form data';
6877
console.error('%s %o', errorMessage, error);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const doYouHaveAFacilityEndDate = {
2+
yesRadioButton: () => cy.get('[data-cy="is-using-facility-end-date-yes"]'),
3+
noRadioButton: () => cy.get('[data-cy="is-using-facility-end-date-no"]'),
4+
errorSummary: () => cy.get('[data-cy="error-summary"]'),
5+
inlineError: () => cy.get('[data-cy="is-using-facility-end-date-error"]'),
6+
pageHeading: () => cy.get('[data-cy="page-heading"]'),
7+
backLink: () => cy.get('[data-cy="back-link"]'),
8+
};
9+
10+
module.exports = doYouHaveAFacilityEndDate;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const facilityEndDate = {
2+
facilityEndDateDay: () => cy.get('[data-cy="facility-end-date-day"]'),
3+
facilityEndDateMonth: () => cy.get('[data-cy="facility-end-date-month"]'),
4+
facilityEndDateYear: () => cy.get('[data-cy="facility-end-date-year"]'),
5+
errorSummary: () => cy.get('[data-cy="error-summary"]'),
6+
facilityEndDateInlineError: () => cy.get('[data-cy="facility-end-date-inline-error"]'),
7+
pageHeading: () => cy.get('[data-cy="page-heading"]'),
8+
backLink: () => cy.get('[data-cy="back-link"]'),
9+
cancelLink: () => cy.get('[data-cy="cancel-link"]'),
10+
};
11+
12+
module.exports = facilityEndDate;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import {
2+
UtilisationReportEntityMockBuilder,
3+
FeeRecordCorrectionEntityMockBuilder,
4+
PENDING_RECONCILIATION,
5+
FeeRecordEntityMockBuilder,
6+
FEE_RECORD_STATUS,
7+
RECORD_CORRECTION_REASON,
8+
CURRENCY,
9+
mapReasonsToDisplayValues,
10+
} from '@ukef/dtfs2-common';
11+
import { NODE_TASKS, BANK1_PAYMENT_REPORT_OFFICER1 } from '../../../../../../../e2e-fixtures';
12+
import relative from '../../../../relativeURL';
13+
import { provideCorrection, pendingCorrections, reviewCorrection } from '../../../../pages';
14+
15+
context('Check the information page - Fee record correction feature flag enabled', () => {
16+
context('When a correction has been provided', () => {
17+
const reportPeriod = { start: { month: 1, year: 2021 }, end: { month: 1, year: 2021 } };
18+
19+
const reasons = [
20+
RECORD_CORRECTION_REASON.UTILISATION_INCORRECT,
21+
RECORD_CORRECTION_REASON.REPORTED_CURRENCY_INCORRECT,
22+
RECORD_CORRECTION_REASON.REPORTED_FEE_INCORRECT,
23+
];
24+
const pdcErrorSummary = 'Some PDC error summary';
25+
26+
const exporter = 'An exporter';
27+
const oldUtilisation = 987.65;
28+
const oldReportedFees = {
29+
currency: CURRENCY.GBP,
30+
amount: 123.45,
31+
};
32+
33+
const newUtilisation = 100.23;
34+
const newReportedFees = {
35+
currency: CURRENCY.USD,
36+
amount: 543.21,
37+
};
38+
const bankAdditionalComments = 'Some additional bank comments';
39+
40+
beforeEach(() => {
41+
cy.task(NODE_TASKS.DELETE_ALL_FROM_SQL_DB);
42+
43+
cy.task('getUserFromDbByEmail', BANK1_PAYMENT_REPORT_OFFICER1.email).then((user) => {
44+
const { _id, bank } = user;
45+
const bankId = bank.id;
46+
47+
const report = UtilisationReportEntityMockBuilder.forStatus(PENDING_RECONCILIATION)
48+
.withUploadedByUserId(_id.toString())
49+
.withBankId(bankId)
50+
.withReportPeriod(reportPeriod)
51+
.build();
52+
53+
const feeRecord = FeeRecordEntityMockBuilder.forReport(report)
54+
.withStatus(FEE_RECORD_STATUS.PENDING_CORRECTION)
55+
.withExporter(exporter)
56+
.withFacilityUtilisation(oldUtilisation)
57+
.withFeesPaidToUkefForThePeriod(oldReportedFees.amount)
58+
.withFeesPaidToUkefForThePeriodCurrency(oldReportedFees.currency)
59+
.build();
60+
61+
const pendingCorrection = FeeRecordCorrectionEntityMockBuilder.forFeeRecordAndIsCompleted(feeRecord, false)
62+
.withId(3)
63+
.withReasons(reasons)
64+
.withAdditionalInfo(pdcErrorSummary)
65+
.build();
66+
67+
cy.task(NODE_TASKS.INSERT_UTILISATION_REPORTS_INTO_DB, [report]);
68+
cy.task(NODE_TASKS.INSERT_FEE_RECORDS_INTO_DB, [feeRecord]);
69+
cy.task(NODE_TASKS.INSERT_FEE_RECORD_CORRECTIONS_INTO_DB, [pendingCorrection]);
70+
});
71+
72+
cy.login(BANK1_PAYMENT_REPORT_OFFICER1);
73+
cy.visit(relative(`/utilisation-report-upload`));
74+
75+
pendingCorrections.row(1).correctionLink().click();
76+
77+
provideCorrection.reportedCurrency.radioInput(newReportedFees.currency).click();
78+
cy.keyboardInput(provideCorrection.reportedFeeInput(), newReportedFees.amount);
79+
cy.keyboardInput(provideCorrection.utilisationInput(), newUtilisation);
80+
cy.keyboardInput(provideCorrection.additionalComments.input(), bankAdditionalComments);
81+
82+
cy.clickContinueButton();
83+
});
84+
85+
after(() => {
86+
cy.task(NODE_TASKS.DELETE_ALL_FROM_SQL_DB);
87+
});
88+
89+
it('should be able to view the form values and other details of correction request', () => {
90+
reviewCorrection.originalValuesSummaryList().should('exist');
91+
reviewCorrection.originalValuesSummaryList().should('contain', exporter);
92+
reviewCorrection.originalValuesSummaryList().should('contain', oldReportedFees.currency);
93+
reviewCorrection.originalValuesSummaryList().should('contain', oldReportedFees.amount);
94+
95+
const expectedCorrectionReasons = mapReasonsToDisplayValues(reasons).join(', ');
96+
const expectedOldValues = `${oldUtilisation}, ${oldReportedFees.currency}, ${oldReportedFees.amount}`;
97+
const expectedNewValues = `${newUtilisation}, ${newReportedFees.currency}, ${newReportedFees.amount}`;
98+
99+
reviewCorrection.recordCorrectionDetailsSummaryList().should('exist');
100+
reviewCorrection.recordCorrectionDetailsSummaryList().should('contain', expectedCorrectionReasons);
101+
reviewCorrection.recordCorrectionDetailsSummaryList().should('contain', pdcErrorSummary);
102+
reviewCorrection.recordCorrectionDetailsSummaryList().should('contain', expectedOldValues);
103+
reviewCorrection.recordCorrectionDetailsSummaryList().should('contain', expectedNewValues);
104+
reviewCorrection.recordCorrectionDetailsSummaryList().should('contain', bankAdditionalComments);
105+
});
106+
107+
context('and when the user clicks cancel', () => {
108+
beforeEach(() => {
109+
cy.clickCancelButton();
110+
});
111+
112+
it('should redirect to the "Report GEF utilisation and fees paid" page', () => {
113+
cy.url().should('eq', relative('/utilisation-report-upload'));
114+
});
115+
});
116+
});
117+
});

e2e-tests/portal/cypress/e2e/journeys/payment-report-officer/record-corrections/feature-flag-enabled/provide-correction.spec.js

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,54 @@ context('Provide correction - Fee record correction feature flag enabled', () =>
105105
provideCorrection.additionalComments.input().should('exist');
106106
});
107107

108-
context('and when the user has entered values and clicked save and review changes', () => {
108+
context('and when the user has entered invalid values and clicked "save and review changes"', () => {
109+
const newFacilityId = 'abc';
110+
const newReportedFee = 'INVALID';
111+
const additionalComments = ' ';
112+
113+
beforeEach(() => {
114+
cy.keyboardInput(provideCorrection.facilityIdInput(), newFacilityId);
115+
cy.keyboardInput(provideCorrection.reportedFeeInput(), newReportedFee);
116+
cy.keyboardInput(provideCorrection.additionalComments.input(), additionalComments);
117+
118+
cy.clickContinueButton();
119+
});
120+
121+
it('should display the validation errors', () => {
122+
const expectedFacilityIdInputError = 'Error: You must enter a facility ID between 8 and 10 digits using the numbers 0-9 only';
123+
const expectedReportedCurrencyError = 'Error: You must select a currency';
124+
const expectedReportedFeeInputError = 'Error: You must enter the reported fee in a valid format';
125+
const expectedAdditionalCommentsError = 'Error: You must enter a comment';
126+
127+
provideCorrection.errorSummaryItems().should('have.length', 4);
128+
129+
provideCorrection.facilityIdError().should('exist');
130+
cy.assertText(provideCorrection.facilityIdError(), expectedFacilityIdInputError);
131+
132+
provideCorrection.reportedCurrency.error().should('exist');
133+
cy.assertText(provideCorrection.reportedCurrency.error(), expectedReportedCurrencyError);
134+
135+
provideCorrection.reportedFeeError().should('exist');
136+
cy.assertText(provideCorrection.reportedFeeError(), expectedReportedFeeInputError);
137+
138+
provideCorrection.utilisationError().should('not.exist');
139+
140+
provideCorrection.additionalComments.error().should('exist');
141+
cy.assertText(provideCorrection.additionalComments.error(), expectedAdditionalCommentsError);
142+
});
143+
144+
it('should retain the values entered by the user', () => {
145+
provideCorrection.facilityIdInput().should('have.value', newFacilityId);
146+
provideCorrection.reportedFeeInput().should('have.value', newReportedFee);
147+
provideCorrection.additionalComments.input().should('have.value', additionalComments);
148+
149+
Object.values(CURRENCY).forEach((currency) => {
150+
provideCorrection.reportedCurrency.radioInput(currency).should('not.be.checked');
151+
});
152+
});
153+
});
154+
155+
context('and when the user has entered valid values and clicked "save and review changes"', () => {
109156
const newFacilityId = '77777777';
110157
const newReportedFee = '12345.67';
111158
const newReportedCurrency = CURRENCY.JPY;
@@ -130,6 +177,10 @@ context('Provide correction - Fee record correction feature flag enabled', () =>
130177
cy.clickContinueButton();
131178
});
132179

180+
it('should redirect to the review page', () => {
181+
cy.url().should('eq', relative(`/utilisation-reports/provide-correction/${pendingCorrectionDetails.id}/check-the-information`));
182+
});
183+
133184
it('should retain the values entered by the user when they return to the page via the review page back link', () => {
134185
cy.clickBackLink();
135186

@@ -170,6 +221,16 @@ context('Provide correction - Fee record correction feature flag enabled', () =>
170221
provideCorrection.additionalComments.input().should('have.value', '');
171222
});
172223
});
224+
225+
context('and when the user clicks cancel', () => {
226+
beforeEach(() => {
227+
cy.clickCancelButton();
228+
});
229+
230+
it('should redirect to the "Report GEF utilisation and fees paid" page', () => {
231+
cy.url().should('eq', relative('/utilisation-report-upload'));
232+
});
233+
});
173234
});
174235
});
175236
});
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
const page = {
22
facilityIdInput: () => cy.get('input[data-cy="FACILITY_ID_INCORRECT-input"]'),
3+
facilityIdError: () => cy.get('[data-cy="FACILITY_ID_INCORRECT-error"]'),
34
reportedCurrency: {
45
container: () => cy.get('[data-cy="REPORTED_CURRENCY_INCORRECT-input"]'),
56
radioInput: (currency) => cy.get(`input[data-cy="currency-${currency}"]`),
7+
error: () => cy.get('[data-cy="REPORTED_CURRENCY_INCORRECT-error"]'),
68
},
79
reportedFeeInput: () => cy.get('input[data-cy="REPORTED_FEE_INCORRECT-input"]'),
10+
reportedFeeError: () => cy.get('[data-cy="REPORTED_FEE_INCORRECT-error"]'),
811
utilisationInput: () => cy.get('input[data-cy="UTILISATION_INCORRECT-input"]'),
12+
utilisationError: () => cy.get('[data-cy="UTILISATION_INCORRECT-error"]'),
913
additionalComments: {
1014
input: () => cy.get(`textarea[data-cy="additional-comments-input"]`),
1115
label: () => cy.get(`[data-cy="additional-comments-label"]`),
1216
hint: () => cy.get(`[data-cy="additional-comments-hint"]`),
17+
error: () => cy.get('[data-cy="additional-comments-error"]'),
1318
},
19+
errorSummary: () => cy.get('[data-cy="error-summary"]'),
20+
errorSummaryItems: () => cy.get('[data-cy="error-summary"] li'),
1421
};
1522

1623
module.exports = page;

0 commit comments

Comments
 (0)