Skip to content

Comments

#2987 - Institution prevent remittance - Enable location only restrictions#5791

Merged
dheepak-aot merged 16 commits intomainfrom
feature/#2987-institution-prevent-remittance-1
Feb 25, 2026
Merged

#2987 - Institution prevent remittance - Enable location only restrictions#5791
dheepak-aot merged 16 commits intomainfrom
feature/#2987-institution-prevent-remittance-1

Conversation

@dheepak-aot
Copy link
Collaborator

@dheepak-aot dheepak-aot commented Feb 22, 2026

Institution prevent remittance - Enable location only restrictions

DB Migrations

  • Added a generic metadata column to sims.restrictions and updated the metadata for SUS retriction.
  • Created a new restriction REMIT with metadata values populated.

Metadata framework

  • The metadata column in sims.restrictions has a property fieldRequirements to evaluate the field requirements of the restricted party(Student restriction | Institution restriction).
  • The validators are built for the metadata framework(kept in API scope as of now) to validate the field requirements based on the metadata property and actual field values.
  • Dropped the NOT NULL constraint for program_id and location_id in sims.institution_restrictions. The program and location validations are governed by restriction metadata now.
  • Updated the unique constraint institution_id_location_id_program_id_restriction_id_is_active_unique to consider NULL as value for uniqueness for the existing combination of institution_id,location_id,program_id and restriction_id

Rollback evidence

image image image

API

  • Updated the getReasonsOptionsList to make the restriction category as optional parameter.
  • Updated the getInstitutionRestrictions to return institution restrictions with program or location as NULL(Will adjust the E2E for this in next PR).
  • Update addInstitutionRestriction to adapt the program and locations being potentially NULL and use the metadata to execute field requirement validations.

UI

  • ON add restrictions page, the UI optionally displays Program and Locations component based on selected restriction.
image image image image

E2E Tests

  • RestrictionAESTController(e2e)-addInstitutionRestriction.
 RestrictionAESTController(e2e)-addInstitutionRestriction.                                                                                                                         
    √ Should add multiple SUS institution restrictions when a valid payload with program ID and multiple locations IDs is submitted. (231 ms)                                       
    √ Should add multiple REMIT institution restrictions when a valid payload with multiple locations IDs is submitted. (96 ms)                                                     
    √ Should add a single institution only institution restriction when a valid payload without program ID and location IDs is submitted. (44 ms)                                                                                                            
    √ Should throw a bad request exception on add REMIT restriction when no locations were provided in the request payload. (22 ms)                                                 
    √ Should throw a bad request exception on add REMIT restriction when program is provided in the request payload. (40 ms)                                                        
    √ Should throw a bad request exception on add SUS restriction when no program and locations were provided in the request payload. (20 ms)                                       

  • RestrictionAESTController(e2e)-getReasonsOptionsList.
RestrictionAESTController(e2e)-getReasonsOptionsList.                                                                                                                             
    √ Should get all the Institution restrictions reasons list when there is no restriction category filter applied. (17 ms)                                                                                                                                      
    Should get reasons options list for a restriction type when the request is valid.                                                                                               
      √ Should get Provincial restrictions reasons list filtered by specific category when Provincial restrictions are requested for a category. (107 ms)                           
      √ Should get Institution restrictions reasons list filtered by specific category when Institution restrictions are requested for a category. (24 ms)

@dheepak-aot dheepak-aot self-assigned this Feb 22, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Enables “location-only” (and more flexible) institution restrictions by introducing restriction metadata-driven field requirements, updating the DB schema to allow nullable program/location links, and propagating the new contract through the API, UI, and tests.

Changes:

  • Added restriction metadata.fieldRequirements (and FieldRequirementType) to drive which fields are required/optional/not allowed per restriction reason.
  • Updated institution restriction persistence to allow program_id/location_id to be nullable, including updated uniqueness constraints and a new REMIT restriction seed.
  • Updated AEST restriction endpoints + web UI modal to consume field requirements, with expanded e2e coverage.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
