[CLAUDE] PurchaseEvaluation: cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng giá trị (Mig 53) + 14 test
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m41s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m41s
Yêu cầu anh Kiệt FDC (sau họp sếp). Mig 53 AddPeUrgentAndCeoApprovalThreshold — 3 AddColumn, no new table (Mig 52→53). Rollout an toàn: cột nullable, ngưỡng null = giữ luồng duyệt cũ 100% cho tới khi admin set.
B — CCM duyệt-final theo NGƯỠNG GIÁ TRỊ ("gói CEO phân quyền theo giá trị"):
- ApprovalWorkflow += CeoApprovalThreshold (decimal?, admin nhập trong Workflow Designer).
- ApproveV2Async: actor role CostControl (CCM) + winnerQuoteTotal (tổng giá NCC được chọn) < ngưỡng → DaDuyet luôn (bỏ CEO); ≥ ngưỡng → đẩy lên CEO như cũ. Ngưỡng null = luồng tuyến tính cũ. Q4 chốt nhận diện theo ROLE người duyệt.
- reviewer PASS 0 blocker: cascade-safe (Off/role không lan), tested load-bearing (CCM dưới ngưỡng → DaDuyet skip CEO).
A — cờ gấp per-vai (visibility-only, Q3 KHÔNG đổi luồng):
- PE += IsUrgentByPro (PRO đỏ) / IsUrgentByCcm (CCM xanh).
- Endpoint PUT /purchase-evaluations/{id}/urgent role-gated (Procurement→ByPro, CostControl→ByCcm, Admin→cả 2, khác→Forbidden) + notify CEO (Director) khi MỚI bật (best-effort).
FE ×2 app: Workflow Designer ô "Ngưỡng giá trị gói CEO" (fe-admin) + PE detail nút bật/tắt cờ gấp đỏ/xanh theo role + badge GẤP + hint "giá trị gói vs ngưỡng → CCM duyệt-final/cần CEO" + PE list badge gấp.
DTO: PE detail += isUrgentByPro/Ccm + winnerQuoteTotal + ceoApprovalThreshold; list += isUrgentByPro/Ccm; workflow V2 += ceoApprovalThreshold.
+14 test (292→306): PeCcmThresholdFinalizeTests 5 (B routing) + PeUrgentToggleAuthzTests 9 (A authz). Build slnx 0/0 · npm build ×2 0 err · dotnet test 306 PASS.
C (sau duyệt xong chuyển phiếu đến dự án) — chờ anh Kiệt làm chi tiết form, CHƯA làm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -57,6 +57,9 @@ public record AwDefinitionDto(
|
||||
string? Description,
|
||||
bool IsActive,
|
||||
bool IsUserSelectable,
|
||||
// [S69 2026-06-17] Ngưỡng giá trị "gói CEO" — admin Designer hiển thị + edit.
|
||||
// Null = không áp ngưỡng (luồng tuyến tính cũ).
|
||||
decimal? CeoApprovalThreshold,
|
||||
// Mig 29 (S21 t5) — 6 advanced options đã MOVE per-NV: F1+F3 xuống AwLevelDto
|
||||
// (per slot Approver). Workflow-level Mig 28 dropped.
|
||||
// Mig 31 (S23 t1) — F2 cũng refactor xuống Level slot (AllowApproverSkipToFinal
|
||||
@ -153,6 +156,7 @@ public class GetAwAdminOverviewQueryHandler(
|
||||
d.Description,
|
||||
d.IsActive,
|
||||
d.IsUserSelectable,
|
||||
d.CeoApprovalThreshold, // [S69] ngưỡng gói CEO
|
||||
d.ActivatedAt,
|
||||
d.CreatedAt,
|
||||
d.Steps.OrderBy(s => s.Order).Select(s => new AwStepDto(
|
||||
@ -221,7 +225,12 @@ public record CreateAwDefinitionCommand(
|
||||
string Code,
|
||||
string Name,
|
||||
string? Description,
|
||||
List<CreateAwStepInput> Steps) : IRequest<Guid>;
|
||||
List<CreateAwStepInput> Steps,
|
||||
// [S69 2026-06-17] Ngưỡng giá trị "gói CEO" — admin nhập trong Workflow Designer.
|
||||
// CCM (CostControl) duyệt-final không cần lên CEO khi tổng giá NCC được chọn <
|
||||
// ngưỡng; ≥ ngưỡng → vẫn lên CEO (Director). NULL = không áp ngưỡng (luồng cũ).
|
||||
// Nullable passthrough — trailing-optional default backward-compat call-site cũ.
|
||||
decimal? CeoApprovalThreshold = null) : IRequest<Guid>;
|
||||
|
||||
public class CreateAwDefinitionCommandValidator : AbstractValidator<CreateAwDefinitionCommand>
|
||||
{
|
||||
@ -243,6 +252,10 @@ public class CreateAwDefinitionCommandValidator : AbstractValidator<CreateAwDefi
|
||||
RuleFor(x => x.Description).MaximumLength(1000);
|
||||
RuleFor(x => x.Steps).NotEmpty()
|
||||
.WithMessage("Quy trình phải có ít nhất 1 bước.");
|
||||
// [S69] Ngưỡng gói CEO — nếu nhập phải >= 0 (NULL = không áp ngưỡng OK).
|
||||
RuleFor(x => x.CeoApprovalThreshold).GreaterThanOrEqualTo(0)
|
||||
.When(x => x.CeoApprovalThreshold.HasValue)
|
||||
.WithMessage("Ngưỡng giá trị gói CEO không được âm.");
|
||||
RuleForEach(x => x.Steps).ChildRules(step =>
|
||||
{
|
||||
step.RuleFor(s => s.Order).GreaterThanOrEqualTo(1);
|
||||
@ -315,6 +328,7 @@ public class CreateAwDefinitionCommandHandler(IApplicationDbContext db)
|
||||
IsActive = true,
|
||||
IsUserSelectable = true, // Mig 25 — version mới mặc định cho user pick
|
||||
// Mig 29 (S21 t5) — Allow* options đã move xuống Level slot (per-NV)
|
||||
CeoApprovalThreshold = request.CeoApprovalThreshold, // [S69] ngưỡng gói CEO (nullable passthrough)
|
||||
ActivatedAt = DateTime.UtcNow,
|
||||
Steps = request.Steps.OrderBy(s => s.Order)
|
||||
.Select(s => new ApprovalWorkflowStep
|
||||
|
||||
Reference in New Issue
Block a user