[CLAUDE] PE-Workflow: S21 t5 Chunk A — Mig 29 refactor Allow* sang per-NV (per-Level + per-Drafter)
Refactor 6 Allow* options từ workflow-level (Mig 28 S21 t4) sang per-NV scope: - F1 (4 mode Trả lại) + F3 (Edit Section 2) → 5 flag MOVE xuống `ApprovalWorkflowLevels` (per slot Approver, cùng table với ApproverUserId). - F2 (AllowDrafterSkipToFinal) → MOVE xuống `Users` (per-Drafter user, User Mgmt). Mig 29 `RefactorAdvancedOptionsToPerLevelAndDrafterUser` — 4-stage migration (EF auto-generated drop-then-add đã được REORDER manual): 1. ADD 5 column trên `ApprovalWorkflowLevels` (AllowReturnOneLevel/OneStep/ ToAssignee/ToDrafter[default true]/AllowApproverEditDetails) 2. ADD 1 column trên `Users` (AllowDrafterSkipToFinal default false) 3. BACKFILL bulk SQL (preserve admin config Mig 28): - Levels: copy workflow.Allow* → all Levels của workflow (JOIN Steps) - Users: SET TRUE cho user nào từng Drafter PE link workflow Allow=true 4. DROP 6 column workflow-level (Mig 28 cleanup) 3-file rule complete. Apply LocalDB Dev + Design success. Domain entity refactor: - `ApprovalWorkflow.cs` — REMOVE 6 Allow* field (S21 t4 Mig 28 cũ) - `ApprovalWorkflowLevel.cs` — ADD 5 Allow* field (F1 + F3) - `User.cs` — ADD 1 Allow* field (F2 AllowDrafterSkipToFinal) EF config update: - `ApprovalWorkflowConfiguration.cs` — remove 6 HasDefaultValue workflow-level, add 5 HasDefaultValue per-Level (4 false + 1 AllowReturnToDrafter true S17) Service refactor `ApplyReturnModeAsync` (`PurchaseEvaluationWorkflowService.cs`): - Resolve currentLevel slot (CurrentWorkflowStepIndex + CurrentApprovalLevelOrder) - Read 5 Allow* từ `currentLevel.AllowXxx` thay vì workflow.Allow* - Admin bypass per-Level flag check (unchanged behavior) - Drafter mode đặc biệt: check AllowReturnToDrafter của currentLevel (vẫn validate) - V1 legacy (no V2 schema) → fallback Drafter behavior tự động DRAFTER trình refactor (`TransitionAsync` skipToFinal branch): - Permission check moved from workflow-level → `drafterUser.AllowDrafterSkipToFinal` - Use `userManager.FindByIdAsync(actorUserId)` để get current Drafter user entity - Admin bypass user flag check (unchanged) Helper `EnsureEditableForDetailsAsync` refactor: - Read `level.AllowApproverEditDetails` thay vì workflow.AllowApproverEditDetails - Error message rõ "Cấp Approver hiện tại (Bước X / Cấp Y)" thay vì "Workflow" DTO refactor: - `AwLevelDto` ADD 5 Allow* field (admin Designer GET per-Level) - `AwDefinitionDto` REMOVE 6 Allow* (no longer workflow-level) - `CreateAwLevelInput` ADD 5 Allow* param (admin Designer POST per-Level) - `CreateAwDefinitionCommand` REMOVE 6 Allow* (Steps[].Levels[] now has them) - `ApprovalWorkflowOptionsDto` chỉ còn 5 flag (F2 removed — separate field) - `PurchaseEvaluationDetailBundleDto`: - rename `WorkflowOptions` → `CurrentLevelOptions` (clearer semantic per-slot) - ADD `DrafterAllowSkipToFinal bool` (resolve từ DrafterUserId → User entity) GetPurchaseEvaluationQueryHandler populate: - `currentLevelOptions` = 5 Allow* của Cấp hiện tại (null nếu V1 legacy / no pointer) - `drafterAllowSkipToFinal` = User.AllowDrafterSkipToFinal lookup từ DrafterUserId Backward compat verified: - Mig 29 backfill preserve admin config S21 t4 — workflow cũ vẫn chạy đúng sau deploy. User chưa từng làm Drafter F2 phải opt-in lần đầu (no auto-set). - 84 test PASS (58 Domain + 26 Infra unchanged, 3 gotcha #45 guard test backward compat signature). Pending Chunk B/C: FE Admin Designer move 5 checkbox xuống per-Level slot + FE eOffice read currentLevelOptions + drafterAllowSkipToFinal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -34,45 +34,10 @@ public class ApprovalWorkflow : BaseEntity
|
||||
// khi tạo version mới (mirror IsActive default), admin có thể unstick.
|
||||
public bool IsUserSelectable { get; set; }
|
||||
|
||||
// ===== Mig 28 (Session 21 turn 4) — 6 advanced options per workflow =====
|
||||
// Cấu hình "Cấu hình nâng cao" trong Admin Designer. User eOffice render
|
||||
// dropdown/checkbox theo flag enabled. 4 flag Return* = mode Trả lại (F1).
|
||||
// 1 flag Skip = Drafter trình thẳng Cấp cuối (F2). 1 flag EditDetails =
|
||||
// Approver chỉnh Section 2 (F3).
|
||||
//
|
||||
// Default backward compat S17: AllowReturnToDrafter=true (mọi workflow cũ
|
||||
// chạy đúng — fallback "Trả về Drafter" như Session 17 spec). 5 flag còn
|
||||
// lại default false — admin opt-in per workflow để audit nghiêm.
|
||||
|
||||
/// F1 mode 1 — Cho phép Approver Trả lại 1 Cấp trước (lùi pointer trong
|
||||
/// cùng Step). Phiếu GIỮ Phase=ChoDuyet (peer review chain).
|
||||
public bool AllowReturnOneLevel { get; set; }
|
||||
|
||||
/// F1 mode 2 — Cho phép Approver Trả lại 1 Bước trước (lùi sang Step trước,
|
||||
/// set level = max của step đó). Phiếu GIỮ Phase=ChoDuyet.
|
||||
public bool AllowReturnOneStep { get; set; }
|
||||
|
||||
/// F1 mode 3 — Cho phép Approver Trả lại Người chỉ định (pick runtime từ
|
||||
/// list NV ĐÃ DUYỆT trong PeLevelOpinions). Phiếu GIỮ Phase=ChoDuyet, set
|
||||
/// Step/Level = vị trí của user pick trong workflow.
|
||||
public bool AllowReturnToAssignee { get; set; }
|
||||
|
||||
/// F1 mode 4 — Cho phép Approver Trả lại Người soạn thảo (Drafter). Phiếu
|
||||
/// đi vào Phase=TraLai, clear pointer (như Session 17 spec). Default TRUE
|
||||
/// để backward compat — admin có thể unstick force peer review only.
|
||||
public bool AllowReturnToDrafter { get; set; } = true;
|
||||
|
||||
/// F2 — Cho phép Drafter gửi thẳng Cấp cuối (skip mọi Bước/Cấp trung gian).
|
||||
/// UI eOffice trình duyệt thêm dropdown 2 option ("Gửi tuần tự" default vs
|
||||
/// "Gửi thẳng Cấp cuối"). BE set CurrentWorkflowStepIndex=maxStep,
|
||||
/// CurrentApprovalLevelOrder=maxLevel. Audit changelog "Drafter skip C1..N".
|
||||
public bool AllowDrafterSkipToFinal { get; set; }
|
||||
|
||||
/// F3 — Cho phép Approver chỉnh sửa Section 2 (Hạng mục + NCC + Báo giá)
|
||||
/// khi phase=ChoDuyet + actor match CurrentLevel.ApproverUserId. KHÔNG đụng
|
||||
/// PE Header (TenGoiThau/Project/Budget). KHÔNG reset workflow. Audit ghi
|
||||
/// PurchaseEvaluationChangelog cho mỗi field/row thay đổi.
|
||||
public bool AllowApproverEditDetails { get; set; }
|
||||
// Mig 28 cũ 6 column workflow-level Allow* đã DROP trong Mig 29 (S21 t5).
|
||||
// Refactor sang per-NV (per ApprovalWorkflowLevel slot + Users F2). Backfill
|
||||
// bulk SQL copy workflow → all Levels của workflow trước khi DROP — preserve
|
||||
// admin config từ S21 t4.
|
||||
|
||||
public List<ApprovalWorkflowStep> Steps { get; set; } = new();
|
||||
}
|
||||
@ -105,5 +70,33 @@ public class ApprovalWorkflowLevel : BaseEntity
|
||||
public string? Name { get; set; } // "Cấp 1" — display optional
|
||||
public Guid ApproverUserId { get; set; } // 1 NV cụ thể duyệt cấp này
|
||||
|
||||
// ===== Mig 29 (Session 21 turn 5) — 5 advanced options per slot =====
|
||||
// Cấu hình quyền duyệt riêng cho TỪNG NV trong slot này. Admin Designer
|
||||
// tick stick per Level row (KHÔNG còn workflow-level cũ Mig 28).
|
||||
//
|
||||
// F1 (4 mode Trả lại) + F3 (Edit Section 2) = quyền của Approver Level.
|
||||
// F2 (Drafter skip) đã move sang Users.AllowDrafterSkipToFinal (per-Drafter
|
||||
// user — không liên quan slot Approver).
|
||||
//
|
||||
// Backfill Mig 29: copy từ workflow-level Allow* cũ → all Levels của workflow.
|
||||
// Default backward compat: AllowReturnToDrafter=true (S17 fallback). 4 flag
|
||||
// còn lại default false (admin opt-in per Level).
|
||||
|
||||
/// F1 mode 1 — Lùi 1 Cấp trong cùng Bước. Phase giữ ChoDuyet (peer review).
|
||||
public bool AllowReturnOneLevel { get; set; }
|
||||
|
||||
/// F1 mode 2 — Lùi sang Bước trước Cấp cuối. Phase giữ ChoDuyet.
|
||||
public bool AllowReturnOneStep { get; set; }
|
||||
|
||||
/// F1 mode 3 — Pick runtime từ NV đã ký (PeLevelOpinions). Phase giữ ChoDuyet.
|
||||
public bool AllowReturnToAssignee { get; set; }
|
||||
|
||||
/// F1 mode 4 — Phase=TraLai, clear pointer (S17 fallback). Default TRUE.
|
||||
public bool AllowReturnToDrafter { get; set; } = true;
|
||||
|
||||
/// F3 — Cho phép NV này edit Section 2 (Hạng mục + NCC + Báo giá) lúc đang
|
||||
/// duyệt. KHÔNG đụng PE Header, KHÔNG reset workflow.
|
||||
public bool AllowApproverEditDetails { get; set; }
|
||||
|
||||
public ApprovalWorkflowStep? Step { get; set; }
|
||||
}
|
||||
|
||||
@ -27,4 +27,13 @@ public class User : IdentityUser<Guid>
|
||||
// Mỗi inner step yêu cầu user khớp DepartmentId + PositionLevel mới duyệt
|
||||
// được sub-step đó. Null cho admin/system/external user.
|
||||
public PositionLevel? PositionLevel { get; set; }
|
||||
|
||||
// Mig 29 (Session 21 turn 5) — F2 per-Drafter: cho phép user này (khi đóng
|
||||
// vai Drafter) gửi PE thẳng Cấp cuối, skip mọi Bước/Cấp trung gian. Workspace
|
||||
// hiện checkbox "Gửi thẳng Cấp cuối" conditional theo flag này.
|
||||
//
|
||||
// Mặc định false (an toàn). Admin set ở User Management page. Backfill
|
||||
// Mig 29: bulk set TRUE cho user nào từng Drafter PE link workflow có
|
||||
// workflow.AllowDrafterSkipToFinal=true (preserve admin config S21 t4).
|
||||
public bool AllowDrafterSkipToFinal { get; set; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user