sources/packages/web/src/types/contracts/RestrictionContract.ts Adds FieldRequirementType enum to support metadata-driven UI validation.
sources/packages/web/src/services/http/dto/Restriction.dto.ts Introduces RestrictionAPIOutDTO to return reasons with field requirements.
sources/packages/web/src/services/http/RestrictionApi.ts Makes category optional and updates return type for restriction reasons.
sources/packages/web/src/services/RestrictionService.ts Aligns service return types with new reasons DTO.
sources/packages/web/src/components/institutions/modals/AddRestrictionModal.vue Shows/hides program/location fields and applies rules based on fieldRequirements.
sources/packages/backend/libs/test-utils/src/models/common.model.ts Adds REMIT to RestrictionCode for test support.
sources/packages/backend/libs/test-utils/src/factories/restriction.ts Allows creating fake restrictions with metadata.
sources/packages/backend/libs/sims-db/src/entities/restriction.type.ts Adds RestrictionMetadata typing for restriction metadata.
sources/packages/backend/libs/sims-db/src/entities/restriction.model.ts Adds nullable metadata JSONB column to Restriction entity.
sources/packages/backend/libs/sims-db/src/entities/institution-restriction.model.ts Makes program/location relations nullable to support flexible applicability.
sources/packages/backend/libs/sims-db/src/entities/index.ts Exports new common types and adjusts export ordering.
sources/packages/backend/libs/sims-db/src/entities/common.type.ts Defines backend FieldRequirementType enum.
sources/packages/backend/libs/integrations/src/services/disbursement-schedule/disbursement-schedule.models.ts Makes institution restriction program/location optional and adjusts effective restriction filtering.
sources/packages/backend/apps/db-migrations/src/sql/Restrictions/Rollback-institution-restrictions-drop-program-location-not-null.sql Rollback for nullable program/location and unique index changes.
sources/packages/backend/apps/db-migrations/src/sql/Restrictions/Rollback-insert-remit-restriction.sql Rollback removal of REMIT restriction seed.
sources/packages/backend/apps/db-migrations/src/sql/Restrictions/Rollback-add-col-metadata-and-update-sus.sql Rollback for restrictions metadata column.
sources/packages/backend/apps/db-migrations/src/sql/Restrictions/Institution-restrictions-drop-program-location-not-null.sql Drops NOT NULL constraints and recreates unique index with NULL-aware semantics.
sources/packages/backend/apps/db-migrations/src/sql/Restrictions/Insert-remit-restriction.sql Seeds new REMIT restriction with metadata-based field requirements.
sources/packages/backend/apps/db-migrations/src/sql/Restrictions/Add-col-metadata-and-update-sus.sql Adds metadata column and populates SUS metadata.
sources/packages/backend/apps/db-migrations/src/migrations/1771391174102-InstitutionRestrictionDropProgramLocationNotNull.ts TypeORM migration wrapper for institution restriction nullability/index changes.
sources/packages/backend/apps/db-migrations/src/migrations/1771299851366-RestrictionAddColMetadataUpdateSUSInsertREMIT.ts TypeORM migration wrapper for metadata + SUS update + REMIT insert.
sources/packages/backend/apps/api/src/utilities/metadata-utils.ts Adds reusable validation for metadata-driven field requirements.
sources/packages/backend/apps/api/src/utilities/index.ts Re-exports metadata utilities.
sources/packages/backend/apps/api/src/services/restriction/restriction.service.ts Returns restriction metadata when fetching reasons.
sources/packages/backend/apps/api/src/services/restriction/models/institution-restriction.model.ts Adds models for institution restriction creation/validation.
sources/packages/backend/apps/api/src/services/restriction/institution-restriction.service.ts Supports optional program/location restrictions, metadata validation, and null joins.
sources/packages/backend/apps/api/src/route-controllers/restriction/restriction.aest.controller.ts Returns fieldRequirements on reasons and maps new validation errors to 400.
sources/packages/backend/apps/api/src/route-controllers/restriction/models/restriction.dto.ts Makes request filtering optional and adds RestrictionAPIOutDTO for reasons.
sources/packages/backend/apps/api/src/route-controllers/restriction/tests/e2e/restriction.aest.controller.getReasonsOptionsList.e2e-spec.ts Expands coverage for reasons list with/without category and metadata.
sources/packages/backend/apps/api/src/route-controllers/restriction/tests/e2e/restriction.aest.controller.addInstitutionRestriction.e2e-spec.ts Adds e2e coverage for SUS, REMIT, and institution-only restriction creation + validation failures.
sources/packages/backend/apps/api/src/constants/error-code.constants.ts Adds FIELD_REQUIREMENTS_NOT_VALID error code.
Comments suppressed due to low confidence (1)

