[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
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:
@ -1055,6 +1055,54 @@ public class PurchaseEvaluationWorkflowService(
|
|||||||
refId: evaluation.Id,
|
refId: evaluation.Id,
|
||||||
ct: ct);
|
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`.
|
// Mig 26 (Session 19) — helper resolve FullName cho denorm `SignedByFullName`.
|
||||||
|
|||||||
Reference in New Issue
Block a user