[CLAUDE] Domain+Infra: Migration 20 Contract workflow inner steps mirror PE (Chunk A)
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled

Mirror PE N-stage Mig 18+19 pattern sang Contract module. Gộp 1 migration
(CREATE TABLE + ALTER + filtered unique alter) thay vì tách 2 như PE.

Schema:
- entity WorkflowStepInnerStep (Domain/Contracts/) — Order, DeptId,
  PositionLevel, Name, SlaDays, IsRequired
- WorkflowStep nav +InnerSteps List
- ContractDepartmentApproval +InnerStepId Guid? FK Restrict
- CREATE TABLE WorkflowStepInnerSteps (no Contract prefix vì module dùng
  entity gốc Workflow* từ Mig 8)
- DROP UX_ContractDeptApprovals_Contract_Phase_Dept_Stage cũ
- RECREATE filtered: WHERE InnerStepId IS NULL (legacy 2-stage Mig 16)
  + new filtered UNIQUE (ContractId, Phase, InnerStepId) WHERE InnerStepId
  IS NOT NULL (N-stage)
- 3 INDEX: IX_InnerStepId, IX_(StepId, Order), IX_DeptId

Backward compat 100%: workflow Contract no InnerSteps configured →
service fallback legacy 2-stage. Data legacy InnerStepId=null vẫn enforce
unique cũ qua filtered index.

Note: Budget defer (chưa có versioned WorkflowDefinition entity —
hardcoded BudgetPolicy.Default). Cần migration AddBudgetVersionedWorkflow
trước khi mirror N-stage Budget.

Verify:
- dotnet build SolutionErp.slnx 0 error
- dotnet ef database update LocalDB applied OK
- dotnet test 89 pass (54 + 35) — no regression

Pending Chunk B: WorkflowAdminFeatures.cs DTO/Input/Validator/Handler
extend mirror PE Chunk B pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-07 19:00:45 +07:00
parent 5e5042d717
commit 951ffa3ed8
8 changed files with 4037 additions and 1 deletions

View File

@ -23,5 +23,9 @@ public class ContractDepartmentApproval : AuditableEntity
public DateTime ApprovedAt { get; set; }
public bool IsBypassed { get; set; } // true nếu NV bypass (User.CanBypassReview=true)
// N-stage inner step link (Mig 20) — null cho data legacy 2-stage Review/Confirm.
// Có giá trị khi step cha có InnerSteps configured. Mirror PE Mig 18 pattern.
public Guid? InnerStepId { get; set; }
public Contract? Contract { get; set; }
}

View File

@ -1,4 +1,5 @@
using SolutionErp.Domain.Common;
using SolutionErp.Domain.Identity; // reuse PositionLevel
namespace SolutionErp.Domain.Contracts;
@ -32,6 +33,11 @@ public class WorkflowStep : BaseEntity
public WorkflowDefinition? WorkflowDefinition { get; set; }
public List<WorkflowStepApprover> Approvers { get; set; } = new();
// Inner steps (Mig 20) — N-stage approval Phòng × PositionLevel sequential.
// Mirror PE pattern (Mig 18). Empty list → service fallback logic 2-stage
// Review/Confirm legacy (Mig 16) per dept.
public List<WorkflowStepInnerStep> InnerSteps { get; set; } = new();
}
public enum WorkflowApproverKind
@ -48,3 +54,23 @@ public class WorkflowStepApprover : BaseEntity
public WorkflowStep? Step { get; set; }
}
// Inner step (Mig 20 — Phase 9+) — sub-step level con cấu hình bên trong 1
// WorkflowStep cha (= 1 phase). Mirror PurchaseEvaluationWorkflowStepInnerStep
// pattern (Mig 18). Cho phép admin định nghĩa thứ tự duyệt N-stage theo
// Department × PositionLevel: NV.A → PP.A → TP.A → NV.B → PP.B → TP.B → ...
//
// User khớp DepartmentId + PositionLevel + Order tiếp theo chưa duyệt = approver
// hợp lệ. CanBypassReview ở User cho TP skip NV+PP cùng dept (audit IsBypassed).
public class WorkflowStepInnerStep : BaseEntity
{
public Guid WorkflowStepId { get; set; }
public int Order { get; set; }
public Guid DepartmentId { get; set; }
public PositionLevel PositionLevel { get; set; } // NV / PP / TP
public string? Name { get; set; } // hiển thị FE — vd "NV.PRO duyệt"
public int? SlaDays { get; set; }
public bool IsRequired { get; set; } = true;
public WorkflowStep? Step { get; set; }
}