Skip to content

Conversation

@andrewsignori-aot
Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot commented Sep 19, 2025

API Related Changes

  • Renamed the role student-delete-restrictions to student-delete-restriction to comply with the business AC.
  • Created a new endpoint to soft-delete a restriction.
  • Changed endpoints to return resolvedAt, resolvedBy, deletedAt, deletedBy.
    • Some DTOs are shared between student and institution restrictions. The DTO properties were renamed for institutions, but they keep returning data from the modifier/updatedAt as before.
  • Ministry endpoints returning information to the student restriction UI were adapted to execute the queries, including soft-deleted records.

UI Related Changes

  • The status chip that displays restriction status was adapted to show the deleted status. For areas of the UI that will never display deleted restrictions (e.g., restriction bypasses), the API was not changed to return properties like deletedAt; the only purpose would be to display the correct status for records that will not be shown.
  • Update the restrictions list to show resolved information from the new fields.
  • Included the delete button for provincial restrictions only.
  • Returned ApiProcessError for possible concurrency error while deleting a restriction that is already deleted.

New deleted status for the Ministry

image

Please note that the restriction badge on the top, as shown below, does not consider the deleted records (as expected).

image

Resolved and later deleted restriction

image

Never resolved, and deleted restriction

image

Resolved restriction getting data from the new columns

image

Feferal restriction does not have "Delete" available

image

New delete modal

image

@andrewsignori-aot andrewsignori-aot self-assigned this Sep 19, 2025
@andrewsignori-aot andrewsignori-aot added Institution Institution Features Ministry Ministry Features SIMS-Api SIMS-Api Web portal labels Sep 19, 2025
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

This PR implements the ability for ministry users to delete provincial student restrictions through both API and UI changes. The implementation includes soft-deletion functionality with audit trails and proper permission controls.

  • Adds soft-delete capability for provincial restrictions with note requirements and audit tracking
  • Updates UI components to display restriction status including deleted state and show delete actions
  • Renames role from plural to singular form to comply with business requirements

Reviewed Changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
StudentRestrictions.vue Adds delete restriction capability prop
Restrictions.vue Simplifies status chip usage for institution restrictions
roles.ts Renames role from plural to singular form
RestrictionContract.ts Adds Deleted status enum value
Restriction.dto.ts Updates DTOs with resolved/deleted tracking fields
RestrictionApi.ts Adds delete restriction API method
RestrictionService.ts Adds delete restriction service method
useRestriction.ts Updates restriction status logic to handle deleted state
StatusChipRestriction.vue Changes from status prop to isActive/deletedAt props
StudentRestrictions.vue Implements delete functionality with modal and permission checks
ViewRestriction.vue Updates to show resolved/deleted information from new fields
HistoryBypassedRestrictions.vue Updates status chip usage
student-restriction-shared.service.ts Removes error constants (moved to shared location)
error-code.constants.ts Adds restriction-related error constants
student-restriction.service.ts Implements delete restriction logic with concurrency handling
institution-restriction.service.ts Updates import for moved error constant
restriction.controller.service.ts Updates to return new resolved/deleted fields
restriction.aest.controller.ts Adds delete endpoint with proper error handling
restriction.dto.ts Adds delete restriction DTO
error-code.constants.ts Adds restriction deletion error constants
roles.enum.ts Updates role name to singular form

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

andrewsignori-aot and others added 3 commits September 19, 2025 15:27
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@andrewsignori-aot andrewsignori-aot marked this pull request as ready for review September 19, 2025 22:32
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

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@dheepak-aot dheepak-aot self-requested a review September 22, 2025 16:05
updatedBy: string;
resolvedBy: string;
deletedBy?: string;
deletedAt?: Date;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor. deletedAt comes from the summary API out DTO.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed.

@ApiUnprocessableEntityResponse({
description: "Provincial restriction is already set as deleted.",
})
@Patch("student/:studentId/student-restriction/:studentRestrictionId/delete")
Copy link
Collaborator

Choose a reason for hiding this comment

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

I can see that existing APIs use student id on APIs that resolve and get restriction detail.
Are we keeping student id here to follow the existing APIs? or is there a different reason?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Following the existing API pattern.

