Skip to content
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

#4133 - SFAS to SIMS Bridge - PT App Cancellation Date & MSFAA (FT/PT) Change - Part 3 #4182

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,104 @@ describe("ApplicationStudentsController(e2e)-submitApplication", () => {
},
);

it(
"Should submit an application for a student when there is a cancelled part-time application in SFAS with overlapping study dates" +
" ignoring the cancelled SFAS application.",
async () => {
// Arrange
const student = await saveFakeStudent(db.dataSource);
const sfasIndividual = await saveFakeSFASIndividual(db.dataSource, {
initialValues: {
lastName: student.user.lastName,
birthDate: student.birthDate,
sin: student.sinValidation.sin,
},
});
// Cancelled SFAS full time application with overlapping study dates.
const sfasPartTimeApplication = createFakeSFASPartTimeApplication(
{ individual: sfasIndividual },
{
initialValues: {
startDate: getISODateOnlyString(new Date()),
endDate: getISODateOnlyString(addDays(50)),
// The SFAS application is cancelled.
applicationCancelDate: getISODateOnlyString(new Date()),
},
},
);
await db.sfasPartTimeApplications.save(sfasPartTimeApplication);

// SIMS Offering having overlapping study period with SFAS.
const simsApplicationOfferingInitialValues = {
studyStartDate: getISODateOnlyString(addDays(30)),
studyEndDate: getISODateOnlyString(addDays(90)),
offeringIntensity: OfferingIntensity.partTime,
};
const simsApplication = createFakeApplication(
{
student,
},
{
initialValue: {
data: {},
applicationStatus: ApplicationStatus.Draft,
applicationStatusUpdatedOn: new Date(),
creator: systemUsersService.systemUser,
createdAt: new Date(),
} as Application,
},
);
const simsDraftApplication = await db.application.save(simsApplication);
const auditUser = await db.user.save(createFakeUser());
const simsApplicationOffering = await db.educationProgramOffering.save(
createFakeEducationProgramOffering(
{
auditUser,
institutionLocation: simsApplication.location,
},
{
initialValues: simsApplicationOfferingInitialValues,
},
),
);
const secondApplicationProgram = simsApplicationOffering.educationProgram;
const applicationData = {
selectedOfferingDate:
simsApplicationOfferingInitialValues.studyStartDate,
selectedOfferingEndDate:
simsApplicationOfferingInitialValues.studyEndDate,
howWillYouBeAttendingTheProgram:
simsApplicationOfferingInitialValues.offeringIntensity,
selectedProgram: secondApplicationProgram.id,
selectedOffering: simsApplicationOffering.id,
selectedLocation: simsApplication.location.id,
};
const payload = {
associatedFiles: [],
data: applicationData,
programYearId: simsApplication.programYear.id,
} as SaveApplicationAPIInDTO;
const endpoint = `/students/application/${simsDraftApplication.id}/submit`;
const token = await getStudentToken(
FakeStudentUsersTypes.FakeStudentUserType1,
);
const dryRunSubmissionMock = jest.fn().mockResolvedValue({
valid: true,
formName: FormNames.Application,
data: { data: applicationData },
});
formService.dryRunSubmission = dryRunSubmissionMock;
await mockUserLoginInfo(appModule, student);
// Act/Assert
await request(app.getHttpServer())
.patch(endpoint)
.send(payload)
.auth(token, BEARER_AUTH_TYPE)
.expect(HttpStatus.OK)
.expect({});
},
);

afterAll(async () => {
await app?.close();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,112 @@ describe("AssessmentController(e2e)-verifyAssessmentCalculationOrder", () => {
});
});

it("Should not sum the awards from SFAS and SFAS part-time applications data when the SFAS applications for the same student and program year are cancelled.", async () => {
// Arrange

// Create the student to be shared across the applications.
const student = await saveFakeStudent(db.dataSource);
// Get the program year for the start date.
const programYear = await db.programYear.findOne({ where: { id: 2 } });

// Current application having the first assessment already processed.
const currentApplication = await saveFakeApplicationDisbursements(
db.dataSource,
{ student },
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.InProgress,
currentAssessmentInitialValues: {
assessmentWorkflowId: "some fake id",
studentAssessmentStatus: StudentAssessmentStatus.Completed,
assessmentDate: addDays(30, programYear.startDate),
},
},
);
const firstAssessmentDate =
currentApplication.currentAssessment.assessmentDate;
// The start date for the first SFAS and SFAS part-time application record is set to the date before the first assessment date of the current application.
const legacyApplicationStartDate = faker.date.between(
programYear.startDate,
addDays(-1, firstAssessmentDate),
);
const legacyApplicationEndDate = addDays(30, firstAssessmentDate);

// Create the second assessment for the current application with a different assessment date.
const secondAssessment = createFakeStudentAssessment(
{
auditUser: currentApplication.student.user,
application: currentApplication,
offering: currentApplication.currentAssessment.offering,
},
{
initialValue: {
assessmentWorkflowId: "some fake id",
studentAssessmentStatus: StudentAssessmentStatus.InProgress,
},
},
);
currentApplication.currentAssessment = secondAssessment;
await db.application.save(currentApplication);

// SFAS Individual.
const sfasIndividual = await saveFakeSFASIndividual(db.dataSource, {
initialValues: {
lastName: student.user.lastName,
birthDate: student.birthDate,
sin: student.sinValidation.sin,
},
});

const fakeSFASApplication = createFakeSFASApplication(
{ individual: sfasIndividual },
{
initialValues: {
startDate: getISODateOnlyString(legacyApplicationStartDate),
endDate: getISODateOnlyString(legacyApplicationEndDate),
csgdAward: 9,
csgpAward: 10,
sbsdAward: 12,
bcagAward: 13,
applicationCancelDate: getISODateOnlyString(new Date()),
},
},
);
await db.sfasApplication.save(fakeSFASApplication);

const fakeSFASPartTimeApplication = createFakeSFASPartTimeApplication(
{ individual: sfasIndividual },
{
initialValues: {
startDate: getISODateOnlyString(legacyApplicationStartDate),
endDate: getISODateOnlyString(legacyApplicationEndDate),
csptAward: 2,
csgdAward: 3,
csgpAward: 4,
sbsdAward: 6,
bcagAward: 7,
applicationCancelDate: getISODateOnlyString(new Date()),
},
},
);
await db.sfasPartTimeApplications.save(fakeSFASPartTimeApplication);
// Act
const result = await assessmentController.verifyAssessmentCalculationOrder(
createFakeVerifyAssessmentCalculationOrderPayload(
currentApplication.currentAssessment.id,
),
);
// Assert
expect(FakeWorkerJobResult.getResultType(result)).toBe(
MockedZeebeJobResult.Complete,
);
// The calculation will not take cancelled SFAS and SFAS part-time application data.
expect(FakeWorkerJobResult.getOutputVariables(result)).toStrictEqual({
isReadyForCalculation: true,
latestCSLPBalance: 0,
});
});

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,69 @@ describe("DisbursementController(e2e)-associateMSFAA", () => {
expect(cancelledMSFAANumber.cancelledDate).not.toBe(null);
});

it("Should not reuse the MSFAA number from SFAS full-time cancelled applications in SIMS when there is a MSFAA for a cancelled SFAS application.", async () => {
// Arrange
const legacyApplicationStartDate = addDays(-100);
const legacyApplicationEndDate = addDays(-10);

// Create student and save fake application with disbursements.
const student = await saveFakeStudent(db.dataSource);
const application = await saveFakeApplicationDisbursements(
db.dataSource,
{ student },
{
offeringIntensity: OfferingIntensity.fullTime,
applicationStatus: ApplicationStatus.InProgress,
},
);

const savedSFASIndividual = await saveFakeSFASIndividual(db.dataSource, {
initialValues: { student: student },
});
await db.sfasApplication.save(
createFakeSFASApplication(
{ individual: savedSFASIndividual },
{
initialValues: {
startDate: getISODateOnlyString(legacyApplicationStartDate),
endDate: getISODateOnlyString(legacyApplicationEndDate),
applicationCancelDate: getISODateOnlyString(new Date()),
},
},
),
);

// Act
const associateMSFAAPayload = createFakeAssociateMSFAAPayload({
assessmentId: application.currentAssessment.id,
});
const saveResult = await disbursementController.associateMSFAA(
associateMSFAAPayload,
);

// Asserts
expect(FakeWorkerJobResult.getResultType(saveResult)).toBe(
MockedZeebeJobResult.Complete,
);

// Fetch MSFAA Number for the student in SIMS.
const createdMSFAANumber = await db.msfaaNumber.findOne({
select: {
id: true,
msfaaNumber: true,
},
where: {
student: { id: student.id },
},
order: {
id: "DESC",
},
});
expect(createdMSFAANumber.msfaaNumber).not.toEqual(
savedSFASIndividual.msfaaNumber,
);
});

