[CLAUDE] PE Workflow: wire Service V2 (Mig 24) — fix bug duyệt phiếu pin schema mới
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m14s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m14s
User báo bug eoffice: phiếu tạo mới không duyệt được + không bắt đc quy
trình mới. Root cause: Mig 23 pin ApprovalWorkflowId vào entity nhưng
Service vẫn đọc WorkflowDefinitionId legacy → match approver theo schema
cũ (Dept+PositionLevel/Role/User) thay vì ApproverUserId V2.
BE Domain — Migration 24 `AddCurrentApprovalLevelOrderToPe`:
- PurchaseEvaluation +CurrentApprovalLevelOrder int? (track Cấp 1/2/3
đang chờ duyệt trong Step hiện tại khi pin V2). Null khi terminal/V1.
- RejectedAtStepIndex giữ deprecated DB column cho data cũ.
BE Service PE — branch theo schema pin:
- V2 (`ApprovalWorkflowId` set): ApproveV2Async() — load
ApprovalWorkflows.Steps.Levels Include 3-level. Group Levels by Order
= Cấp (OR-of-N approvers). Match `actor.Id ∈ levelGroup.ApproverUserId`
(KHÔNG match Dept+Level/Role/User như V1). Advance:
Còn cấp tiếp trong Step → levelOrder++
Hết cấp → idx++, levelOrder=1
Hết Step → DaDuyet
- V1 legacy (chỉ `WorkflowDefinitionId` set): ApproveV1LegacyAsync() —
giữ nguyên logic Mig 21 (Dept+PositionLevel match)
- Drafter trình từ Nháp/Trả lại: init CurrentWorkflowStepIndex=0 +
CurrentApprovalLevelOrder=1 (chỉ khi V2 pin)
- Reject (Trả lại): clear CurrentApprovalLevelOrder=null
- Reject (Từ chối): clear all tracking
BE Synthetic Policy V2:
- `PurchaseEvaluationPolicyRegistry.ForV2Schema()` — simple state machine
policy (DangSoanThao/TraLai → ChoDuyet/TuChoi; ChoDuyet → ChoDuyet/
TraLai/TuChoi). Roles="*" cho ChoDuyet branch — Service tự enforce
ApproverUserId, Policy chỉ expose 3 nút FE.
- GetPurchaseEvaluationByIdQuery handler: ưu tiên ForV2Schema() khi pin
V2 (FE đọc workflow.nextPhases để show button).
Verify: 81 test pass · BE 0 error · Mig 24 applied cả 2 LocalDB.
Test thử (Drafter eoffice):
1. Designer V2 tạo quy trình QT-DN-V2-001: Bước 1 (Phòng A), Cấp 1 (NV X)
2. Workspace tạo phiếu mới, Select QT-DN-V2-001 → Lưu phiếu + Gửi duyệt
3. Phiếu Phase=ChoDuyet, idx=0, levelOrder=1. NV X login → thấy phiếu
trong Inbox + duyệt được. Sau approve → idx++, levelOrder reset 1.
4. Cấu hình level mismatch: NV Y khác → thấy ForbiddenException rõ tên.
Logic Contract V2 chưa wire (chỉ PE), defer Session sau khi user UAT PE OK.
This commit is contained in:
@ -43,12 +43,17 @@ public class PurchaseEvaluation : AuditableEntity
|
||||
|
||||
// Flat workflow tracking (Session 16 — Migration 21):
|
||||
// - CurrentWorkflowStepIndex: 0-based index của step đang chờ approver
|
||||
// (khi Phase=ChoDuyet). Null khi DangSoanThao/DaDuyet/TuChoi.
|
||||
// - RejectedAtStepIndex: snapshot CurrentWorkflowStepIndex tại Trả lại.
|
||||
// Drafter resume → restore CurrentWorkflowStepIndex (jump-back).
|
||||
// (khi Phase=ChoDuyet). Null khi DangSoanThao/DaDuyet/TuChoi/TraLai.
|
||||
// - RejectedAtStepIndex: [DEPRECATED Session 17] snapshot index tại Trả lại.
|
||||
// Field giữ DB column cho data cũ — Service không set value mới.
|
||||
public int? CurrentWorkflowStepIndex { get; set; }
|
||||
public int? RejectedAtStepIndex { get; set; }
|
||||
|
||||
// V2 schema tracking (Session 17 — Migration 24):
|
||||
// - CurrentApprovalLevelOrder: Cấp đang chờ duyệt (1/2/3) trong Step
|
||||
// hiện tại khi pin ApprovalWorkflowId. Null khi V1 legacy hoặc terminal.
|
||||
public int? CurrentApprovalLevelOrder { get; set; }
|
||||
|
||||
public List<PurchaseEvaluationSupplier> Suppliers { get; set; } = new();
|
||||
public List<PurchaseEvaluationDetail> Details { get; set; } = new();
|
||||
public List<PurchaseEvaluationQuote> Quotes { get; set; } = new();
|
||||
|
||||
@ -156,6 +156,52 @@ public static class PurchaseEvaluationPolicyRegistry
|
||||
public static PurchaseEvaluationPolicy ForEvaluation(PurchaseEvaluation ev) =>
|
||||
For(ev.Type);
|
||||
|
||||
// Session 17 — synthetic policy cho phiếu pin schema V2 (ApprovalWorkflowsV2).
|
||||
// Workflow chạy theo state machine 5 trạng thái + iterate Steps/Levels —
|
||||
// Phase enum chỉ dùng (DangSoanThao/TraLai/ChoDuyet/DaDuyet/TuChoi). Service
|
||||
// tự handle advance level/step bên trong ChoDuyet, FE chỉ cần biết:
|
||||
// DangSoanThao/TraLai → ChoDuyet (trình) | TuChoi (huỷ)
|
||||
// ChoDuyet → ChoDuyet (advance) | TraLai (trả lại) | TuChoi (từ chối)
|
||||
public static PurchaseEvaluationPolicy ForV2Schema()
|
||||
{
|
||||
var transitions = new Dictionary<(PurchaseEvaluationPhase, PurchaseEvaluationPhase), string[]>
|
||||
{
|
||||
// Drafter trình từ Nháp HOẶC gửi lại từ Trả lại — cùng entry point
|
||||
[(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.ChoDuyet)] = [AppRoles.Drafter, AppRoles.DeptManager],
|
||||
[(PurchaseEvaluationPhase.DangSoanThao, PurchaseEvaluationPhase.TuChoi)] = [AppRoles.Drafter, AppRoles.DeptManager],
|
||||
[(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.ChoDuyet)] = [AppRoles.Drafter, AppRoles.DeptManager],
|
||||
[(PurchaseEvaluationPhase.TraLai, PurchaseEvaluationPhase.TuChoi)] = [AppRoles.Drafter, AppRoles.DeptManager],
|
||||
|
||||
// ChoDuyet — Service guard match approver ApproverUserId, Policy chỉ
|
||||
// expose 3 nút cho FE (Duyệt forward / Trả lại / Từ chối). Roles "*"
|
||||
// để guard không block; Service tự enforce ApproverUserId match.
|
||||
[(PurchaseEvaluationPhase.ChoDuyet, PurchaseEvaluationPhase.ChoDuyet)] = ["*"],
|
||||
[(PurchaseEvaluationPhase.ChoDuyet, PurchaseEvaluationPhase.TraLai)] = ["*"],
|
||||
[(PurchaseEvaluationPhase.ChoDuyet, PurchaseEvaluationPhase.TuChoi)] = ["*"],
|
||||
};
|
||||
var sla = new Dictionary<PurchaseEvaluationPhase, TimeSpan?>
|
||||
{
|
||||
[PurchaseEvaluationPhase.DangSoanThao] = TimeSpan.FromDays(3),
|
||||
[PurchaseEvaluationPhase.TraLai] = TimeSpan.FromDays(3),
|
||||
[PurchaseEvaluationPhase.ChoDuyet] = TimeSpan.FromDays(7),
|
||||
[PurchaseEvaluationPhase.DaDuyet] = null,
|
||||
[PurchaseEvaluationPhase.TuChoi] = null,
|
||||
};
|
||||
return new PurchaseEvaluationPolicy(
|
||||
Name: "V2-Schema",
|
||||
Description: "Schema mới ApprovalWorkflowsV2 — Service iterate Steps/Levels theo workflow pin.",
|
||||
Transitions: transitions,
|
||||
PhaseSla: sla,
|
||||
ActivePhases:
|
||||
[
|
||||
PurchaseEvaluationPhase.DangSoanThao,
|
||||
PurchaseEvaluationPhase.TraLai,
|
||||
PurchaseEvaluationPhase.ChoDuyet,
|
||||
PurchaseEvaluationPhase.DaDuyet,
|
||||
PurchaseEvaluationPhase.TuChoi,
|
||||
]);
|
||||
}
|
||||
|
||||
// Build policy from persisted admin-authored definition (mirror
|
||||
// WorkflowPolicyRegistry.FromDefinition for HĐ).
|
||||
public static PurchaseEvaluationPolicy FromDefinition(PurchaseEvaluationWorkflowDefinition def)
|
||||
|
||||
Reference in New Issue
Block a user