[CLAUDE] PurchaseEvaluation: drafter tự gỡ cờ GẤP + ngân sách kỳ này tự nhảy từ ban-hành (anh Kiệt FDC UAT R2)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m46s

D2 — Người KHAI phiếu tự GỠ cờ GẤP của mình (nới luật S77 "GỠ=chỉ TP"). BE handler
restructure SET/UNSET: GẮN giữ role-only (PRO/CCM/Admin); GỠ +drafter (DrafterUserId==actor)
→ drafter/Admin clear CẢ 2 cờ, TP-vai clear cờ vai mình. FE canToggle +isDrafter.
D3 — "Ngân sách kỳ này" (row3) tự nhảy từ "Ngân sách Ban hành lần đầu"
(PeWorkItemBudget.ProInitialAmount) khi chưa nhập tay. Submit-guard BE + FE missingForApproval
dùng effective = budgetPeriodAmount ?? proInitialAmount (mirror 2 tầng, chống bypass gotcha #44).

BE 2 file (Urgent handler + Workflow submit-guard). FE PeDetailTabs ×2 app SHA-identical.
Test +5 PeUrgentToggleAuthzTests (drafter-self-unset authz matrix) → 371 PASS. BE slnx + 2 FE build PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-23 14:00:33 +07:00
parent 24f0083d78
commit a5e936fc0a
5 changed files with 219 additions and 42 deletions

View File

@ -198,7 +198,19 @@ public class PurchaseEvaluationWorkflowService(
// [S61 Mig 50] Schema ngân sách mới — điều kiện (3) = "Ngân sách - kỳ này"
// (BudgetPeriodAmount, drafter nhập). FE PeDetailTabs missingForApproval
// mirror CÙNG predicate (đổi đồng bộ 2 tầng).
if (evaluation.BudgetPeriodAmount is null || evaluation.BudgetPeriodAmount <= 0)
// [S85 anh Kiệt — D3] "Ngân sách kỳ này" tự nhảy từ "Ngân sách Ban hành lần đầu"
// (PeWorkItemBudget.ProInitialAmount per Dự-án×Hạng-mục). Effective = BudgetPeriodAmount
// ?? ProInitialAmount → phiếu chưa nhập tay row3 nhưng đã có ban-hành PRO vẫn gửi-duyệt được
// (FE missingForApproval mirror cùng fallback — đổi đồng bộ 2 tầng).
decimal? effectiveBudget = evaluation.BudgetPeriodAmount;
if ((effectiveBudget is null || effectiveBudget <= 0) && evaluation.WorkItemId is Guid wiId)
{
effectiveBudget = await db.PeWorkItemBudgets.AsNoTracking()
.Where(b => b.ProjectId == evaluation.ProjectId && b.WorkItemId == wiId)
.Select(b => b.ProInitialAmount)
.FirstOrDefaultAsync(ct);
}
if (effectiveBudget is null || effectiveBudget <= 0)
{
missing.Add("chưa nhập Ngân sách kỳ này");
}