Skip to content

Commit

Permalink
#2523 - PD/PPD Assessment and Disbursement Logic (#2642)
Browse files Browse the repository at this point in the history
- [x] Save calculatedDataPDPPDStatus to the workflow data
- [x] **Check for Disability Profile Status at eCert Generation using
calculatedDataPDPPDStatus:**
  - Student assessment contains PD/PPD _application_ flag=yes then
    - Student profile PD/PPD approved, generated e-Cert.
    - Student profile PD/PPD missing approval, withhold disbursement.
- [x] Add unit or e2e test (depending on which is relevant).

Changed the factories to include workflow data , for the existing test
cases to pass.
  • Loading branch information
guru-aot authored Jan 5, 2024
1 parent 81b649b commit 2fdf4d3
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import {
ApplicationStatus,
Assessment,
COEStatus,
DisabilityStatus,
DisbursementOverawardOriginType,
DisbursementSchedule,
DisbursementScheduleStatus,
DisbursementValueType,
FormYesNoOptions,
OfferingIntensity,
RelationshipStatus,
} from "@sims/sims-db";
import {
E2EDataSources,
Expand Down Expand Up @@ -465,5 +468,217 @@ describe(
}),
).toBe(true);
});

it("Should not generate disbursement if the Student assessment contains PD/PPD application flag is yes and Student profile PD/PPD missing approval", async () => {
// Arrange

// Student with valid SIN and PD/PPD Not Requested.
const student = await saveFakeStudent(db.dataSource);
// Valid MSFAA Number.
const msfaaNumber = await db.msfaaNumber.save(
createFakeMSFAANumber({ student }, { msfaaState: MSFAAStates.Signed }),
);

// Student application eligible for e-Cert.
const application = await saveFakeApplicationDisbursements(
db.dataSource,
{ student, msfaaNumber },
{
offeringIntensity: OfferingIntensity.fullTime,
applicationStatus: ApplicationStatus.Completed,
currentAssessmentInitialValues: {
assessmentData: { weeks: 5 } as Assessment,
assessmentDate: new Date(),
workflowData: {
studentData: {
dependantStatus: "dependant",
relationshipStatus: RelationshipStatus.Single,
livingWithParents: FormYesNoOptions.Yes,
numberOfParents: 2,
},
calculatedData: {
familySize: 2,
studentMSOLAllowance: 7777,
totalNonEducationalCost: 22,
studentMaritalStatusCode: "SI",
pdppdStatus: true,
},
},
},
firstDisbursementInitialValues: {
coeStatus: COEStatus.completed,
},
},
);

// Queued job.
const { job } = mockBullJob<void>();

// Act
const result = await processor.processECert(job);

// Assert 0 uploaded records.
expect(result).toStrictEqual([
"Process finalized with success.",
"Generated file: none",
"Uploaded records: 0",
]);
const [disbursement] =
application.currentAssessment.disbursementSchedules;
const isScheduleNotSent = await db.disbursementSchedule.exist({
where: {
id: disbursement.id,
disbursementScheduleStatus: DisbursementScheduleStatus.Pending,
},
});
expect(isScheduleNotSent).toBe(true);
});

it("Should generate disbursement if the Student assessment contains PD/PPD application flag is yes and Student profile PD approved or confirmed", async () => {
// Arrange

// Student with valid SIN and PD/PPD approved or confirmed.
const student = await saveFakeStudent(
db.dataSource,
{},
{
initialValue: {
disabilityStatus: DisabilityStatus.PD,
},
},
);
// Valid MSFAA Number.
const msfaaNumber = await db.msfaaNumber.save(
createFakeMSFAANumber({ student }, { msfaaState: MSFAAStates.Signed }),
);
// Student application eligible for e-Cert.
const application = await saveFakeApplicationDisbursements(
db.dataSource,
{ student, msfaaNumber },
{
offeringIntensity: OfferingIntensity.fullTime,
applicationStatus: ApplicationStatus.Completed,
currentAssessmentInitialValues: {
assessmentData: { weeks: 5 } as Assessment,
assessmentDate: new Date(),
workflowData: {
studentData: {
dependantStatus: "dependant",
relationshipStatus: RelationshipStatus.Single,
livingWithParents: FormYesNoOptions.Yes,
numberOfParents: 2,
},
calculatedData: {
familySize: 2,
studentMSOLAllowance: 7777,
totalNonEducationalCost: 22,
studentMaritalStatusCode: "SI",
pdppdStatus: true,
},
},
},
firstDisbursementInitialValues: {
coeStatus: COEStatus.completed,
},
},
);

// Queued job.
const { job } = mockBullJob<void>();

// Act
const result = await processor.processECert(job);

// Assert uploaded file.
const uploadedFile = getUploadedFile(sftpClientMock);
const fileDate = dayjs().format("YYYYMMDD");
const uploadedFileName = `MSFT-Request\\DPBC.EDU.FTECERTS.${fileDate}.001`;
expect(uploadedFile.remoteFilePath).toBe(uploadedFileName);
expect(result).toStrictEqual([
"Process finalized with success.",
`Generated file: ${uploadedFileName}`,
"Uploaded records: 1",
]);
const [disbursement] =
application.currentAssessment.disbursementSchedules;
const isScheduleSent = await db.disbursementSchedule.exist({
where: {
id: disbursement.id,
dateSent: Not(IsNull()),
disbursementScheduleStatus: DisbursementScheduleStatus.Sent,
},
});
expect(isScheduleSent).toBe(true);
});

