Skip to content

Commit fe802ca

Browse files
#3620 - Change Request - Partner Current Year Income (financial information) option (#3799)
- Added a new question to the Partner Information and Income to allow students to submit partner income for the current year. - Replaced "YEAR" with dynamic outcome with following logic: - Updated the Camunda workflow to reflect new priority list for partner income. - Moved the "Define partner income" in the workflow after the appeals to use the appeals' calculated variables - Converted the current logic inside "Define Partner Income" to a flow - Created E2E tests for partner current year income. - For API: "Should save the current year partner income when the student submits an appeal for the current year partner income." - For workflow: "Should calculate partner income as current year partner income value when there is a request a change for current year partner income." Screenshots of current year partner income UI ![image](https://github.com/user-attachments/assets/fe5b22e0-be24-48af-80b5-78048386762e) ![image](https://github.com/user-attachments/assets/0de431e0-a3d6-46c8-aa16-9a3246fd1aa7) Screenshot of Camunda workflow ![image](https://github.com/user-attachments/assets/20db3de1-a8c4-4d65-93c9-5c7cdf5c5a8c)
1 parent 2926208 commit fe802ca

File tree

9 files changed

+4559
-2992
lines changed

9 files changed

+4559
-2992
lines changed

Diff for: sources/packages/backend/apps/api/src/route-controllers/student-appeal/_tests_/e2e/student-appeal.students.controller.submitStudentAppeal.e2e-spec.ts

+102
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ describe("StudentAppealStudentsController(e2e)-submitStudentAppeal", () => {
4747
let studentFileRepo: Repository<StudentFile>;
4848
const FINANCIAL_INFORMATION_FORM_NAME = "studentfinancialinformationappeal";
4949
const DEPENDANT_INFORMATION_FORM_NAME = "studentDependantsAppeal";
50+
const PARTNER_INFORMATION_FORM_NAME = "partnerinformationandincomeappeal";
5051

5152
beforeAll(async () => {
5253
const { nestApplication, module, dataSource } =
@@ -501,6 +502,107 @@ describe("StudentAppealStudentsController(e2e)-submitStudentAppeal", () => {
501502
);
502503
});
503504

505+
it("Should save the current year partner income when the student submits an appeal for the current year partner income.", async () => {
506+
// Arrange
507+
const application = await saveFakeApplication(appDataSource, undefined, {
508+
applicationStatus: ApplicationStatus.Completed,
509+
});
510+
// Create a current year partner income file.
511+
const partnerIncomeFile = await saveFakeStudentFileUpload(
512+
appDataSource,
513+
{
514+
student: application.student,
515+
creator: application.student.user,
516+
},
517+
{ fileOrigin: FileOriginType.Temporary },
518+
);
519+
// Prepare the data to request a change of current year partner income.
520+
const partnerIncomeInformationData = {
521+
programYear: application.programYear.programYear,
522+
relationshipStatus: "married",
523+
partnerEstimatedIncome: 1000,
524+
currentYearPartnerIncome: 2000,
525+
reasonsignificantdecreaseInPartnerIncome: "other",
526+
decreaseInPartnerIncomeSupportingDocuments: [
527+
{
528+
storage: "url",
529+
originalName: partnerIncomeFile.fileName,
530+
name: partnerIncomeFile.uniqueFileName,
531+
url: "student/files/" + partnerIncomeFile.uniqueFileName,
532+
size: 0,
533+
type: "text/plain",
534+
hash: "1cb251ec0d568de6a929b520c4aed8d1",
535+
},
536+
],
537+
otherExceptionalPartnerCircumstance: "any",
538+
};
539+
540+
const payload: StudentAppealAPIInDTO = {
541+
studentAppealRequests: [
542+
{
543+
formName: PARTNER_INFORMATION_FORM_NAME,
544+
formData: partnerIncomeInformationData,
545+
files: [partnerIncomeFile.uniqueFileName],
546+
},
547+
],
548+
};
549+
// Mock user service to return the saved student.
550+
await mockUserLoginInfo(appModule, application.student);
551+
// Get any student user token.
552+
const studentToken = await getStudentToken(
553+
FakeStudentUsersTypes.FakeStudentUserType1,
554+
);
555+
// Mock the form service to validate the dry-run submission result.
556+
const formService = await getProviderInstanceForModule(
557+
appModule,
558+
AppStudentsModule,
559+
FormService,
560+
);
561+
const dryRunSubmissionMock = jest.fn().mockResolvedValue({
562+
valid: true,
563+
formName: PARTNER_INFORMATION_FORM_NAME,
564+
data: { data: partnerIncomeInformationData },
565+
});
566+
567+
formService.dryRunSubmission = dryRunSubmissionMock;
568+
569+
const endpoint = `/students/appeal/application/${application.id}`;
570+
571+
// Act/Assert
572+
let createdAppealId: number;
573+
await request(app.getHttpServer())
574+
.post(endpoint)
575+
.auth(studentToken, BEARER_AUTH_TYPE)
576+
.send(payload)
577+
.expect(HttpStatus.CREATED)
578+
.expect((response) => {
579+
expect(response.body.id).toBeGreaterThan(0);
580+
createdAppealId = +response.body.id;
581+
});
582+
583+
// Expect created student appeal request data to be the same in the payload.
584+
const newStudentAppealRequest = await studentAppealRequestRepo.findOne({
585+
where: { studentAppeal: { id: createdAppealId } },
586+
});
587+
expect(newStudentAppealRequest.submittedData).toStrictEqual(
588+
payload.studentAppealRequests[0].formData,
589+
);
590+
// Expect the file origin type to be Appeal for the updated current year partner income file.
591+
const updatedPartnerIncomeFile = await studentFileRepo.findOne({
592+
where: { id: partnerIncomeFile.id },
593+
});
594+
expect(updatedPartnerIncomeFile.fileOrigin).toBe(FileOriginType.Appeal);
595+
596+
// Expect to call the dry run submission.
597+
expect(dryRunSubmissionMock).toHaveBeenCalledWith(
598+
PARTNER_INFORMATION_FORM_NAME,
599+
{
600+
...partnerIncomeInformationData,
601+
programYear: application.programYear.programYear,
602+
},
603+
);
604+
});
605+
504606
afterAll(async () => {
505607
await app?.close();
506608
});

Diff for: sources/packages/backend/workflow/src/workflow-definitions/parttime-assessment-2022-2023.bpmn

+1,009-951
Large diffs are not rendered by default.

Diff for: sources/packages/backend/workflow/src/workflow-definitions/parttime-assessment-2023-2024.bpmn

+992-934
Large diffs are not rendered by default.

Diff for: sources/packages/backend/workflow/src/workflow-definitions/parttime-assessment-2024-2025.bpmn

+1,075-1,017
Large diffs are not rendered by default.

Diff for: sources/packages/backend/workflow/test/2022-2023/parttime-assessment/appeals/parttime-assessment-partner-information-and-income.e2e-spec.ts

+52
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,56 @@ describe(`E2E Test Workflow parttime-assessment-${PROGRAM_YEAR}-partner-informat
124124
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
125125
).toBeNull();
126126
});
127+
128+
it("Should calculate partner income as current year partner income value when there is a request a change for current year partner income.", async () => {
129+
// Arrange
130+
const assessmentConsolidatedData =
131+
createFakeConsolidatedPartTimeData(PROGRAM_YEAR);
132+
assessmentConsolidatedData.partner1CRAReportedIncome = 3000;
133+
assessmentConsolidatedData.appealsPartnerInformationAndIncomeAppealData = {
134+
relationshipStatus: "married",
135+
partnerEstimatedIncome: 1000,
136+
currentYearPartnerIncome: 2000,
137+
};
138+
139+
// Act
140+
const calculatedAssessment = await executePartTimeAssessmentForProgramYear(
141+
PROGRAM_YEAR,
142+
assessmentConsolidatedData,
143+
);
144+
145+
// Assert
146+
expect(
147+
calculatedAssessment.variables.calculatedDataCurrentYearPartnerIncome,
148+
).toBe(2000);
149+
expect(
150+
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
151+
).toBe(2000);
152+
});
153+
154+
it("Should calculate partner income as current year partner income value when there is a request a change for current year partner income and the partner's total income is provided.", async () => {
155+
// Arrange
156+
const assessmentConsolidatedData =
157+
createFakeConsolidatedPartTimeData(PROGRAM_YEAR);
158+
assessmentConsolidatedData.partner1TotalIncome = 4000;
159+
assessmentConsolidatedData.appealsPartnerInformationAndIncomeAppealData = {
160+
relationshipStatus: "married",
161+
partnerEstimatedIncome: 1000,
162+
currentYearPartnerIncome: 2000,
163+
};
164+
165+
// Act
166+
const calculatedAssessment = await executePartTimeAssessmentForProgramYear(
167+
PROGRAM_YEAR,
168+
assessmentConsolidatedData,
169+
);
170+
171+
// Assert
172+
expect(
173+
calculatedAssessment.variables.calculatedDataCurrentYearPartnerIncome,
174+
).toBe(2000);
175+
expect(
176+
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
177+
).toBe(2000);
178+
});
127179
});

Diff for: sources/packages/backend/workflow/test/2023-2024/parttime-assessment/appeals/parttime-assessment-partner-information-and-income.e2e-spec.ts

+52
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,56 @@ describe(`E2E Test Workflow parttime-assessment-${PROGRAM_YEAR}-partner-informat
124124
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
125125
).toBeNull();
126126
});
127+
128+
it("Should calculate partner income as current year partner income value when there is a request a change for current year partner income.", async () => {
129+
// Arrange
130+
const assessmentConsolidatedData =
131+
createFakeConsolidatedPartTimeData(PROGRAM_YEAR);
132+
assessmentConsolidatedData.partner1CRAReportedIncome = 3000;
133+
assessmentConsolidatedData.appealsPartnerInformationAndIncomeAppealData = {
134+
relationshipStatus: "married",
135+
partnerEstimatedIncome: 1000,
136+
currentYearPartnerIncome: 2000,
137+
};
138+
139+
// Act
140+
const calculatedAssessment = await executePartTimeAssessmentForProgramYear(
141+
PROGRAM_YEAR,
142+
assessmentConsolidatedData,
143+
);
144+
145+
// Assert
146+
expect(
147+
calculatedAssessment.variables.calculatedDataCurrentYearPartnerIncome,
148+
).toBe(2000);
149+
expect(
150+
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
151+
).toBe(2000);
152+
});
153+
154+
it("Should calculate partner income as current year partner income value when there is a request a change for current year partner income and the partner's total income is provided.", async () => {
155+
// Arrange
156+
const assessmentConsolidatedData =
157+
createFakeConsolidatedPartTimeData(PROGRAM_YEAR);
158+
assessmentConsolidatedData.partner1TotalIncome = 4000;
159+
assessmentConsolidatedData.appealsPartnerInformationAndIncomeAppealData = {
160+
relationshipStatus: "married",
161+
partnerEstimatedIncome: 1000,
162+
currentYearPartnerIncome: 2000,
163+
};
164+
165+
// Act
166+
const calculatedAssessment = await executePartTimeAssessmentForProgramYear(
167+
PROGRAM_YEAR,
168+
assessmentConsolidatedData,
169+
);
170+
171+
// Assert
172+
expect(
173+
calculatedAssessment.variables.calculatedDataCurrentYearPartnerIncome,
174+
).toBe(2000);
175+
expect(
176+
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
177+
).toBe(2000);
178+
});
127179
});

