[CLAUDE] PurchaseEvaluation: chuong bao nguoi duyet khi phieu vao cap cua ho (submit + moi cap)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m48s

Tra Sol (Zalo): 'khong thay chuong bao - viec co ho so can duyet'. PE workflow truoc chi notify DRAFTER luc terminal; nguoi DUYET khong duoc bao khi phieu toi cap cua ho. Fix: block trong LogTransitionAsync (sau drafter-notify) - khi toPhase==ChoDuyet, resolve approver cap hien tai (workflow.Steps[CurrentWorkflowStepIndex].Levels Order==CurrentApprovalLevelOrder -> ApproverUserId OR-of-N, exclude actor) -> NotifyManyAsync Generic 'Phieu can ban duyet'. Fire moi luc phieu vao cap ChoDuyet: submit (cap 1) + moi approve-advance (cap ke) - 5 call-site advance deu log toPhase=ChoDuyet sau khi set pointer (verified). Best-effort try/catch (notify fail KHONG rollback transition). V2-only guard. Bell render Generic san (urgent->CEO da chung minh). BE-only, no-mig. Build slnx 0/0, test 354 PASS (khong vo transition cu). Notify = test-after (UAT).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-19 15:22:44 +07:00
parent fa6654b8f4
commit 424131d0b1

View File

@ -1055,6 +1055,54 @@ public class PurchaseEvaluationWorkflowService(
refId: evaluation.Id,
ct: ct);
}
// ===== 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
// tới 1 Cấp duyệt (toPhase==ChoDuyet) → báo NV Cấp đang chờ.
// Resolve mirror ĐÚNG canonical (ApplyDrafterBypassOnSubmit / EnsureActor
// line ~301): load ApprovalWorkflow → Step tại CurrentWorkflowStepIndex →
// Levels.Where(Order == CurrentApprovalLevelOrder) → distinct ApproverUserId.
// V2-only (ApprovalWorkflowId + pointer set); phiếu V1/no-workflow skip.
// Best-effort (try/catch) — phiếu đã SaveChanges, notify fail KHÔNG fail transition.
if (toPhase == PurchaseEvaluationPhase.ChoDuyet
&& evaluation.ApprovalWorkflowId is Guid notifyAwId
&& evaluation.CurrentWorkflowStepIndex is int notifyCsi
&& evaluation.CurrentApprovalLevelOrder is int notifyLvl)
{
try
{
var workflow = await db.ApprovalWorkflows.AsNoTracking()
.Include(w => w.Steps).ThenInclude(s => s.Levels)
.FirstOrDefaultAsync(w => w.Id == notifyAwId, ct);
var stepsOrdered = workflow?.Steps.OrderBy(s => s.Order).ToList();
if (stepsOrdered is not null && notifyCsi >= 0 && notifyCsi < stepsOrdered.Count)
{
var approverIds = stepsOrdered[notifyCsi].Levels
.Where(l => l.Order == notifyLvl
&& l.ApproverUserId != Guid.Empty
&& l.ApproverUserId != actorUserId)
.Select(l => l.ApproverUserId)
.Distinct()
.ToList();
if (approverIds.Count > 0)
{
await notifications.NotifyManyAsync(
approverIds,
NotificationType.Generic,
$"Phiếu cần bạn duyệt: {evaluation.MaPhieu ?? evaluation.TenGoiThau}",
"Có phiếu Duyệt NCC đang chờ bạn duyệt.",
$"/purchase-evaluations/{evaluation.Id}",
evaluation.Id,
ct);
}
}
}
catch
{
// best-effort — nuốt lỗi notify để KHÔNG rollback transition đã lưu.
}
}
}
// Mig 26 (Session 19) — helper resolve FullName cho denorm `SignedByFullName`.