it("Should generate disbursement if the Student assessment contains PD/PPD application flag is no", async () => {
// Arrange

// Student with valid SIN and PD/PPD Not Requested.
const student = await saveFakeStudent(db.dataSource);
// Valid MSFAA Number.
const msfaaNumber = await db.msfaaNumber.save(
createFakeMSFAANumber({ student }, { msfaaState: MSFAAStates.Signed }),
);

// Student application eligible for e-Cert.
const application = await saveFakeApplicationDisbursements(
db.dataSource,
{ student, msfaaNumber },
{
offeringIntensity: OfferingIntensity.fullTime,
applicationStatus: ApplicationStatus.Completed,
currentAssessmentInitialValues: {
assessmentData: { weeks: 5 } as Assessment,
assessmentDate: new Date(),
workflowData: {
studentData: {
dependantStatus: "dependant",
relationshipStatus: RelationshipStatus.Single,
livingWithParents: FormYesNoOptions.Yes,
numberOfParents: 2,
},
calculatedData: {
familySize: 2,
studentMSOLAllowance: 7777,
totalNonEducationalCost: 22,
studentMaritalStatusCode: "SI",
pdppdStatus: false,
},
},
},
firstDisbursementInitialValues: {
coeStatus: COEStatus.completed,
},
},
);

// Queued job.
const { job } = mockBullJob<void>();

// Act
const result = await processor.processECert(job);

// Assert uploaded file.
const uploadedFile = getUploadedFile(sftpClientMock);
const fileDate = dayjs().format("YYYYMMDD");
const uploadedFileName = `MSFT-Request\\DPBC.EDU.FTECERTS.${fileDate}.001`;
expect(uploadedFile.remoteFilePath).toBe(uploadedFileName);
expect(result).toStrictEqual([
"Process finalized with success.",
`Generated file: ${uploadedFileName}`,
"Uploaded records: 1",
]);
const [disbursement] =
application.currentAssessment.disbursementSchedules;
const isScheduleSent = await db.disbursementSchedule.exist({
where: {
id: disbursement.id,
dateSent: Not(IsNull()),
disbursementScheduleStatus: DisbursementScheduleStatus.Sent,
},
});
expect(isScheduleSent).toBe(true);
});
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export interface IER12WorkflowData {
numberOfParents?: number;
};
calculatedData: {
pdppdStatus: boolean;
parentalAssets?: number;
studentMaritalStatusCode: StudentMaritalStatusCode;
totalEligibleDependents?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const WORKFLOW_DATA_SINGLE_INDEPENDENT_WITH_NO_DEPENDENTS: IER12WorkflowD
numberOfParents: undefined,
},
calculatedData: {
pdppdStatus: false,
parentalAssets: undefined,
studentMaritalStatusCode: "SI",
totalEligibleDependents: undefined,
Expand Down Expand Up @@ -38,6 +39,7 @@ export const WORKFLOW_DATA_MARRIED_WITH_DEPENDENTS: IER12WorkflowData = {
numberOfParents: undefined,
},
calculatedData: {
pdppdStatus: false,
parentalAssets: undefined,
studentMaritalStatusCode: "MA",
totalEligibleDependents: 3,
Expand Down Expand Up @@ -67,6 +69,7 @@ export const WORKFLOW_DATA_DEPENDANT_RELATIONSHIP_OTHER_LIVING_WITH_PARENTS: IER
numberOfParents: 2,
},
calculatedData: {
pdppdStatus: false,
parentalAssets: 142.97,
studentMaritalStatusCode: "SI",
totalEligibleDependents: undefined,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RestrictionCode } from "@sims/services";
import {
DisabilityStatus,
DisbursementSchedule,
DisbursementValueType,
EducationProgramOffering,
Expand Down Expand Up @@ -127,6 +128,21 @@ export const FULL_TIME_DISBURSEMENT_FEEDBACK_ERRORS = [
"EDU-00112",
];

/**
* Represents students Disability status both from application submitted
* and the student profile disability status verification.
*/
export interface DisabilityDetails {
/**
* Calculated PD/PPD status applied in the application by the student.
*/
calculatedPDPPDStatus: boolean;
/**
* Student profile disability status.
*/
studentProfileDisabilityStatus: DisabilityStatus;
}

/**
* Represents an active student restriction.
*/
Expand Down Expand Up @@ -178,6 +194,8 @@ export class EligibleECertDisbursement {
* @param offering education program offering.
* @param maxLifetimeBCLoanAmount maximum BC loan configured to the assessment's
* program year.
* @param disabilityDetails students Disability status both from application submitted
* and the student profile disability status verification.
* @param restrictions All active student restrictions actions. These actions can
* impact the e-Cert calculations.
* This is a shared array reference between all the disbursements of a single student.
Expand All @@ -195,6 +213,7 @@ export class EligibleECertDisbursement {
public readonly disbursement: DisbursementSchedule,
public readonly offering: EligibleECertOffering,
public readonly maxLifetimeBCLoanAmount: number,
public readonly disabilityDetails: DisabilityDetails,
readonly restrictions: StudentActiveRestriction[],
) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from "@sims/sims-db";
import { InjectRepository } from "@nestjs/typeorm";
import {
DisabilityDetails,
EligibleECertDisbursement,
StudentActiveRestriction,
mapStudentActiveRestrictions,
Expand Down Expand Up @@ -62,6 +63,7 @@ export class ECertGenerationService {
"application.id",
"application.applicationNumber",
"currentAssessment.id",
"currentAssessment.workflowData",
"disbursementSchedule.id",
"disbursementSchedule.disbursementDate",
"disbursementSchedule.tuitionRemittanceRequestedAmount",
Expand All @@ -79,6 +81,7 @@ export class ECertGenerationService {
"offering.actualTuitionCosts",
"offering.programRelatedCosts",
"student.id",
"student.disabilityStatus",
"sinValidation.id",
"sinValidation.isValidSIN",
// The student active restrictions are initially loaded along side all the student data but they can
Expand Down Expand Up @@ -141,16 +144,24 @@ export class ECertGenerationService {
eligibleApplications.flatMap<EligibleECertDisbursement>((application) => {
return application.currentAssessment.disbursementSchedules.map(
(disbursement) => {
const student = application.student;
const disabilityDetails: DisabilityDetails = {
calculatedPDPPDStatus:
application.currentAssessment.workflowData.calculatedData
.pdppdStatus,
studentProfileDisabilityStatus: student.disabilityStatus,
};
return new EligibleECertDisbursement(
application.student.id,
!!application.student.sinValidation.isValidSIN,
student.id,
!!student.sinValidation.isValidSIN,
application.currentAssessment.id,
application.id,
application.applicationNumber,
disbursement,
application.currentAssessment.offering,
application.programYear.maxLifetimeBCLoanAmount,
groupedStudentRestrictions[application.student.id],
disabilityDetails,
groupedStudentRestrictions[student.id],
);
},
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { COEStatus } from "@sims/sims-db";
import { COEStatus, DisabilityStatus } from "@sims/sims-db";
import { ProcessSummary } from "@sims/utilities/logger";
import { EligibleECertDisbursement } from "../disbursement-schedule.models";

Expand Down Expand Up @@ -36,6 +36,17 @@ export abstract class ValidateDisbursementBase {
log.info(`Student MSFAA associated with the disbursement is not signed.`);
shouldContinue = false;
}
// Disability Status PD/PPD Verified.
const disabilityStatusValidation = eCertDisbursement.disabilityDetails
.calculatedPDPPDStatus
? [DisabilityStatus.PD, DisabilityStatus.PPD].includes(
eCertDisbursement.disabilityDetails.studentProfileDisabilityStatus,
)
: true;
if (!disabilityStatusValidation) {
log.info(`Student disability Status PD/PPD is not verified.`);
shouldContinue = false;
}
return shouldContinue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ export interface WorkflowData {
dependantInfantQuantity?: number;
dependantDeclaredOnTaxesQuantity?: number;
dependantPostSecondaryQuantity?: number;
pdppdStatus: boolean;
partnerStudentStudyWeeks?: number;
};
}
Expand Down
Loading

0 comments on commit 2fdf4d3

Please sign in to comment.