sources/packages/backend/libs/integrations/src/services/disbursement-schedule/disbursement-schedule.models.ts:422

  • getEffectiveInstitutionRestrictions now uses optional chaining comparisons (restriction.program?.id === programId and restriction.location?.id === locationId), which will exclude any institution restrictions that intentionally have program or location unset (e.g., the new location-only restrictions where program is not allowed). This likely prevents REMIT/location-only and institution-level restrictions from ever being applied during e-Cert/disbursement calculations. Consider treating null/undefined program/location on a restriction as a wildcard (match all) and only enforcing equality when the field is present.
  private getEffectiveInstitutionRestrictions(): ReadonlyArray<InstitutionActiveRestriction> {
    const programId = this.offering.educationProgram.id;
    const locationId = this.offering.institutionLocation.id;
    return this.institutionRestrictions.filter(
      (restriction) =>
        restriction.program?.id === programId &&
        restriction.location?.id === locationId &&
        !this.institutionRestrictionsBypassedIds.includes(
          restriction.institutionRestrictionId,
        ),
    );

Comment on lines +116 to +123
const selectedReason = reasons.value.find(
(reason) => reason.id === formModel.restrictionId,
);
if (!selectedReason?.fieldRequirements) {
return { canShow: false };
}
const fieldRequirement = selectedReason.fieldRequirements[fieldKey];
const canShow = fieldRequirement !== FieldRequirementType.NotAllowed;
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

When the selected restriction changes, programId/locationIds values from a previously selected reason can remain in formModel even if the new reason marks the field as NotAllowed (the input gets hidden but the value is still submitted). This can cause backend validation errors that the user cannot fix because the field is no longer visible. Consider watching formModel.restrictionId (or programAttributes/locationAttributes) and clearing formModel.programId/formModel.locationIds when canShow becomes false (and possibly when a field becomes optional/required).

Copilot uses AI. Check for mistakes.
@dheepak-aot dheepak-aot marked this pull request as ready for review February 23, 2026 20:20
Comment on lines -188 to -191
restrictionId: number,
locationIds: number[],
programId: number,
noteDescription: string,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please review the parameter comments.

@tiago-graf tiago-graf self-requested a review February 23, 2026 23:47
Copy link
Collaborator

Choose a reason for hiding this comment

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

metadata-utils.ts seems too generic. Can it be prefixed with "restrictions"?

.expect(HttpStatus.BAD_REQUEST)
.expect({
message:
"Field requirement error(s): program is required, location is required.",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Really great to see the details in the validations and the validation messages ❤️

Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot left a comment

Choose a reason for hiding this comment

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

Great work introducing the restrictions metadata framework. Please take a look at the minor comments.

Copy link
Collaborator

@tiago-graf tiago-graf left a comment

Choose a reason for hiding this comment

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

Looks good to me!

async getReasonsOptionsList(
@Query() options: RestrictionReasonsOptionsAPIInDTO,
): Promise<OptionItemAPIOutDTO[]> {
): Promise<RestrictionAPIOutDTO[]> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

it did caught my attention that get "reasons" is returning a list of restriction objects

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Calling the API as reasons was not accurate, as it returns restriction details. This endpoint requires refactor and has a ticket for the same. I took the opportunity to update the DTO name alone 😊

@sonarqubecloud
Copy link

@github-actions
Copy link

Backend Unit Tests Coverage Report

Totals Coverage
Statements: 20.36% ( 4501 / 22106 )
Methods: 9.75% ( 262 / 2687 )
Lines: 24.59% ( 3853 / 15666 )
Branches: 10.29% ( 386 / 3753 )

@github-actions
Copy link

E2E Workflow Workers Coverage Report

Totals Coverage
Statements: 75.53% ( 1062 / 1406 )
Methods: 79.45% ( 116 / 146 )
Lines: 78.88% ( 773 / 980 )
Branches: 61.79% ( 173 / 280 )

@github-actions
Copy link

E2E Queue Consumers Coverage Report

Totals Coverage
Statements: 85.68% ( 1616 / 1886 )
Methods: 85% ( 187 / 220 )
Lines: 88.64% ( 1287 / 1452 )
Branches: 66.36% ( 142 / 214 )

@github-actions
Copy link

E2E SIMS API Coverage Report

Totals Coverage
Statements: 76.99% ( 9288 / 12064 )
Methods: 75.49% ( 1075 / 1424 )
Lines: 81.34% ( 6731 / 8275 )
Branches: 62.66% ( 1482 / 2365 )

Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot left a comment

Choose a reason for hiding this comment

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

Thanks for making the changes, looks good 👍

@dheepak-aot dheepak-aot added this pull request to the merge queue Feb 25, 2026
Merged via the queue into main with commit 38889ed Feb 25, 2026
22 checks passed
@dheepak-aot dheepak-aot deleted the feature/#2987-institution-prevent-remittance-1 branch February 25, 2026 00:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DB DB migration involved SIMS-Api SIMS-Api Web portal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants