Skip to content

Commit

Permalink
#2672 - Assessment Gateway Inputs for Program Year Awards Consumed (#…
Browse files Browse the repository at this point in the history
…2817)

Changed the processes for workers `VerifyAssessmentCalculationOrder` and
`WorkflowWrapUp` to allow:
- The SUM of awards for past applications.
- Checking future impacted applications to create reassessments.

### Changes in worker `VerifyAssessmentCalculationOrder`
- The output DTO now allows adding dynamic properties besides the
required `isReadyForCalculation`.
- A new dynamic property will be created for every grant award present
in previous applications for the same student and same program year. The
grants totals will be grouped per offering intensity, and they will be
displayed following the examples below.
  - programYearTotalFullTimeCSGD
  - programYearTotalFullTimeCSGP 
  - programYearTotalFullTimeSBSD 
  - programYearTotalFullTimeBCAG
  - programYearTotalFullTimeSBSD
  - programYearTotalPartTimeCSGD
  - programYearTotalPartTimeCSGP 
  - programYearTotalPartTimeSBSD 
  - programYearTotalPartTimeBCAG
  - programYearTotalPartTimeSBSD
- The totals are returned by a new method
`getProgramYearPreviousAwardsTotals` that uses the same centralized
logic to determine the past applications (`getSequencedApplications`)
introduced in the previous PR #2732
- Having the awards segregated per intensity would allow the workflow to
decide which ones must be combined. For instance, the values for CSGP
and SBSD will be added together later to process the assessment
calculations while grants like CSPT, CSGD, and BCAG will have their
values added per offering intensity. In this way, the worker's
responsibility is to provide the granular total while the workflow
responsibility is to decide how to SUM them.
- The method `getSequencedApplications` was changed to optionally
receive a "reference date" that is needed to determine the past
applications when the application being verified was never calculated
(doesn't have an assessment date) needed to place this application into
the chronology order.

#### E2E Tests
- Should sum the grants from two past applications with different
offering intensities when the applications are for the same student and
program year.
- Should consider the grant from only one disbursement from a valid past
application when the past application has two disbursements and the
second COE is declined.
- Should not return any program year total awards when there are no
applications in the past for the same student and program year.

### Changes in worker `WorkflowWrapUp`
- Added the previously created method
`assessImpactedApplicationReassessmentNeeded` to the `WorkflowWrapUp`
worker to ensure that a future application (if any) will be reassessed.
- The method `updateAssessmentStatusAndSaveWorkflowData` is executed in
a transaction with `assessImpactedApplicationReassessmentNeeded` to
ensure that they will rollback together in case an error happen, which
would allow the worker to be retried.
- The method `updateAssessmentStatusAndSaveWorkflowData` is now used to
ensure the worker idempotency.

#### E2E Tests
- Should find the next impacted assessment and create a reassessment
when there is an application for the same student and program year in
the future.
- Should return job completed when the workflow data is already set.

### E2E Tests Global
- Created the method `getOutputVariables` to allow the assertion of
output variables sent to Camunda.
- Created the method `getResultType` to replace the previous way of
checking the job result status.
  • Loading branch information
andrewsignori-aot authored Feb 15, 2024
1 parent 8e243e2 commit db070bb
Show file tree
Hide file tree
Showing 10 changed files with 796 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
import {
createE2EDataSources,
createFakeDisbursementValue,
E2EDataSources,
saveFakeApplicationDisbursements,
saveFakeStudent,
} from "@sims/test-utils";
import {
FakeWorkerJobResult,
MockedZeebeJobResult,
} from "../../../../../test/utils/worker-job-mock";
import { createTestingAppModule } from "../../../../../test/helpers";
import { AssessmentController } from "../../assessment.controller";
import {
ApplicationStatus,
COEStatus,
DisbursementValueType,
OfferingIntensity,
StudentAssessmentStatus,
} from "@sims/sims-db";
import { addDays } from "@sims/utilities";
import { createFakeVerifyAssessmentCalculationOrderPayload } from "./verify-assessment-calculation-order-factory";

describe("AssessmentController(e2e)-verifyAssessmentCalculationOrder", () => {
let db: E2EDataSources;
let assessmentController: AssessmentController;

beforeAll(async () => {
const { nestApplication, dataSource } = await createTestingAppModule();
db = createE2EDataSources(dataSource);
assessmentController = nestApplication.get(AssessmentController);
});

it("Should sum the grants from two past applications with different offering intensities when the applications are for the same student and program year.", async () => {
// Arrange

// Create the student to be shared across the applications.
const student = await saveFakeStudent(db.dataSource);
// Past part-time application with federal and provincial loans and grants.
// Loans will be ignored.
await saveFakeApplicationDisbursements(
db.dataSource,
{
student,
firstDisbursementValues: [
createFakeDisbursementValue(
DisbursementValueType.CanadaLoan,
"CSLP",
1,
),
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSPT",
2,
),
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSGD",
3,
),
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSGP",
4,
),
// Should not be disbursed due to BCLM restriction.
createFakeDisbursementValue(DisbursementValueType.BCLoan, "BCSL", 5),
createFakeDisbursementValue(DisbursementValueType.BCGrant, "SBSD", 6),
// Should not be disbursed due to BCLM restriction.
createFakeDisbursementValue(DisbursementValueType.BCGrant, "BCAG", 7),
],
},
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.Completed,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
assessmentDate: addDays(-2),
studentAssessmentStatus: StudentAssessmentStatus.Completed,
},
},
);
// Past full-time application with federal and provincial loans and grants.
// Loans will be ignored.
await saveFakeApplicationDisbursements(
db.dataSource,
{
student,
firstDisbursementValues: [
createFakeDisbursementValue(
DisbursementValueType.CanadaLoan,
"CSLF",
8,
),
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSGD",
9,
),
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSGP",
10,
),
createFakeDisbursementValue(DisbursementValueType.BCLoan, "BCSL", 11),
createFakeDisbursementValue(
DisbursementValueType.BCGrant,
"SBSD",
12,
),
createFakeDisbursementValue(
DisbursementValueType.BCGrant,
"BCAG",
13,
),
],
},
{
offeringIntensity: OfferingIntensity.fullTime,
applicationStatus: ApplicationStatus.Completed,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
assessmentDate: addDays(-1),
studentAssessmentStatus: StudentAssessmentStatus.Completed,
},
},
);
// Application currently being processed.
const currentApplication = await saveFakeApplicationDisbursements(
db.dataSource,
{ student },
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.InProgress,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
studentAssessmentStatus: StudentAssessmentStatus.InProgress,
},
},
);