Comment on lines +305 to +326
await this.dataSource.transaction(async (transactionalEntityManager) => {
const now = new Date();
const auditUser = { id: auditUserId } as User;
const note = await this.noteSharedService.createStudentNote(
studentId,
NoteType.Restriction,
noteDescription,
auditUserId,
transactionalEntityManager,
);
const updateResult = await transactionalEntityManager
.getRepository(StudentRestriction)
.update(
{ id: restriction.id, deletedAt: IsNull() },
{
deletionNote: note,
deletedAt: now,
deletedBy: auditUser,
modifier: auditUser,
updatedAt: now,
},
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

There was a discussion about setting isActive to false while deleting a restriction(to reduce legacy integration side effects). Is it dropped to keep the deletion process simple?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not dropped, but not part of this ticket ACs. After multiple requests from DEVs to have it added, it ended up not being added here. Hence, I believe that it will be part of the other one.

Comment on lines +327 to +331
resolvedAt: institutionRestriction.updatedAt,
createdBy: getUserFullName(institutionRestriction.creator),
updatedBy: getUserFullName(institutionRestriction.modifier),
// Currently mapping modifier to resolvedBy as there is no resolvedBy for
// institutions restrictions but the API shares the same DTO.
resolvedBy: getUserFullName(institutionRestriction.modifier),
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

Comment on lines +158 to +168
if (options?.extendedDetails) {
return {
...restrictionDetail,
resolvedAt: studentRestriction.resolvedAt,
deletedAt: studentRestriction.deletedAt,
resolvedBy: getUserFullName(studentRestriction.resolvedBy) || undefined,
deletedBy: getUserFullName(studentRestriction.deletedBy) || undefined,
resolutionNote: studentRestriction.resolutionNote?.description,
deletionNote: studentRestriction.deletionNote?.description,
};
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

{{ item.restrictionCode }}
</template>
<template #[`item.restrictionStatus`]="{ item }">
<status-chip-restriction
Copy link
Collaborator

@dheepak-aot dheepak-aot Sep 22, 2025

Choose a reason for hiding this comment

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

What happens to a bypass record when the student restriction associated to that is deleted? this was something we weren't sure about how typeorm is handling it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will be investigated and shared, not part of this PR.

(props.restrictionData.isActive ||
props.restrictionData.resolutionNote),
);
(props.restrictionData.isActive || props.restrictionData.resolutionNote)
Copy link
Collaborator

Choose a reason for hiding this comment

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

.restrictionData.isActive and restrictionData.resolutionNote are mutually exclusive.

Condition can be appended as (props.restrictionData.resolutionNote || !restrictionData.deletedAt) which will achieve the same?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The mentioned code was already in place. I believe that it is better to read by keeping the existing logic and dealing with the deleted logic at the top.
Not willing to put effort into this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

By effort, if you are saying the effort to validate different situations, it's fair enough. It is not a blocker as the code here works.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, this code was the same code that had issues recently. Effort-wise and I did not see an improvement in the suggested code, hence keeping it as it is since it was not considered as a blocker.

@click="viewStudentRestriction(slotProps.data.restrictionId)"
>View</v-btn
>
<check-permission-role :role="Role.StudentDeleteRestriction">
Copy link
Collaborator

@dheepak-aot dheepak-aot Sep 22, 2025

Choose a reason for hiding this comment

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

Minor. the vif can be added to check-permission-role to avoid check permission role component from being created.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Moved v-if.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not able to see the changes yet.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Missing a push, it should be updated now.

updatedBy: string;
resolvedBy: string;
deletedBy?: string;
deletedAt?: Date;
Copy link
Collaborator

Choose a reason for hiding this comment

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

same here on deleteAt repeating.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just changed it.

Copy link
Collaborator

@dheepak-aot dheepak-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 enabling delete restrictions and other updates. I could see just 2 minor comments left.

@sonarqubecloud
Copy link

@github-actions
Copy link

Backend Unit Tests Coverage Report

Totals Coverage
Statements: 21.38% ( 4168 / 19493 )
Methods: 9.63% ( 239 / 2482 )
Lines: 24.74% ( 3609 / 14589 )
Branches: 13.21% ( 320 / 2422 )

@github-actions
Copy link

E2E Workflow Workers Coverage Report

Totals Coverage
Statements: 75.33% ( 974 / 1293 )
Methods: 78.08% ( 114 / 146 )
Lines: 78.25% ( 759 / 970 )
Branches: 57.06% ( 101 / 177 )

@github-actions
Copy link

E2E Queue Consumers Coverage Report

Totals Coverage
Statements: 86.43% ( 1548 / 1791 )
Methods: 84.62% ( 176 / 208 )
Lines: 88.75% ( 1278 / 1440 )
Branches: 65.73% ( 94 / 143 )

@github-actions
Copy link

E2E SIMS API Coverage Report

Totals Coverage
Statements: 74.34% ( 7571 / 10184 )
Methods: 72.13% ( 924 / 1281 )
Lines: 77.8% ( 5868 / 7542 )
Branches: 57.24% ( 779 / 1361 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Institution Institution Features Ministry Ministry Features SIMS-Api SIMS-Api Web portal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants