Skip to content

Commit

Permalink
#3511 - Revise PT Scholastic Standing (#3717)
Browse files Browse the repository at this point in the history
![image](https://github.com/user-attachments/assets/2136a0e9-9cff-41be-8a91-2dacc446ad45)

When an withdrawal of an application is requested from the institution
user, now PTWTHD restriction is also added with PTSSR.

---------

Co-authored-by: guru-aot <[email protected]>
  • Loading branch information
guru-aot and guru-aot authored Sep 18, 2024
1 parent 5504c48 commit 152f608
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HttpStatus, INestApplication } from "@nestjs/common";
import {
E2EDataSources,
RestrictionCode,
createE2EDataSources,
createFakeInstitutionLocation,
createFakeStudentAppeal,
Expand All @@ -20,6 +21,8 @@ import {
ApplicationStatus,
AssessmentTriggerType,
InstitutionLocation,
NotificationMessageType,
OfferingIntensity,
StudentScholasticStandingChangeType,
} from "@sims/sims-db";
import {
Expand Down Expand Up @@ -250,18 +253,112 @@ describe("StudentScholasticStandingsInstitutionsController(e2e)-saveScholasticSt
).toBe(createdScholasticStandingId);
});

it("Should create a new scholastic standing for a part-time application when the institution user requests.", async () => {
// Arrange
mockFormioDryRun({
studentScholasticStandingChangeType:
StudentScholasticStandingChangeType.StudentDidNotCompleteProgram,
});
const application = await saveFakeApplication(
db.dataSource,
{
institutionLocation: collegeFLocation,
},
{
offeringIntensity: OfferingIntensity.partTime,
applicationStatus: ApplicationStatus.Completed,
},
);
// Institution token.
const institutionUserToken = await getInstitutionToken(
InstitutionTokenTypes.CollegeFUser,
);
const endpoint = `/institutions/scholastic-standing/location/${collegeFLocation.id}/application/${application.id}`;

// Act/Assert
await request(app.getHttpServer())
.post(endpoint)
.send(payload)
.auth(institutionUserToken, BEARER_AUTH_TYPE)
.expect(HttpStatus.CREATED)
.expect((response) => {
expect(response.body.id).toBeGreaterThan(0);
});
const restriction = await db.studentRestriction.find({
select: {
id: true,
restriction: {
id: true,
restrictionCode: true,
},
},
relations: {
restriction: true,
},
where: { application: { id: application.id } },
});
expect(restriction).toEqual([
{
id: expect.any(Number),
restriction: {
id: expect.any(Number),
restrictionCode: RestrictionCode.PTSSR,
},
},
{
id: expect.any(Number),
restriction: {
id: expect.any(Number),
restrictionCode: RestrictionCode.PTWTHD,
},
},
]);
const notifications = await db.notification.find({
select: {
id: true,
user: { id: true },
notificationMessage: { id: true },
},
relations: { user: true, notificationMessage: true },
where: { user: { id: application.student.user.id } },
order: { notificationMessage: { id: "ASC" } },
});
expect(notifications).toEqual([
{
id: expect.any(Number),
notificationMessage: {
id: NotificationMessageType.StudentRestrictionAdded,
},
user: { id: application.student.user.id },
},
{
id: expect.any(Number),
notificationMessage: {
id: NotificationMessageType.InstitutionReportsChange,
},
user: { id: application.student.user.id },
},
]);
});

