improvement: users get notified whenever a task is done completely, not per step.

This commit is contained in:
2026-09-07 22:36:33 +03:30
parent e52701dba3
commit 880809fdbe
17 changed files with 79 additions and 29 deletions

View File

@@ -0,0 +1,8 @@
-- AlterEnum
ALTER TYPE "LabCaseActivityType" ADD VALUE 'CASE_COMPLETED';
-- AlterEnum
ALTER TYPE "UserNotificationType" ADD VALUE 'CASE_COMPLETED';
-- Step-level TASK_COMPLETED inbox rows were spam; case-complete uses CASE_COMPLETED going forward.
DELETE FROM "UserNotification" WHERE type = 'TASK_COMPLETED';

View File

@@ -492,6 +492,7 @@ enum LabCaseActivityType {
CASE_AMENDED
TASK_COMPLETED
TASK_ASSIGNED
CASE_COMPLETED
}
enum LabCaseTabReadTarget {
@@ -508,6 +509,7 @@ enum UserNotificationType {
CASE_IMPORTANT
TASK_COMPLETED
TASK_ASSIGNED
CASE_COMPLETED
CONNECTION_REQUEST
STAFF_INVITE
}

View File

@@ -7,15 +7,15 @@ export const LAB_CASES_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.CASE_IMPORTANT,
];
/** Lab Tasks tab — task completions, lab-side comments, and assignments (assignee-scoped in counts). */
/** Lab Tasks tab — case fully completed, lab-side comments, and assignments (assignee-scoped in counts). */
export const LAB_TASKS_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.TASK_COMPLETED,
LabCaseActivityType.CASE_COMPLETED,
LabCaseActivityType.LAB_COMMENT,
LabCaseActivityType.TASK_ASSIGNED,
];
/** Clinic Treatment tab — visible lab comments and task progress. */
/** Clinic Treatment tab — visible lab comments and case fully completed. */
export const CLINIC_TREATMENT_TAB_ACTIVITY_TYPES: LabCaseActivityType[] = [
LabCaseActivityType.LAB_COMMENT,
LabCaseActivityType.TASK_COMPLETED,
LabCaseActivityType.CASE_COMPLETED,
];

View File

@@ -303,6 +303,7 @@ export class TasksService {
}
}
let caseCompleted = false;
if (dto.status === LabTaskStatus.COMPLETED && task.status !== LabTaskStatus.COMPLETED) {
await this.labCaseActivity.record(
{
@@ -321,18 +322,37 @@ export class TasksService {
},
tx,
);
const remainingIncomplete = await tx.labCaseTask.count({
where: {
labCaseId: task.labCaseId,
status: { not: LabTaskStatus.COMPLETED },
},
});
caseCompleted = remainingIncomplete === 0;
if (caseCompleted) {
await this.labCaseActivity.record(
{
labCaseId: task.labCaseId,
type: LabCaseActivityType.CASE_COMPLETED,
actorUserId,
payload: { labCaseId: task.labCaseId },
},
tx,
);
}
}
return result;
return { result, caseCompleted };
});
if (dto.status === LabTaskStatus.COMPLETED && task.status !== LabTaskStatus.COMPLETED) {
if (updated.caseCompleted) {
void this.userNotifications.notify({
organizationId: labOrganizationId,
type: UserNotificationType.TASK_COMPLETED,
href: `/tasks?taskId=${encodeURIComponent(taskId)}&labCaseId=${encodeURIComponent(task.labCaseId)}`,
type: UserNotificationType.CASE_COMPLETED,
href: `/cases?caseId=${encodeURIComponent(task.labCaseId)}`,
actorUserId,
payload: { labCaseId: task.labCaseId, taskId },
payload: { labCaseId: task.labCaseId },
requiredPermission: 'TAB_TASKS_READ',
});
@@ -340,10 +360,10 @@ export class TasksService {
if (clinicOrgId) {
void this.userNotifications.notify({
organizationId: clinicOrgId,
type: UserNotificationType.TASK_COMPLETED,
type: UserNotificationType.CASE_COMPLETED,
href: `/treatment?labCaseId=${encodeURIComponent(task.labCaseId)}`,
actorUserId,
payload: { labCaseId: task.labCaseId, taskId },
payload: { labCaseId: task.labCaseId },
requiredPermission: 'TAB_TREATMENT_READ',
labCaseIdForProviderScope: task.labCaseId,
});
@@ -353,11 +373,11 @@ export class TasksService {
const locale = normalizeCatalogLocale(localeInput);
const prosthesisLabels = await this.catalogLabels.resolveLabels(
CatalogEntityKind.PROSTHESIS_TYPE,
atomicProsthesisCodes([updated.prosthesisTypeCode]),
atomicProsthesisCodes([updated.result.prosthesisTypeCode]),
locale,
);
return { success: true, data: this.mapTaskListItem(updated, prosthesisLabels) };
return { success: true, data: this.mapTaskListItem(updated.result, prosthesisLabels) };
}
async listFilterOptions(