Ràng buộc 2 (Phase 9): khi reject, trả về Drafter (DangSoanThao) + lưu phase
nguồn. Drafter sửa lại + trình lại → quay về phase đã reject (skip phase
trung gian).
Logic flow:
1. Reject (Decision=Reject):
- entity.RejectedFromPhase = currentPhase // snapshot phase đang reject
- targetPhase override = DangSoanThao // force về Drafter
- Approval row: FromPhase=X, ToPhase=DangSoanThao, Decision=Reject
- Notification cho Drafter
2. Resume after reject (Decision=Approve, fromPhase=DangSoanThao,
RejectedFromPhase != null):
- targetPhase override = entity.RejectedFromPhase!.Value
- entity.RejectedFromPhase = null // clear field
- Skip policy guard (Drafter có quyền trình lại sau khi sửa)
- Approval row: FromPhase=DangSoanThao, ToPhase=ResumePhase, Decision=Approve
3. Normal transition (chưa reject hoặc đã clear):
- Logic cũ giữ nguyên — policy guard check + transition
Pattern unified cho 3 module:
- ContractWorkflowService.TransitionAsync: 2 case detect + override
- PurchaseEvaluationWorkflowService.TransitionAsync: tương tự
- TransitionBudgetCommandHandler.Handle: tương tự (Budget không có service riêng,
logic ở handler)
Files:
- src/Backend/SolutionErp.Infrastructure/Services/ContractWorkflowService.cs
- src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs
- src/Backend/SolutionErp.Application/Budgets/BudgetFeatures.cs
Verify:
- Build pass (2 warning DocxRenderer cũ, không liên quan)
- 77 unit test pass — Domain policy không đổi, tests giữ nguyên
Note: Approval history giờ track đầy đủ cycle reject→sửa→resume:
Approval 1: DangGopY → DangSoanThao, Decision=Reject (CCM reject)
Approval 2: DangSoanThao → DangGopY, Decision=Approve (Drafter resume)
UI có thể detect "đã từng reject" qua RejectedFromPhase != null hoặc
qua Approval history (Decision=Reject row gần nhất). Hiển thị banner
đỏ "Phiếu đã bị reject từ phase X, lý do: Y" cho Drafter.
Smart reject hoàn tất Ràng buộc 2. Còn Ràng buộc 3 (2-stage dept approval)
ở Chunk D.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>