-
-
- {PurchaseEvaluationPhaseLabel[a.fromPhase]}
-
-
→
-
- {PurchaseEvaluationPhaseLabel[a.toPhase]}
-
+ {ev.approvals.map(a => {
+ const dec = decisionBadge(a.decision, a.toPhase)
+ return (
+
+
+
+
+ {dec.label}
+
+
+ {PurchaseEvaluationPhaseLabel[a.fromPhase]}
+
+ →
+
+ {PurchaseEvaluationPhaseLabel[a.toPhase]}
+
+
+
{new Date(a.approvedAt).toLocaleString('vi-VN')}
- {new Date(a.approvedAt).toLocaleString('vi-VN')}
-
-
- {a.approverName ?? 'Hệ thống'}{a.comment && ` · ${a.comment}`}
-
-
- ))}
+
+ {a.approverName ?? 'Hệ thống'}{a.comment && ` · ${a.comment}`}
+
+
+ )
+ })}
)
}
diff --git a/src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs b/src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs
index 361b896..5fad08b 100644
--- a/src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs
+++ b/src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs
@@ -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,
});