diff --git a/sources/packages/backend/apps/api/src/constants/error-code.constants.ts b/sources/packages/backend/apps/api/src/constants/error-code.constants.ts index e3e1423295..173a56dd0f 100644 --- a/sources/packages/backend/apps/api/src/constants/error-code.constants.ts +++ b/sources/packages/backend/apps/api/src/constants/error-code.constants.ts @@ -122,3 +122,8 @@ export const DUPLICATE_SABC_CODE = "DUPLICATE_SABC_CODE"; * Institution location not valid. */ export const INSTITUTION_LOCATION_NOT_VALID = "INSTITUTION_LOCATION_NOT_VALID"; + +/** + * Request for disability not allowed. + */ +export const DISABILITY_REQUEST_NOT_ALLOWED = "DISABILITY_REQUEST_NOT_ALLOWED"; diff --git a/sources/packages/backend/apps/api/src/route-controllers/application-offering-change-request/_tests_/e2e/application-offering-change-request.institutions.controller.getCompletedApplications.e2e-spec.ts b/sources/packages/backend/apps/api/src/route-controllers/application-offering-change-request/_tests_/e2e/application-offering-change-request.institutions.controller.getCompletedApplications.e2e-spec.ts index b439ee9402..c0fb9c851e 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/application-offering-change-request/_tests_/e2e/application-offering-change-request.institutions.controller.getCompletedApplications.e2e-spec.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/application-offering-change-request/_tests_/e2e/application-offering-change-request.institutions.controller.getCompletedApplications.e2e-spec.ts @@ -306,7 +306,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getComplet const searchKeyword = "TestStudent"; const endpoint = `/institutions/location/${collegeFLocation.id}/application-offering-change-request/completed?page=0&pageLimit=10&searchCriteria=${searchKeyword}`; - console.log(endpoint); + // Act/Assert await request(app.getHttpServer()) .get(endpoint) diff --git a/sources/packages/backend/apps/api/src/route-controllers/atbc/atbc.students.controller.ts b/sources/packages/backend/apps/api/src/route-controllers/atbc/atbc.students.controller.ts index c43baac819..c4feeba8ac 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/atbc/atbc.students.controller.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/atbc/atbc.students.controller.ts @@ -12,9 +12,11 @@ import { UserToken, } from "../../auth/decorators"; import { StudentUserToken } from "../../auth/userToken.interface"; -import { ClientTypeBaseRoute } from "../../types"; +import { ApiProcessError, ClientTypeBaseRoute } from "../../types"; import BaseController from "../BaseController"; import { ATBCIntegrationProcessingService } from "@sims/integrations/atbc-integration"; +import { DisabilityStatus } from "@sims/sims-db"; +import { DISABILITY_REQUEST_NOT_ALLOWED } from "../../constants"; @AllowAuthorizedParty(AuthorizedParties.student) @RequiresStudentAccount() @@ -29,40 +31,41 @@ export class ATBCStudentController extends BaseController { } /** - * Creates the request for ATBC PD evaluation. - * Student should only be allowed to check the PD status once and the + * Creates the request for ATBC disability evaluation. + * Student should only be allowed to check the disability status once and the * SIN validation must be already done with a successful result. */ - @Patch("apply-pd-status") + @Patch("apply-disability-status") @ApiUnprocessableEntityResponse({ description: "Either the client does not have a validated SIN or the request was already sent to ATBC.", }) - async applyForPDStatus( + async applyForDisabilityStatus( @UserToken() studentUserToken: StudentUserToken, ): Promise { // Get student details const student = await this.studentService.getStudentById( studentUserToken.studentId, ); - // Check the PD status in DB. Student should only be allowed to check the PD status once. - // studentPDSentAt is set when student apply for PD status for the first. - // studentPDVerified is null before PD scheduled job update status. - // studentPDVerified is true if PD confirmed by ATBC or is true from sfas_individual table. - // studentPDVerified is false if PD denied by ATBC. + // To apply for a disability status, SIN validation must be completed for the student and + // not applied for disability status already. if ( !student.sinValidation.isValidSIN || - !!student.studentPDSentAt || - student.studentPDVerified !== null + student.disabilityStatus !== DisabilityStatus.NotRequested ) { throw new UnprocessableEntityException( - "Either the client does not have a validated SIN or the request was already sent to ATBC.", + new ApiProcessError( + "Either SIN validation is not complete or requested for disability status already.", + DISABILITY_REQUEST_NOT_ALLOWED, + ), ); } // This is the only place in application where we call an external application // in API instead of using queues. This is because once the student applies for PD, // after a successful API call the apply for PD button needs to be disabled to avoid // duplicate requests coming. - await this.atbcIntegrationProcessingService.applyForPDStatus(student.id); + await this.atbcIntegrationProcessingService.applyForDisabilityStatus( + student.id, + ); } } diff --git a/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.institutions.controller.getStudentProfile.e2e-spec.ts b/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.institutions.controller.getStudentProfile.e2e-spec.ts index a2df638ce8..c63b8c7b08 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.institutions.controller.getStudentProfile.e2e-spec.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.institutions.controller.getStudentProfile.e2e-spec.ts @@ -17,7 +17,7 @@ import { saveFakeStudent, } from "@sims/test-utils"; import { Application, Institution, InstitutionLocation } from "@sims/sims-db"; -import { determinePDStatus, getUserFullName } from "../../../../utilities"; +import { getUserFullName } from "../../../../utilities"; import { getISODateOnlyString } from "@sims/utilities"; import { saveStudentApplicationForCollegeC } from "./student.institutions.utils"; @@ -86,7 +86,7 @@ describe("StudentInstitutionsController(e2e)-getStudentProfile", () => { }, phone: student.contactInfo.phone, }, - pdStatus: determinePDStatus(student), + disabilityStatus: student.disabilityStatus, validSin: student.sinValidation.isValidSIN, sin: student.sinValidation.sin, }); diff --git a/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.students.controller.getStudentProfile.e2e-spec.ts b/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.students.controller.getStudentProfile.e2e-spec.ts index 4440bcbf0b..c86f9ab29a 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.students.controller.getStudentProfile.e2e-spec.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/student/_tests_/e2e/student.students.controller.getStudentProfile.e2e-spec.ts @@ -9,7 +9,7 @@ import { mockUserLoginInfo, } from "../../../../testHelpers"; import { saveFakeStudent } from "@sims/test-utils"; -import { determinePDStatus, getUserFullName } from "../../../../utilities"; +import { getUserFullName } from "../../../../utilities"; import { TestingModule } from "@nestjs/testing"; describe("StudentInstitutionsController(e2e)-getStudentProfile", () => { @@ -62,7 +62,7 @@ describe("StudentInstitutionsController(e2e)-getStudentProfile", () => { }, phone: student.contactInfo.phone, }, - pdStatus: determinePDStatus(student), + disabilityStatus: student.disabilityStatus, validSin: student.sinValidation.isValidSIN, sin: student.sinValidation.sin, }); diff --git a/sources/packages/backend/apps/api/src/route-controllers/student/models/student.dto.ts b/sources/packages/backend/apps/api/src/route-controllers/student/models/student.dto.ts index 5d1b91b0fc..1ce9456571 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/student/models/student.dto.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/student/models/student.dto.ts @@ -17,12 +17,12 @@ import { FileOriginType, NOTE_DESCRIPTION_MAX_LENGTH, FILE_NAME_MAX_LENGTH, + DisabilityStatus, } from "@sims/sims-db"; import { AddressAPIOutDTO, AddressDetailsAPIInDTO, } from "../../../route-controllers/models/common.dto"; -import { StudentPDStatus } from "../../../types"; export class ContactInformationAPIOutDTO { address: AddressAPIOutDTO; @@ -180,7 +180,7 @@ export class StudentProfileAPIOutDTO { dateOfBirth: string; contact: ContactInformationAPIOutDTO; validSin: boolean; - pdStatus: StudentPDStatus; + disabilityStatus: DisabilityStatus; sin: string; } diff --git a/sources/packages/backend/apps/api/src/route-controllers/student/student.controller.service.ts b/sources/packages/backend/apps/api/src/route-controllers/student/student.controller.service.ts index 6783e859b0..fd39e92370 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/student/student.controller.service.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/student/student.controller.service.ts @@ -11,7 +11,7 @@ import { ApplicationPaginationOptionsAPIInDTO, PaginatedResultsAPIOutDTO, } from "../models/pagination.dto"; -import { determinePDStatus, getUserFullName } from "../../utilities"; +import { getUserFullName } from "../../utilities"; import { getISODateOnlyString } from "@sims/utilities"; import { AddressInfo, Application, Student } from "@sims/sims-db"; import { @@ -131,7 +131,7 @@ export class StudentControllerService { address: transformAddressDetailsForAddressBlockForm(address), phone: student.contactInfo.phone, }, - pdStatus: determinePDStatus(student), + disabilityStatus: student.disabilityStatus, validSin: student.sinValidation.isValidSIN, sin: student.sinValidation.sin, }; diff --git a/sources/packages/backend/apps/api/src/route-controllers/student/student.students.controller.e2e-spec.ts b/sources/packages/backend/apps/api/src/route-controllers/student/student.students.controller.e2e-spec.ts index 5e08f96da6..9fe089b673 100644 --- a/sources/packages/backend/apps/api/src/route-controllers/student/student.students.controller.e2e-spec.ts +++ b/sources/packages/backend/apps/api/src/route-controllers/student/student.students.controller.e2e-spec.ts @@ -37,7 +37,7 @@ describe("Test ATBC Controller", () => { // Act/Assert await request(app.getHttpServer()) - .patch("/students/atbc/apply-pd-status") + .patch("/students/atbc/apply-disability-status") .auth(accessToken, BEARER_AUTH_TYPE) .expect(HttpStatus.OK); }); diff --git a/sources/packages/backend/apps/api/src/services/student/student.service.ts b/sources/packages/backend/apps/api/src/services/student/student.service.ts index 646b7f8c56..93760ffbc6 100644 --- a/sources/packages/backend/apps/api/src/services/student/student.service.ts +++ b/sources/packages/backend/apps/api/src/services/student/student.service.ts @@ -14,6 +14,7 @@ import { DisbursementOverawardOriginType, RestrictionNotificationType, StudentRestriction, + DisabilityStatus, } from "@sims/sims-db"; import { DataSource, EntityManager } from "typeorm"; import { StudentUserToken } from "../../auth/userToken.interface"; @@ -69,6 +70,7 @@ export class StudentService extends RecordDataModelService { "student.studentPDVerified", "student.studentPDSentAt", "student.studentPDUpdateAt", + "student.disabilityStatus", "sinValidation.id", "sinValidation.sin", "sinValidation.isValidSIN", @@ -166,11 +168,19 @@ export class StudentService extends RecordDataModelService { student.sinConsent = studentInfo.sinConsent; try { // Get PD status from SFAS integration data. - student.studentPDVerified = await this.sfasIndividualService.getPDStatus( - user.lastName, - student.birthDate, - studentSIN, - ); + const sfasIndividual = + await this.sfasIndividualService.getIndividualStudent( + user.lastName, + student.birthDate, + studentSIN, + ); + // If SFAS individual exist with matching details, read the pd status. + if (sfasIndividual) { + student.studentPDVerified = sfasIndividual.pdStatus; + student.disabilityStatus = this.getDisabilityStatus( + sfasIndividual.pdStatus, + ); + } } catch (error) { this.logger.error("Unable to get SFAS information of student."); this.logger.error(error); @@ -667,4 +677,19 @@ export class StudentService extends RecordDataModelService { entityManager, ); } + + /** + * Get student disability status. + * @param pdVerified sfas pdVerified flag. + * @returns disability status. + */ + private getDisabilityStatus(pdVerified: boolean): DisabilityStatus { + if (pdVerified) { + return DisabilityStatus.PD; + } + if (pdVerified === false) { + return DisabilityStatus.Declined; + } + return DisabilityStatus.NotRequested; + } } diff --git a/sources/packages/backend/apps/api/src/types/index.ts b/sources/packages/backend/apps/api/src/types/index.ts index 2f6d61f851..3498422ae5 100644 --- a/sources/packages/backend/apps/api/src/types/index.ts +++ b/sources/packages/backend/apps/api/src/types/index.ts @@ -4,5 +4,4 @@ export * from "./formsFlow"; export * from "./institutionAuth"; export * from "./optionItem"; export * from "./apiProcessError"; -export * from "./pdStatus"; export * from "./clientTypeBaseRoute"; diff --git a/sources/packages/backend/apps/api/src/types/pdStatus.ts b/sources/packages/backend/apps/api/src/types/pdStatus.ts deleted file mode 100644 index 89d7bba521..0000000000 --- a/sources/packages/backend/apps/api/src/types/pdStatus.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Enumeration for student permanent disability status. - */ -export enum StudentPDStatus { - Yes = "Yes", - No = "No", - NotRequested = "Not Requested", - Pending = "Pending", -} diff --git a/sources/packages/backend/apps/api/src/utilities/student-utils.ts b/sources/packages/backend/apps/api/src/utilities/student-utils.ts index 96f9e1c813..f2614f45e2 100644 --- a/sources/packages/backend/apps/api/src/utilities/student-utils.ts +++ b/sources/packages/backend/apps/api/src/utilities/student-utils.ts @@ -1,24 +1,3 @@ -import { StudentPDStatus } from "../types/pdStatus"; -import { Student } from "@sims/sims-db"; - -/** - * Determines the permanent disability status from Student Entity. - * @param student - * @returns PDStatus enum - */ -export const determinePDStatus = (student: Student): StudentPDStatus => { - if (student.studentPDVerified) { - return StudentPDStatus.Yes; - } - if (student.studentPDVerified === false) { - return StudentPDStatus.No; - } - if (student.studentPDSentAt) { - return StudentPDStatus.Pending; - } - return StudentPDStatus.NotRequested; -}; - export const deliveryMethod = ( deliveredOnline: boolean, deliveredOnSite: boolean, diff --git a/sources/packages/backend/apps/db-migrations/src/migrations/1689350242512-AddStudentDisabilityStatusCol.ts b/sources/packages/backend/apps/db-migrations/src/migrations/1689350242512-AddStudentDisabilityStatusCol.ts new file mode 100644 index 0000000000..b4192adb20 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/migrations/1689350242512-AddStudentDisabilityStatusCol.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; +import { getSQLFileData } from "../utilities/sqlLoader"; + +export class AddStudentDisabilityStatusCol1689350242512 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + getSQLFileData("Create-disability-status.sql", "Types"), + ); + await queryRunner.query( + getSQLFileData("Add-col-disability-status.sql", "Student"), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + getSQLFileData("Drop-col-disability-status.sql", "Student"), + ); + await queryRunner.query( + getSQLFileData("Drop-disability-status.sql", "Types"), + ); + } +} diff --git a/sources/packages/backend/apps/db-migrations/src/sql/Student/Add-col-disability-status.sql b/sources/packages/backend/apps/db-migrations/src/sql/Student/Add-col-disability-status.sql new file mode 100644 index 0000000000..22edea578e --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/Student/Add-col-disability-status.sql @@ -0,0 +1,18 @@ +ALTER TABLE + sims.students +ADD + COLUMN IF NOT EXISTS disability_status sims.disability_status NOT NULL DEFAULT 'Not requested'; + +COMMENT ON COLUMN sims.students.disability_status IS 'Disability status of the student. The disability could be PD or PPD.'; + +-- Update the disability_status column based on pd_verified and pd_date_sent for existing data. +UPDATE + sims.students +SET + disability_status = CASE + WHEN pd_verified IS NULL + AND pd_date_sent IS NOT NULL THEN 'Requested' + WHEN pd_verified = true THEN 'PD' + WHEN pd_verified = false THEN 'Declined' + ELSE 'Not requested' :: sims.disability_status + END; \ No newline at end of file diff --git a/sources/packages/backend/apps/db-migrations/src/sql/Student/Drop-col-disability-status.sql b/sources/packages/backend/apps/db-migrations/src/sql/Student/Drop-col-disability-status.sql new file mode 100644 index 0000000000..f94126df52 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/Student/Drop-col-disability-status.sql @@ -0,0 +1,2 @@ +ALTER TABLE + sims.students DROP COLUMN disability_status; \ No newline at end of file diff --git a/sources/packages/backend/apps/db-migrations/src/sql/Types/Create-disability-status.sql b/sources/packages/backend/apps/db-migrations/src/sql/Types/Create-disability-status.sql new file mode 100644 index 0000000000..afdd6c4776 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/Types/Create-disability-status.sql @@ -0,0 +1,7 @@ +CREATE TYPE sims.disability_status AS ENUM ( + 'Not requested', + 'Requested', + 'PD', + 'PPD', + 'Declined' +); \ No newline at end of file diff --git a/sources/packages/backend/apps/db-migrations/src/sql/Types/Drop-disability-status.sql b/sources/packages/backend/apps/db-migrations/src/sql/Types/Drop-disability-status.sql new file mode 100644 index 0000000000..0617075d32 --- /dev/null +++ b/sources/packages/backend/apps/db-migrations/src/sql/Types/Drop-disability-status.sql @@ -0,0 +1 @@ +DROP TYPE sims.disability_status; \ No newline at end of file diff --git a/sources/packages/backend/libs/integrations/src/atbc-integration/atbc-integration.processing.service.ts b/sources/packages/backend/libs/integrations/src/atbc-integration/atbc-integration.processing.service.ts index b1f764b740..7e6caf64fa 100644 --- a/sources/packages/backend/libs/integrations/src/atbc-integration/atbc-integration.processing.service.ts +++ b/sources/packages/backend/libs/integrations/src/atbc-integration/atbc-integration.processing.service.ts @@ -21,11 +21,13 @@ export class ATBCIntegrationProcessingService { ) {} /** - * Apply for PD status calling the ATBC endpoint. + * Apply for disability status calling the ATBC endpoint. * @param studentId student who applied for PD status. * @returns ATBC response. */ - async applyForPDStatus(studentId: number): Promise { + async applyForDisabilityStatus( + studentId: number, + ): Promise { // Student who requested to apply PD status. const student = await this.studentService.getStudentById(studentId); const payload: ATBCCreateClientPayload = { @@ -45,7 +47,10 @@ export class ATBCIntegrationProcessingService { if (response) { const auditUser = await this.systemUsersService.systemUser(); // Update PD sent date. - await this.studentService.updatePDSentDate(student.id, auditUser); + await this.studentService.updateDisabilityRequested( + student.id, + auditUser, + ); } return response; } diff --git a/sources/packages/backend/libs/integrations/src/services/student/student.service.ts b/sources/packages/backend/libs/integrations/src/services/student/student.service.ts index 83c7a67ba0..bb28a97dcb 100644 --- a/sources/packages/backend/libs/integrations/src/services/student/student.service.ts +++ b/sources/packages/backend/libs/integrations/src/services/student/student.service.ts @@ -1,5 +1,6 @@ import { Injectable } from "@nestjs/common"; import { + DisabilityStatus, RecordDataModelService, SINValidation, Student, @@ -7,7 +8,7 @@ import { } from "@sims/sims-db"; import { getUTCNow } from "@sims/utilities"; import { InjectLogger, LoggerService } from "@sims/utilities/logger"; -import { DataSource, EntityManager } from "typeorm"; +import { DataSource, EntityManager, UpdateResult } from "typeorm"; @Injectable() export class StudentService extends RecordDataModelService { @@ -32,23 +33,25 @@ export class StudentService extends RecordDataModelService { } /** - * Update the PD Sent Date + * Update the disability status to requested. * @param studentId student who's PD status is to be updated. * @param auditUser user who is making the changes. - * @returns Student who's PD sent date is updated. + * @returns update result. */ - async updatePDSentDate(studentId: number, auditUser: User): Promise { - // get the Student Object - const studentToUpdate = await this.repo.findOneOrFail({ - where: { id: studentId }, - }); - if (studentToUpdate) { - const now = new Date(); - studentToUpdate.studentPDSentAt = now; - studentToUpdate.modifier = auditUser; - studentToUpdate.updatedAt = now; - return this.repo.save(studentToUpdate); - } + async updateDisabilityRequested( + studentId: number, + auditUser: User, + ): Promise { + const now = new Date(); + return this.repo.update( + { id: studentId }, + { + studentPDSentAt: now, + modifier: auditUser, + updatedAt: now, + disabilityStatus: DisabilityStatus.Requested, + }, + ); } /** diff --git a/sources/packages/backend/libs/services/src/sfas/sfas-individual.service.ts b/sources/packages/backend/libs/services/src/sfas/sfas-individual.service.ts index 77093f270d..08b8a222bb 100644 --- a/sources/packages/backend/libs/services/src/sfas/sfas-individual.service.ts +++ b/sources/packages/backend/libs/services/src/sfas/sfas-individual.service.ts @@ -12,20 +12,17 @@ export class SFASIndividualService extends DataModelService { } /** - * Get the permanent disability status from SFAS, if available. + * Get SFAS student, if available. * @param lastName student last name. * @param birthDate student data of birth. * @param sin student Social Insurance Number. - * @returns the permanent disability if present or null. Even when - * the record is present os SFAS, the value could still be null, - * what means that a permanent disability verification was never - * executed for the student. + * @returns SFAS Student. */ - async getPDStatus( + async getIndividualStudent( lastName: string, birthDate: string, sin: string, - ): Promise { + ): Promise { const individual = await this.repo .createQueryBuilder("individual") .select("individual.pdStatus") @@ -36,7 +33,7 @@ export class SFASIndividualService extends DataModelService { .andWhere("individual.birthDate = :birthDate", { birthDate }) .getOne(); - return individual?.pdStatus; + return individual; } /** diff --git a/sources/packages/backend/libs/sims-db/src/entities/index.ts b/sources/packages/backend/libs/sims-db/src/entities/index.ts index fde2d4321e..38f6647047 100644 --- a/sources/packages/backend/libs/sims-db/src/entities/index.ts +++ b/sources/packages/backend/libs/sims-db/src/entities/index.ts @@ -84,3 +84,4 @@ export * from "./queue_configuration.model"; export * from "./student-assessment-status.type"; export * from "./application-offering-change-request-status.type"; export * from "./application-offering-change-request.model"; +export * from "./student-disability-status.type"; diff --git a/sources/packages/backend/libs/sims-db/src/entities/student-disability-status.type.ts b/sources/packages/backend/libs/sims-db/src/entities/student-disability-status.type.ts new file mode 100644 index 0000000000..c9eddc67ad --- /dev/null +++ b/sources/packages/backend/libs/sims-db/src/entities/student-disability-status.type.ts @@ -0,0 +1,12 @@ +/** + * Disability status of student. + */ +export enum DisabilityStatus { + NotRequested = "Not requested", + Requested = "Requested", + /** Permanent Disability. */ + PD = "PD", + /** Persistent and Prolonged Disability.*/ + PPD = "PPD", + Declined = "Declined", +} diff --git a/sources/packages/backend/libs/sims-db/src/entities/student.model.ts b/sources/packages/backend/libs/sims-db/src/entities/student.model.ts index 41a8b55455..c247efcb69 100644 --- a/sources/packages/backend/libs/sims-db/src/entities/student.model.ts +++ b/sources/packages/backend/libs/sims-db/src/entities/student.model.ts @@ -12,7 +12,7 @@ import { import { ColumnNames, TableNames } from "../constant"; import { RecordDataModel } from "./record.model"; import { User } from "./user.model"; -import { ContactInfo, Note, StudentRestriction } from "."; +import { ContactInfo, Note, DisabilityStatus, StudentRestriction } from "."; import { SINValidation } from "./sin-validation.model"; @Entity({ name: TableNames.Student }) @@ -101,4 +101,15 @@ export class Student extends RecordDataModel { }, ) studentRestrictions?: StudentRestriction[]; + + /** + * Disability status of the student. + */ + @Column({ + name: "disability_status", + type: "enum", + enum: DisabilityStatus, + enumName: "DisabilityStatus", + }) + disabilityStatus: DisabilityStatus; } diff --git a/sources/packages/backend/libs/test-utils/src/factories/student.ts b/sources/packages/backend/libs/test-utils/src/factories/student.ts index e23cc0e020..f9e9f02657 100644 --- a/sources/packages/backend/libs/test-utils/src/factories/student.ts +++ b/sources/packages/backend/libs/test-utils/src/factories/student.ts @@ -1,5 +1,5 @@ import * as faker from "faker"; -import { SINValidation, Student, User } from "@sims/sims-db"; +import { DisabilityStatus, SINValidation, Student, User } from "@sims/sims-db"; import { createFakeUser } from "@sims/test-utils"; import { DataSource } from "typeorm"; import { createFakeSINValidation } from "./sin-validation"; @@ -23,6 +23,7 @@ export function createFakeStudent(user?: User): Student { phone: faker.phone.phoneNumber(), }; student.sinConsent = true; + student.disabilityStatus = DisabilityStatus.NotRequested; return student; } diff --git a/sources/packages/forms/src/form-definitions/sfaa2021-22.json b/sources/packages/forms/src/form-definitions/sfaa2021-22.json index ef4a1fb740..964c870e27 100644 --- a/sources/packages/forms/src/form-definitions/sfaa2021-22.json +++ b/sources/packages/forms/src/form-definitions/sfaa2021-22.json @@ -5468,8 +5468,7 @@ "properties": {}, "lockKey": true, "calculateServer": true, - "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating selectedStudyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If program/study period not listed is selected, validate the study end date to be after given days before now.\r\nvalue = !!data.studyendDate && isGivenDateBeforeToday(data.studyendDate);\r\n", - "isNew": false + "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating selectedStudyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If program/study period not listed is selected, validate the study end date to be after given days before now.\r\nvalue = !!data.studyendDate && isGivenDateBeforeToday(data.studyendDate);\r\n" }, { "input": true, @@ -5489,8 +5488,7 @@ "properties": {}, "lockKey": true, "calculateServer": true, - "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating studyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If a study period is selected, validate its study end date to be after given days before now.\r\nvalue =\r\n !!data.selectedOfferingEndDate &&\r\n isGivenDateBeforeToday(data.selectedOfferingEndDate);\r\n", - "isNew": false + "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating studyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If a study period is selected, validate its study end date to be after given days before now.\r\nvalue =\r\n !!data.selectedOfferingEndDate &&\r\n isGivenDateBeforeToday(data.selectedOfferingEndDate);\r\n" }, { "input": true, @@ -6529,11 +6527,11 @@ "truncateMultipleSpaces": false }, { - "label": "Permanent disability status", + "label": "Disability status", "customClass": "font-weight-bold", "disabled": true, "tableView": true, - "key": "pdStatus", + "key": "disabilityStatus", "type": "textfield", "input": true, "hideOnChildrenHidden": false, @@ -6579,7 +6577,7 @@ "pattern": "" }, "conditional": { - "show": null, + "show": "", "when": null, "eq": "" }, @@ -6604,7 +6602,9 @@ "id": "eq3hnwv", "addons": [], "displayMask": "", - "truncateMultipleSpaces": false + "truncateMultipleSpaces": false, + "tags": [], + "lockKey": true } ], "width": 6, diff --git a/sources/packages/forms/src/form-definitions/sfaa2022-23.json b/sources/packages/forms/src/form-definitions/sfaa2022-23.json index 2697ed1ddd..249443be01 100644 --- a/sources/packages/forms/src/form-definitions/sfaa2022-23.json +++ b/sources/packages/forms/src/form-definitions/sfaa2022-23.json @@ -5468,8 +5468,7 @@ "properties": {}, "lockKey": true, "calculateServer": true, - "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating selectedStudyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If program/study period not listed is selected, validate the study end date to be after given days before now.\r\nvalue = !!data.studyendDate && isGivenDateBeforeToday(data.studyendDate);\r\n", - "isNew": false + "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating selectedStudyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If program/study period not listed is selected, validate the study end date to be after given days before now.\r\nvalue = !!data.studyendDate && isGivenDateBeforeToday(data.studyendDate);\r\n" }, { "input": true, @@ -5489,8 +5488,7 @@ "properties": {}, "lockKey": true, "calculateServer": true, - "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating studyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If a study period is selected, validate its study end date to be after given days before now.\r\nvalue =\r\n !!data.selectedOfferingEndDate &&\r\n isGivenDateBeforeToday(data.selectedOfferingEndDate);\r\n", - "isNew": false + "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating studyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If a study period is selected, validate its study end date to be after given days before now.\r\nvalue =\r\n !!data.selectedOfferingEndDate &&\r\n isGivenDateBeforeToday(data.selectedOfferingEndDate);\r\n" }, { "input": true, @@ -6529,11 +6527,11 @@ "truncateMultipleSpaces": false }, { - "label": "Permanent disability status", + "label": "Disability status", "customClass": "font-weight-bold", "disabled": true, "tableView": true, - "key": "pdStatus", + "key": "disabilityStatus", "type": "textfield", "input": true, "hideOnChildrenHidden": false, @@ -6579,7 +6577,7 @@ "pattern": "" }, "conditional": { - "show": null, + "show": "", "when": null, "eq": "" }, @@ -6604,7 +6602,9 @@ "id": "eq3hnwv", "addons": [], "displayMask": "", - "truncateMultipleSpaces": false + "truncateMultipleSpaces": false, + "tags": [], + "lockKey": true } ], "width": 6, diff --git a/sources/packages/forms/src/form-definitions/sfaa2023-24.json b/sources/packages/forms/src/form-definitions/sfaa2023-24.json index 5fdf3077ac..a0e0d7b38a 100644 --- a/sources/packages/forms/src/form-definitions/sfaa2023-24.json +++ b/sources/packages/forms/src/form-definitions/sfaa2023-24.json @@ -5468,8 +5468,7 @@ "properties": {}, "lockKey": true, "calculateServer": true, - "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating selectedStudyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If program/study period not listed is selected, validate the study end date to be after given days before now.\r\nvalue = !!data.studyendDate && isGivenDateBeforeToday(data.studyendDate);\r\n", - "isNew": false + "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating selectedStudyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If program/study period not listed is selected, validate the study end date to be after given days before now.\r\nvalue = !!data.studyendDate && isGivenDateBeforeToday(data.studyendDate);\r\n" }, { "input": true, @@ -5489,8 +5488,7 @@ "properties": {}, "lockKey": true, "calculateServer": true, - "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating studyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If a study period is selected, validate its study end date to be after given days before now.\r\nvalue =\r\n !!data.selectedOfferingEndDate &&\r\n isGivenDateBeforeToday(data.selectedOfferingEndDate);\r\n", - "isNew": false + "calculateValue": "/**\r\n * Validates if the date provided is before today.\r\n *\r\n * The same validation exists on calculating studyEndDateBeforeToday,\r\n * other student application forms, program information request form\r\n * and also on the server side.\r\n *\r\n * When there is an update to this logic make sure to update in all the above.\r\n *\r\n */\r\n\r\nfunction isGivenDateBeforeToday(givenDate) {\r\n return moment\r\n .utc(givenDate)\r\n .isBefore(moment.utc(new Date()).format(\"YYYY-MM-DD\"), \"day\");\r\n}\r\n\r\n// If a study period is selected, validate its study end date to be after given days before now.\r\nvalue =\r\n !!data.selectedOfferingEndDate &&\r\n isGivenDateBeforeToday(data.selectedOfferingEndDate);\r\n" }, { "input": true, @@ -6529,11 +6527,11 @@ "truncateMultipleSpaces": false }, { - "label": "Permanent disability status", + "label": "Disability status", "customClass": "font-weight-bold", "disabled": true, "tableView": true, - "key": "pdStatus", + "key": "disabilityStatus", "type": "textfield", "input": true, "hideOnChildrenHidden": false, @@ -6579,7 +6577,7 @@ "pattern": "" }, "conditional": { - "show": null, + "show": "", "when": null, "eq": "" }, @@ -6604,7 +6602,9 @@ "id": "eq3hnwv", "addons": [], "displayMask": "", - "truncateMultipleSpaces": false + "truncateMultipleSpaces": false, + "tags": [], + "lockKey": true } ], "width": 6, diff --git a/sources/packages/forms/src/form-definitions/studentprofile.json b/sources/packages/forms/src/form-definitions/studentprofile.json index 6c3314f87a..d9c40987a2 100644 --- a/sources/packages/forms/src/form-definitions/studentprofile.json +++ b/sources/packages/forms/src/form-definitions/studentprofile.json @@ -1613,13 +1613,13 @@ "tags": [] }, { - "label": "Permanent disability (PD) status", + "label": "Disability status", "labelPosition": "top", "labelWidth": "", "labelMargin": "", "placeholder": "", "description": "", - "tooltip": "If you have a permanent disability, you may apply for a status here, that we will use to help you apply for eligible grants or bursaries in your applications. Please go to studentaidbc.ca for more information.", + "tooltip": "If you have a disability, you may apply for a status here, that we will use to help you apply for eligible grants or bursaries in your applications. Please go to studentaidbc.ca for more information.", "prefix": "", "suffix": "", "widget": { @@ -1673,11 +1673,11 @@ "unique": false, "errorLabel": "", "errors": "", - "key": "pdStatus", + "key": "disabilityStatus", "tags": [], "properties": {}, "conditional": { - "show": null, + "show": "", "when": null, "eq": "", "json": "" @@ -1702,7 +1702,8 @@ "addons": [], "inputType": "text", "id": "eeplqe", - "defaultValue": "" + "defaultValue": "", + "lockKey": true }, { "label": "Apply for PD status", @@ -1730,9 +1731,9 @@ "tags": [], "properties": {}, "conditional": { - "show": true, - "when": "pdStatus", - "eq": "Not Requested", + "show": "true", + "when": "disabilityStatus", + "eq": "Not requested", "json": "" }, "customConditional": "", diff --git a/sources/packages/web/src/components/common/students/StudentProfile.vue b/sources/packages/web/src/components/common/students/StudentProfile.vue index d0937ff581..4e0eb4b270 100644 --- a/sources/packages/web/src/components/common/students/StudentProfile.vue +++ b/sources/packages/web/src/components/common/students/StudentProfile.vue @@ -39,8 +39,8 @@ diff --git a/sources/packages/web/src/constants/error-code.constants.ts b/sources/packages/web/src/constants/error-code.constants.ts index 90b4cfa6bd..044cefbf9f 100644 --- a/sources/packages/web/src/constants/error-code.constants.ts +++ b/sources/packages/web/src/constants/error-code.constants.ts @@ -73,3 +73,7 @@ export const DUPLICATE_INSTITUTION_LOCATION_CODE = * Duplicate SABC code for the institution. */ export const DUPLICATE_SABC_CODE = "DUPLICATE_SABC_CODE"; +/** + * Request for disability not allowed. + */ +export const DISABILITY_REQUEST_NOT_ALLOWED = "DISABILITY_REQUEST_NOT_ALLOWED"; diff --git a/sources/packages/web/src/services/StudentService.ts b/sources/packages/web/src/services/StudentService.ts index ef195115cc..a95d51fe36 100644 --- a/sources/packages/web/src/services/StudentService.ts +++ b/sources/packages/web/src/services/StudentService.ts @@ -73,8 +73,8 @@ export class StudentService { await ApiClient.Students.synchronizeFromUserToken(); } - async applyForPDStatus(): Promise { - return ApiClient.Students.applyForPDStatus(); + async applyForDisabilityStatus(): Promise { + await ApiClient.Students.applyForDisabilityStatus(); } /** diff --git a/sources/packages/web/src/services/http/StudentApi.ts b/sources/packages/web/src/services/http/StudentApi.ts index 9845265930..80421458f5 100644 --- a/sources/packages/web/src/services/http/StudentApi.ts +++ b/sources/packages/web/src/services/http/StudentApi.ts @@ -66,8 +66,11 @@ export class StudentApi extends HttpBaseClient { * Student should only be allowed to check the PD status once and the * SIN validation must be already done with a successful result. */ - async applyForPDStatus(): Promise { - await this.patchCall(this.addClientRoot("atbc/apply-pd-status"), null); + async applyForDisabilityStatus(): Promise { + await this.patchCall( + this.addClientRoot("atbc/apply-disability-status"), + null, + ); } /** diff --git a/sources/packages/web/src/services/http/dto/Student.dto.ts b/sources/packages/web/src/services/http/dto/Student.dto.ts index 58d6a87f90..7f0821a46c 100644 --- a/sources/packages/web/src/services/http/dto/Student.dto.ts +++ b/sources/packages/web/src/services/http/dto/Student.dto.ts @@ -1,4 +1,4 @@ -import { FileOriginType, StudentPDStatus } from "@/types"; +import { FileOriginType, DisabilityStatus } from "@/types"; import { ContactInformationAPIOutDTO } from "./Address.dto"; import { AddressDetailsFormAPIDTO } from "./Common.dto"; import { Expose } from "class-transformer"; @@ -15,6 +15,8 @@ export class CreateStudentAPIInDTO extends AddressDetailsFormAPIDTO { sinNumber: string; @Expose() gender: string; + @Expose() + sinConsent: boolean; } /** @@ -41,7 +43,7 @@ export interface StudentProfileAPIOutDTO { dateOfBirth: string; contact: ContactInformationAPIOutDTO; validSin: boolean; - pdStatus: StudentPDStatus; + disabilityStatus: DisabilityStatus; sin: string; sinConsent: boolean; hasRestriction?: boolean; diff --git a/sources/packages/web/src/types/contracts/StudentContract.ts b/sources/packages/web/src/types/contracts/StudentContract.ts index 0489903c81..247b43f0d3 100644 --- a/sources/packages/web/src/types/contracts/StudentContract.ts +++ b/sources/packages/web/src/types/contracts/StudentContract.ts @@ -10,13 +10,16 @@ export interface StudentProfile extends StudentProfileAPIOutDTO { } /** - * Enumeration for student permanent disability status. + * Disability status of student. */ -export enum StudentPDStatus { - Yes = "Yes", - No = "No", - NotRequested = "Not Requested", - Pending = "Pending", +export enum DisabilityStatus { + NotRequested = "Not requested", + Requested = "Requested", + /** Permanent Disability. */ + PD = "PD", + /** Persistent and Prolonged Disability.*/ + PPD = "PPD", + Declined = "Declined", } /** @@ -69,7 +72,7 @@ export enum StudentProfileFormModes { export type StudentProfileFormModel = Pick< StudentProfileAPIOutDTO, - "firstName" | "lastName" | "gender" | "email" | "pdStatus" + "firstName" | "lastName" | "gender" | "email" | "disabilityStatus" > & AddressDetailsFormAPIDTO & { phone: string; diff --git a/sources/packages/web/src/views/student/StudentProfileEdit.vue b/sources/packages/web/src/views/student/StudentProfileEdit.vue index 44af33d4c2..7b53a9f748 100644 --- a/sources/packages/web/src/views/student/StudentProfileEdit.vue +++ b/sources/packages/web/src/views/student/StudentProfileEdit.vue @@ -26,8 +26,9 @@ import PDStatusApplicationModal from "@/components/students/modals/PDStatusAppli import { StudentService } from "@/services/StudentService"; import { UpdateStudentAPIInDTO } from "@/services/http/dto/Student.dto"; import { AuthService } from "@/services/AuthService"; -import { FormIOForm } from "@/types"; +import { ApiProcessError, FormIOForm } from "@/types"; import StudentProfileForm from "@/components/common/StudentProfileForm.vue"; +import { DISABILITY_REQUEST_NOT_ALLOWED } from "@/constants"; export default defineComponent({ components: { @@ -60,13 +61,20 @@ export default defineComponent({ const applyPDStatus = async () => { try { - await StudentService.shared.applyForPDStatus(); + await StudentService.shared.applyForDisabilityStatus(); snackBar.success( "Your application is submitted. The outcome will display on your profile", ); - } catch { + } catch (error: unknown) { + if ( + error instanceof ApiProcessError && + error.errorType === DISABILITY_REQUEST_NOT_ALLOWED + ) { + snackBar.error(`${error.message}`); + return; + } snackBar.error( - "An error happened during the apply PD process. Please try after sometime.", + "Unexpected error while applying for disability status. Please try after sometime.", ); } await getStudentDetails(); diff --git a/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue b/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue index 4ece5a65e2..64f64ed210 100644 --- a/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue +++ b/sources/packages/web/src/views/student/financial-aid-application/FullTimeApplication.vue @@ -154,7 +154,7 @@ export default defineComponent({ studentPhoneNumber: studentInfo.contact.phone, studentHomeAddress: formattedAddress, studentEmail: studentInfo.email, - pdStatus: studentInfo.pdStatus, + disabilityStatus: studentInfo.disabilityStatus, }; const programYear = { programYearStartDate: applicationData.programYearStartDate,