[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:
pqhuy1987
2026-05-22 12:18:46 +07:00
parent a85e437478
commit 138469db4e
3 changed files with 187 additions and 1 deletions

View File

@ -235,7 +235,7 @@ public class TransitionContractCommandHandler(
currentUser.Roles,
request.Decision,
request.Comment,
ct);
ct: ct);
}
}

View File

@ -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.