[CLAUDE] PurchaseEvaluation: mark-read noti "cần duyệt" cũ khi phiếu rời cấp (fix chuông stale — anh Kiệt FDC)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m3s

anh Kiệt "chuông không bỏ ra được" — noti "Phiếu cần bạn duyệt" của approver (kể cả CEO) KHÔNG tự xóa khi phiếu đã xong/chuyển bởi người khác (duyệt-thay tại Cấp CEO, co-approver OR-of-N, finalize) → chuông đầy phiếu thừa.

Fix: trong LogTransitionAsync (chạy MỌI transition), TRƯỚC block notify cấp mới → mark-read (ReadAt) tất cả noti Generic + RefId=phiếu còn unread. Phiếu rời cấp (finalize/advance/return/reject) → noti cũ tự sạch; approver cấp MỚI nhận noti fresh (tạo sau mark-read). Best-effort try/catch, V2-only, ExecuteUpdateAsync. KHÔNG đổi target (noti vẫn báo đúng lúc), chỉ thu-hồi khi stale.

Test: +test #7 (finalize → noti CEO cũ mark-read). 435→436 PASS. BE-only, no migration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-01 15:47:08 +07:00
parent e657faa74a
commit 36cbf8b1cc
2 changed files with 68 additions and 0 deletions

View File

@ -1110,6 +1110,28 @@ public class PurchaseEvaluationWorkflowService(
ct: ct);
}
// [S96 2026-07-01 — anh Kiệt FDC "chuông không bỏ ra được"] Phiếu RỜI một Cấp (finalize/
// advance/return/reject) → noti "cần bạn duyệt" CŨ (Generic + RefId=phiếu) của những approver
// chưa kịp duyệt = STALE (phiếu đã xong/chuyển, họ không cần duyệt nữa) → mark-read (ReadAt) để
// chuông tự sạch. Chạy MỌI transition (kể cả toPhase=DaDuyet/TuChoi/TraLai + duyệt-thay hoàn-tất
// hộ tại Cấp CEO). Approver Cấp MỚI nhận noti FRESH ở block dưới (tạo SAU mark-read → giữ unread).
// Best-effort — fail KHÔNG rollback transition. V2-only (có ApprovalWorkflowId).
if (evaluation.ApprovalWorkflowId is not null)
{
try
{
await db.Notifications
.Where(n => n.RefId == evaluation.Id
&& n.Type == NotificationType.Generic
&& n.ReadAt == null)
.ExecuteUpdateAsync(s => s.SetProperty(n => n.ReadAt, dateTime.UtcNow), ct);
}
catch
{
// best-effort — mark-read fail KHÔNG fail transition đã lưu.
}
}
// ===== Notify approver(s) cấp hiện tại khi phiếu vào ChoDuyet =====
// Tra Sol (Zalo): approver KHÔNG nhận chuông "có hồ sơ cần duyệt" — chỉ
// drafter được báo (block ↑). Bổ sung: mỗi lần phiếu ENTER hoặc ADVANCE