// Act
const result = await assessmentController.verifyAssessmentCalculationOrder(
createFakeVerifyAssessmentCalculationOrderPayload(
currentApplication.currentAssessment.id,
),
);

// Asserts
expect(FakeWorkerJobResult.getResultType(result)).toBe(
MockedZeebeJobResult.Complete,
);
expect(FakeWorkerJobResult.getOutputVariables(result)).toStrictEqual({
isReadyForCalculation: true,
// Full-time
programYearTotalFullTimeBCAG: 13,
programYearTotalFullTimeCSGD: 9,
programYearTotalFullTimeCSGP: 10,
programYearTotalFullTimeSBSD: 12,
// Part-time
programYearTotalPartTimeBCAG: 7,
programYearTotalPartTimeCSGD: 3,
programYearTotalPartTimeCSGP: 4,
programYearTotalPartTimeCSPT: 2,
programYearTotalPartTimeSBSD: 6,
});
});

it("Should consider the grant from only one disbursement from a valid past application when the past application has two disbursements and the second COE is declined.", async () => {
// Arrange

// Create the student to be shared across the applications.
const student = await saveFakeStudent(db.dataSource);
// Past part-time application with two disbursements where the second COE was declined.
await saveFakeApplicationDisbursements(
db.dataSource,
{
student,
firstDisbursementValues: [
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSGP",
1000,
),
],
secondDisbursementValues: [
createFakeDisbursementValue(
DisbursementValueType.CanadaGrant,
"CSGP",
1000,
),
],
},
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.Completed,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
assessmentDate: addDays(-1),
studentAssessmentStatus: StudentAssessmentStatus.Completed,
},
secondDisbursementInitialValues: {
coeStatus: COEStatus.declined,
},
},
);
// Application currently being processed.
const currentApplication = await saveFakeApplicationDisbursements(
db.dataSource,
{ student },
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.InProgress,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
studentAssessmentStatus: StudentAssessmentStatus.InProgress,
},
},
);

// Act
const result = await assessmentController.verifyAssessmentCalculationOrder(
createFakeVerifyAssessmentCalculationOrderPayload(
currentApplication.currentAssessment.id,
),
);

// Asserts
expect(FakeWorkerJobResult.getResultType(result)).toBe(
MockedZeebeJobResult.Complete,
);
// Expect to consider only the CSGP from the first disbursement
// and ignore the second disbursement with the declined COE.
expect(FakeWorkerJobResult.getOutputVariables(result)).toStrictEqual({
isReadyForCalculation: true,
programYearTotalPartTimeCSGP: 1000,
});
});

it("Should not return any program year total awards when there are no applications in the past for the same student and program year.", async () => {
// Arrange

// Application currently being processed.
const currentApplication = await saveFakeApplicationDisbursements(
db.dataSource,
undefined,
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.InProgress,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
studentAssessmentStatus: StudentAssessmentStatus.InProgress,
},
},
);

// Act
const result = await assessmentController.verifyAssessmentCalculationOrder(
createFakeVerifyAssessmentCalculationOrderPayload(
currentApplication.currentAssessment.id,
),
);

// Asserts
expect(FakeWorkerJobResult.getResultType(result)).toBe(
MockedZeebeJobResult.Complete,
);
expect(FakeWorkerJobResult.getOutputVariables(result)).toStrictEqual({
isReadyForCalculation: true,
});
});
});
Loading

0 comments on commit db070bb

Please sign in to comment.