Diff for: sources/packages/backend/workflow/test/2024-2025/parttime-assessment/appeals/parttime-assessment-partner-information-and-income.e2e-spec.ts

+52
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,56 @@ describe(`E2E Test Workflow parttime-assessment-${PROGRAM_YEAR}-partner-informat
124124
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
125125
).toBeNull();
126126
});
127+
128+
it("Should calculate partner income as current year partner income value when there is a request a change for current year partner income.", async () => {
129+
// Arrange
130+
const assessmentConsolidatedData =
131+
createFakeConsolidatedPartTimeData(PROGRAM_YEAR);
132+
assessmentConsolidatedData.partner1CRAReportedIncome = 3000;
133+
assessmentConsolidatedData.appealsPartnerInformationAndIncomeAppealData = {
134+
relationshipStatus: "married",
135+
partnerEstimatedIncome: 1000,
136+
currentYearPartnerIncome: 2000,
137+
};
138+
139+
// Act
140+
const calculatedAssessment = await executePartTimeAssessmentForProgramYear(
141+
PROGRAM_YEAR,
142+
assessmentConsolidatedData,
143+
);
144+
145+
// Assert
146+
expect(
147+
calculatedAssessment.variables.calculatedDataCurrentYearPartnerIncome,
148+
).toBe(2000);
149+
expect(
150+
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
151+
).toBe(2000);
152+
});
153+
154+
it("Should calculate partner income as current year partner income value when there is a request a change for current year partner income and the partner's total income is provided.", async () => {
155+
// Arrange
156+
const assessmentConsolidatedData =
157+
createFakeConsolidatedPartTimeData(PROGRAM_YEAR);
158+
assessmentConsolidatedData.partner1TotalIncome = 4000;
159+
assessmentConsolidatedData.appealsPartnerInformationAndIncomeAppealData = {
160+
relationshipStatus: "married",
161+
partnerEstimatedIncome: 1000,
162+
currentYearPartnerIncome: 2000,
163+
};
164+
165+
// Act
166+
const calculatedAssessment = await executePartTimeAssessmentForProgramYear(
167+
PROGRAM_YEAR,
168+
assessmentConsolidatedData,
169+
);
170+
171+
// Assert
172+
expect(
173+
calculatedAssessment.variables.calculatedDataCurrentYearPartnerIncome,
174+
).toBe(2000);
175+
expect(
176+
calculatedAssessment.variables.calculatedDataPartner1TotalIncome,
177+
).toBe(2000);
178+
});
127179
});

Diff for: sources/packages/backend/workflow/test/models/assessment.model.ts

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface StudentFinancialInformationAppealData extends JSONDoc {
2121
currentYearIncome?: number;
2222
daycareCosts12YearsOrOver?: number;
2323
daycareCosts11YearsOrUnder?: number;
24+
currentYearPartnerIncome?: number;
2425
}
2526

2627
export enum TransportationCostSituation {
@@ -44,6 +45,7 @@ export type RelationshipStatusType = "single" | "other" | "married";
4445
export interface PartnerInformationAndIncomeAppealData extends JSONDoc {
4546
relationshipStatus: RelationshipStatusType;
4647
partnerEstimatedIncome?: number;
48+
currentYearPartnerIncome?: number;
4749
}
4850

4951
export enum CredentialType {
@@ -273,6 +275,8 @@ export interface CalculatedAssessmentModel {
273275
calculatedDataTaxReturnIncome: number;
274276
calculatedDataCurrentYearIncome: number;
275277
calculatedDataStudentTotalIncome: number;
278+
calculatedDataCurrentYearPartnerIncome: number;
279+
partner1CRAReportedIncome?: number;
276280

277281
// Common variables used in both full-time and part-time.
278282
// CSGP

0 commit comments

Comments
 (0)