/**
* Centralized method to handle the form.io mock.
* @param options method options:
* - `validDryRun`: boolean false indicates that the form mock resolved value is invalid. Default value is true.
* - `studentScholasticStandingChangeType`: Student scholastic standing change type to be added in combination with SchoolTransfer scholastic standing type .
*/
function mockFormioDryRun(options?: { validDryRun?: boolean }): void {
function mockFormioDryRun(options?: {
validDryRun?: boolean;
studentScholasticStandingChangeType?: StudentScholasticStandingChangeType;
}): void {
const validDryRun = options?.validDryRun ?? true;
payload = {
data: {
dateOfChange: getISODateOnlyString(new Date()),
scholasticStandingChangeType:
StudentScholasticStandingChangeType.SchoolTransfer,
options?.studentScholasticStandingChangeType
? options.studentScholasticStandingChangeType
: StudentScholasticStandingChangeType.SchoolTransfer,
},
};
formService.dryRunSubmission = jest.fn().mockResolvedValue({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import {
} from "./student-scholastic-standings.models";
import { StudentRestrictionService } from "../restriction/student-restriction.service";
import { APPLICATION_CHANGE_NOT_ELIGIBLE } from "../../constants";
import { SCHOLASTIC_STANDING_MINIMUM_UNSUCCESSFUL_WEEKS } from "../../utilities";
import {
PART_TIME_SCHOLASTIC_STANDING_RESTRICTIONS,
SCHOLASTIC_STANDING_MINIMUM_UNSUCCESSFUL_WEEKS,
} from "../../utilities";
import {
NotificationActionsService,
RestrictionCode,
Expand Down Expand Up @@ -157,19 +160,19 @@ export class StudentScholasticStandingsService extends RecordDataModelService<St
.getOne();

// Check for restrictions and apply if any.
const studentRestriction = await this.getScholasticStandingRestrictions(
const studentRestrictions = await this.getScholasticStandingRestrictions(
scholasticStandingData,
existingOffering.offeringIntensity,
application.studentId,
auditUserId,
application.id,
);
let createdRestriction: StudentRestriction | undefined = undefined;
if (studentRestriction) {
let createdRestrictions: StudentRestriction[];
if (studentRestrictions.length) {
// Used later to send the notification at the end of the process.
createdRestriction = await transactionalEntityManager
createdRestrictions = await transactionalEntityManager
.getRepository(StudentRestriction)
.save(studentRestriction);
.save(studentRestrictions);
}

// Create StudentScholasticStanding.
Expand Down Expand Up @@ -291,9 +294,12 @@ export class StudentScholasticStandingsService extends RecordDataModelService<St
// Case a restriction was created, send a notification to the student.
// Left as the last step to ensure that everything else was processed with
// success and the notification will not be generated otherwise.
if (createdRestriction) {
if (createdRestrictions?.length) {
const restrictionIds = createdRestrictions.map(
(createdRestriction) => createdRestriction.id,
);
await this.studentRestrictionSharedService.createNotifications(
[createdRestriction.id],
restrictionIds,
auditUserId,
transactionalEntityManager,
);
Expand Down Expand Up @@ -324,22 +330,23 @@ export class StudentScholasticStandingsService extends RecordDataModelService<St
* @param auditUserId user that should be considered the one that is
* causing the changes.
* @param applicationId application id.
* @returns a new student restriction object, that need to be saved.
* @returns a new student restriction object(s), that need to be saved.
*/
async getScholasticStandingRestrictions(
scholasticStandingData: ScholasticStanding,
offeringIntensity: OfferingIntensity,
studentId: number,
auditUserId: number,
applicationId: number,
): Promise<StudentRestriction | undefined> {
): Promise<StudentRestriction[]> {
if (offeringIntensity === OfferingIntensity.fullTime) {
return this.getFullTimeStudentRestrictions(
const fullTimeRestriction = await this.getFullTimeStudentRestrictions(
scholasticStandingData,
studentId,
auditUserId,
applicationId,
);
return fullTimeRestriction ? [fullTimeRestriction] : [];
}
if (offeringIntensity === OfferingIntensity.partTime) {
return this.getPartTimeStudentRestrictions(
Expand Down Expand Up @@ -442,27 +449,35 @@ export class StudentScholasticStandingsService extends RecordDataModelService<St
* @param auditUserId user that should be considered the one that is
* causing the changes.
* @param applicationId application id.
* @returns a new student restriction object, that need to be saved.
* @returns a new student restriction objects, that need to be saved.
*/
async getPartTimeStudentRestrictions(
scholasticStandingData: ScholasticStanding,
studentId: number,
auditUserId: number,
applicationId: number,
): Promise<StudentRestriction | undefined> {
): Promise<StudentRestriction[]> {
const studentRestriction: StudentRestriction[] = [];
if (
[
StudentScholasticStandingChangeType.StudentDidNotCompleteProgram,
StudentScholasticStandingChangeType.StudentWithdrewFromProgram,
].includes(scholasticStandingData.scholasticStandingChangeType)
) {
return this.studentRestrictionSharedService.createRestrictionToSave(
studentId,
RestrictionCode.PTSSR,
auditUserId,
applicationId,
);
// Create an array to hold the restriction promises.
const restrictionPromises =
PART_TIME_SCHOLASTIC_STANDING_RESTRICTIONS.map((restrictionCode) =>
this.studentRestrictionSharedService.createRestrictionToSave(
studentId,
restrictionCode,
auditUserId,
applicationId,
),
);
const restrictions = await Promise.all(restrictionPromises);
studentRestriction.push(...restrictions);
}
return studentRestriction;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { RestrictionCode } from "@sims/services";

export const PIR_DENIED_REASON_OTHER_ID = 1;
// Timeout to handle the worst-case scenario where the commit/rollback
// was not executed due to a possible catastrophic failure.
Expand Down Expand Up @@ -110,3 +112,11 @@ export const OFFERING_STUDY_PERIOD_MIN_FUNDED_WEEKS_FULL_TIME = 12;
* Minimum amount of funded weeks required for a part time offering study period.
*/
export const OFFERING_STUDY_PERIOD_MIN_FUNDED_WEEKS_PART_TIME = 6;

/**
* Part time scholastic standing restrictions.
*/
export const PART_TIME_SCHOLASTIC_STANDING_RESTRICTIONS: RestrictionCode[] = [
RestrictionCode.PTSSR,
RestrictionCode.PTWTHD,
];
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export enum RestrictionCode {
* for a PT course application, "PTSSR" restriction is added to the student account.
*/
PTSSR = "PTSSR",
/**
* When an institution report withdrawal or unsuccessful weeks
* for a PT course application, "PTWTHD" restriction is added to the student account.
*/
PTWTHD = "PTWTHD",
/**
* When a student has a temporary SIN and applies for a full-time/part-time application
* this restriction is applied case the SIN expiry date is before the offering end date.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ export enum RestrictionCode {
*/
AF = "AF",
/**
* Verification restriction on file. Set up call back for Student case review verification team.
* Part-time scholastic standing restrictions - Student withdrew or was unsuccesful from Part Time studies.
*/
PTWTHD = "PTWTHD",
/**
* Part-time scholastic standing restrictions - Not eligible for part time funding due to scholastic standing must self fund or appeal.
*/
PTSSR = "PTSSR",
}

0 comments on commit 152f608

Please sign in to comment.