it("Should create new MSFAA Number for full-time applications by creating and activating in SIMS when MSFAA is not found or invalid SFAS application offering end date.", async () => {
// Arrange
const firstLegacyApplicationStartDate = addDays(-MAX_MSFAA_VALID_DAYS + 10);
Expand Down Expand Up @@ -617,6 +680,69 @@ describe("DisbursementController(e2e)-associateMSFAA", () => {
expect(secondDisbursementSchedule.msfaaNumber.id).toBe(savedMSFAANumber.id);
});

it("Should not reuse the MSFAA number from SFAS part-time cancelled applications in SIMS when there is a MSFAA for a cancelled SFAS application.", async () => {
// Arrange
const legacyApplicationStartDate = addDays(-100);
const legacyApplicationEndDate = addDays(-10);

// Create student and save fake application with disbursements.
const student = await saveFakeStudent(db.dataSource);
const application = await saveFakeApplicationDisbursements(
db.dataSource,
{ student },
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.InProgress,
},
);

const savedSFASIndividual = await saveFakeSFASIndividual(db.dataSource, {
initialValues: { student: student },
});
await db.sfasPartTimeApplications.save(
createFakeSFASPartTimeApplication(
{ individual: savedSFASIndividual },
{
initialValues: {
startDate: getISODateOnlyString(legacyApplicationStartDate),
endDate: getISODateOnlyString(legacyApplicationEndDate),
applicationCancelDate: getISODateOnlyString(new Date()),
},
},
),
);

// Act
const associateMSFAAPayload = createFakeAssociateMSFAAPayload({
assessmentId: application.currentAssessment.id,
});
const saveResult = await disbursementController.associateMSFAA(
associateMSFAAPayload,
);

// Asserts
expect(FakeWorkerJobResult.getResultType(saveResult)).toBe(
MockedZeebeJobResult.Complete,
);

// Fetch MSFAA Number for the student in SIMS.
const createdMSFAANumber = await db.msfaaNumber.findOne({
select: {
id: true,
msfaaNumber: true,
},
where: {
student: { id: student.id },
},
order: {
id: "DESC",
},
});
expect(createdMSFAANumber.msfaaNumber).not.toEqual(
savedSFASIndividual.msfaaNumber,
);
});

it("Should create new MSFAA number for part-time application when MSFAA is found for previously signed disbursement and its offering end date is not between the valid date.", async () => {
// Arrange
const student = await saveFakeStudent(db.dataSource);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class SFASApplicationService extends DataModelService<SFASApplication> {
individual: true,
},
where: {
applicationCancelDate: IsNull(),
individual: { student: { id: studentId }, msfaaNumber: Not(IsNull()) },
endDate: MoreThanOrEqual(getISODateOnlyString(minMSFAAValidDate)),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export class SFASPartTimeApplicationsService extends DataModelService<SFASPartTi
.createQueryBuilder("sfasPTApplication")
.select(["sfasPTApplication.id"])
.innerJoin("sfasPTApplication.individual", "sfasPTstudent")
.where("lower(sfasPTstudent.lastName) = lower(:lastName)", { lastName })
.where("sfasPTApplication.applicationCancelDate IS NULL")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

.andWhere("lower(sfasPTstudent.lastName) = lower(:lastName)", {
lastName,
})
.andWhere("sfasPTstudent.sin = :sin", { sin })
.andWhere("sfasPTstudent.birthDate = :birthDate", { birthDate })
.andWhere(
Expand Down Expand Up @@ -89,6 +92,7 @@ export class SFASPartTimeApplicationsService extends DataModelService<SFASPartTi
individual: true,
},
where: {
applicationCancelDate: IsNull(),
individual: { student: { id: studentId }, msfaaNumber: Not(IsNull()) },
endDate: MoreThanOrEqual(getISODateOnlyString(minMSFAAValidDate)),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,8 @@ export class AssessmentSequentialProcessingService {
.addSelect("SUM(sfasPTApplication.bcagAward)", "BCAG")
.addSelect("SUM(sfasPTApplication.csptAward)", "CSPT")
.innerJoin("sfasPTApplication.individual", "sfasStudent")
.where("lower(sfasStudent.lastName) = lower(:lastName)", { lastName })
.where("sfasPTApplication.applicationCancelDate IS NULL")
.andWhere("lower(sfasStudent.lastName) = lower(:lastName)", { lastName })
.andWhere("sfasStudent.sin = :sin", { sin })
.andWhere("sfasStudent.birthDate = :birthDate", { birthDate })
.andWhere("sfasPTApplication.startDate >= :startDate", {
Expand Down
Loading
Loading