[CLAUDE] Infra+App: Plan B Chunk B — Service ApproveV2Async branch + gen mã HĐ adapt
Mirror PE PurchaseEvaluationWorkflowService.cs:ApproveV2Async (line 446-634).
V1 legacy giữ behavior cũ — 7 prod contract chạy nhánh này. V2 mới pin
ApprovalWorkflowId chạy ApproveV2Async helper.
Changes:
- ContractWorkflowService.cs:
- TransitionAsync +skipToFinal=false param F2 (Mig 31 Plan K mirror PE)
- Drafter trình init CurrentApprovalLevelOrder=1 nếu V2 schema pin
- APPROVE STEP branch V2/V1 dispatch theo ApprovalWorkflowId
- +ApproveV2Async helper ~150 LOC (mirror PE pattern):
- Load AW.Steps.Levels OR-of-N
- Match approver actor.Id ∈ pendingLevelGroup.ApproverUserId
- Add ContractApproval row + enrich comment skipPrefix
- skipToFinal F2: AllowApproverSkipToFinal guard + advance pointer last
- Advance level/step normal
- Terminal: gen mã HĐ RG-001 + Phase=DaPhatHanh (khác PE just DaDuyet)
- IContractWorkflowService.cs: TransitionAsync +skipToFinal=false param
- ContractFeatures.cs: caller TransitionAsync use named arg ct: ct (skip optional)
TODO Chunk C: UPSERT ContractLevelOpinion (table chưa tồn tại — Mig 33
sẽ scaffold + entity + EF config). Block UPSERT add ở đây sau Chunk C done.
Verify:
- dotnet build SolutionErp.slnx PASS 0 err, 2 pre-existing DocxRenderer warn
- dotnet test 111/111 PASS (58 Domain + 53 Infra) — 0 regression
- V1 legacy path UNCHANGED (7 prod contract giữ behavior)
Plan B chain (6 chunks):
- A1 58898e8 Contract +2 fields (em main, done)
- A2 a85e437 Mig 32 schema + Config + Seed (Implementer Case 2, done)
- B (this) Service ApproveV2Async branch (em main, done)
- C Mig 33 ContractLevelOpinions (Implementer, next)
- D FE Workspace V2 (Implementer, pending)
- E FE Section 5 V2 (Implementer, pending)
Race condition lesson: em main + Implementer parallel touch BE same plan
→ Implementer stash em main WIP for clean build verify. Solution: SEQUENTIAL
chunks A→B→C, NOT parallel B với A2. Pattern add to Implementer MEMORY.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -235,7 +235,7 @@ public class TransitionContractCommandHandler(
|
||||
currentUser.Roles,
|
||||
request.Decision,
|
||||
request.Comment,
|
||||
ct);
|
||||
ct: ct);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,9 @@ public interface IContractWorkflowService
|
||||
{
|
||||
// Kiểm tra + thực hiện transition. Throw ForbiddenException nếu không hợp lệ.
|
||||
// Tự tạo ContractApproval row + update Phase + SlaDeadline + gen mã HĐ nếu cần.
|
||||
// [Plan B S29 2026-05-22] +skipToFinal param F2 (Mig 31): Approver scope
|
||||
// ChoDuyet skip thẳng Cấp cuối. V2 only, V1 legacy throw nếu non-admin.
|
||||
// Default false để KHÔNG break existing caller (ContractsController).
|
||||
Task TransitionAsync(
|
||||
Contract contract,
|
||||
ContractPhase targetPhase,
|
||||
@ -13,6 +16,7 @@ public interface IContractWorkflowService
|
||||
IReadOnlyList<string> actorRoles,
|
||||
ApprovalDecision decision,
|
||||
string? comment,
|
||||
bool skipToFinal = false,
|
||||
CancellationToken ct = default);
|
||||
|
||||
// SLA còn bao lâu ở phase hiện tại (seconds). Null nếu không có SLA.
|
||||
|
||||
Reference in New Issue
Block a user