[CLAUDE] PurchaseEvaluation: Plan AC — fix Lịch sử duyệt panel show Trả lại + Duyệt vượt cấp
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m27s

Bro UAT 2026-05-19 screenshot: panel "Lịch sử duyệt" KHÔNG show Return mode
events (Bro Trả lại từ Phan Văn Chương → Trà missing) + KHÔNG distinct
event Duyệt vượt cấp (skipToFinal F2).

Root cause:
- PurchaseEvaluationApprovals.Add() chỉ ở Approve branch (line 472 V2 + 660 V1)
- Reject branch line 75-103 NEVER adds Approval row — chỉ log Changelog
- skipToFinal advance branch line 532-572 dùng existing line 472 row nhưng
  comment KHÔNG distinct "vượt cấp" semantic vs approve thường

Fix Plan AC:

1. BE Service.cs Reject branch (line 75-103): capture pre-call Step/Level
   trước ApplyReturnModeAsync mutate pointer, add Approval row sau khi mutate:
   Decision=Reject + FromPhase + ToPhase=evaluation.Phase + Comment carry
   from-position + mode summary. Cover cả Trả lại (TraLai+pointer-mode) +
   Từ chối (TuChoi terminal).

2. BE Service.cs line 472 Approve branch: enrich Comment với prefix
   "[Duyệt vượt cấp tới Cấp cuối]" khi skipToFinal=true để Lịch sử duyệt
   distinguish vượt cấp với approve thường.

3. FE PeDetailTabs.tsx × 2 app ApprovalsTab: add Decision badge phân biệt
   Approve (emerald) / Trả lại (amber) / Từ chối (rose). Vì 3/4 mode Trả
   lại (OneLevel/OneStep/Assignee) giữ Phase=ChoDuyet → fromPhase→toPhase
   badge giống Approve. Decision badge bù visual phân biệt.

Verify:
- dotnet build clean 0 err 2 warn (pre-existing DocxRenderer)
- dotnet test 111/111 PASS
- npm build × fe-user + fe-admin PASS 0 TS err

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-19 10:45:25 +07:00
parent 8c05947176
commit a734bf2b8b
3 changed files with 105 additions and 38 deletions

View File

@ -80,6 +80,13 @@ public class PurchaseEvaluationWorkflowService(
// guard tránh request forge non-approver gọi PATCH direct.
await EnsureCanRejectV2Async(evaluation, actorUserId, isAdmin, ct);
// Plan AC S25 Bug 3a — capture pre-call Step/Level để log Approval row
// chính xác (ApplyReturnModeAsync mutate pointer cho 3 mode OneLevel/
// OneStep/Assignee). FE ApprovalsTab render `ev.approvals` — trước
// đây Reject KHÔNG add row → Lịch sử duyệt panel mất event Trả lại.
var fromStepIdx = evaluation.CurrentWorkflowStepIndex;
var fromLevelOrder = evaluation.CurrentApprovalLevelOrder;
if (targetPhase == PurchaseEvaluationPhase.TuChoi)
{
// Từ chối hoàn toàn — phiếu khoá vĩnh viễn (lock edit Mig 16).
@ -97,6 +104,25 @@ public class PurchaseEvaluationWorkflowService(
? returnSummary
: $"{comment} [{returnSummary}]";
}
// Plan AC S25 Bug 3a — add Approval row cho Lịch sử duyệt panel
// (FE ApprovalsTab). Decision=Reject + Comment carry mode + summary.
// From-position dùng pre-call Step/Level để show actor đã trả lại
// từ Bước/Cấp nào.
var fromPos = fromStepIdx.HasValue && fromLevelOrder.HasValue
? $"[Bước {fromStepIdx.Value + 1} — Cấp {fromLevelOrder.Value}] "
: "";
db.PurchaseEvaluationApprovals.Add(new PurchaseEvaluationApproval
{
PurchaseEvaluationId = evaluation.Id,
FromPhase = fromPhase,
ToPhase = evaluation.Phase,
ApproverUserId = actorUserId,
Decision = ApprovalDecision.Reject,
Comment = $"{fromPos}{comment ?? ""}".Trim(),
ApprovedAt = dateTime.UtcNow,
});
await LogTransitionAsync(evaluation, fromPhase, evaluation.Phase, actorUserId, decision, comment, ct);
await db.SaveChangesAsync(ct);
return;
@ -468,7 +494,10 @@ public class PurchaseEvaluationWorkflowService(
}
}
// Log approval
// Log approval. Plan AC S25 Bug 3b — enrich comment với prefix
// "[Duyệt vượt cấp]" khi skipToFinal=true để FE Lịch sử duyệt panel
// phân biệt rõ event vượt cấp với approve thường.
var skipPrefix = skipToFinal ? "[Duyệt vượt cấp tới Cấp cuối] " : "";
db.PurchaseEvaluationApprovals.Add(new PurchaseEvaluationApproval
{
PurchaseEvaluationId = evaluation.Id,
@ -476,7 +505,7 @@ public class PurchaseEvaluationWorkflowService(
ToPhase = evaluation.Phase,
ApproverUserId = actorUserId,
Decision = ApprovalDecision.Approve,
Comment = $"[Bước {currentIdx + 1} — Cấp {currentLevelOrder}] {comment ?? ""}",
Comment = $"{skipPrefix}[Bước {currentIdx + 1} — Cấp {currentLevelOrder}] {comment ?? ""}".Trim(),
ApprovedAt = dateTime.UtcNow,
});