From b04a11a62fb1f7af2e49d7803302140c75a65bb8 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Wed, 13 May 2026 23:12:43 +0700 Subject: [PATCH] =?UTF-8?q?[CLAUDE]=20FE-PE:=20S22+5=20Chunk=20B=20?= =?UTF-8?q?=E2=80=94=20Designer=20checkbox=20+AllowApproverEditBudget=20pe?= =?UTF-8?q?r=20slot=20+=20Section=20read=20flag=20(mirror=202=20app)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FE Admin Designer (ApprovalWorkflowsV2Page.tsx): - LevelDto + EditLevelEntry +allowApproverEditBudget - copyFromDefinition + makeDefaultLevelEntry propagate default false - POST body include allowApproverEditBudget cho mỗi Level slot - NEW checkbox UI per Level inline panel: "Cho phép chỉnh sửa Section ngân sách lúc đang duyệt" (col-span-2, mirror pattern allowApproverEditDetails Mig 29) FE Types mirror 2 app: - fe-admin + fe-user `ApprovalWorkflowOptions` +allowApproverEditBudget FE BudgetAdjustSection refactor (mirror 2 app): - Trước: isApproverChoDuyet = phase ChoDuyet + actor in approvers - Sau: isApproverChoDuyet = phase ChoDuyet + actor in approvers + currentLevelOptions.allowApproverEditBudget=true (per slot opt-in) - Drafter scope Nháp/Trả lại unchanged - Admin bypass unchanged UX impact: - Admin Designer phải tick checkbox cho NV slot mới được edit ngân sách lúc duyệt - Nếu KHÔNG tick → button "Điều chỉnh" trong Section 5 KHÔNG hiện cho approver - Drafter vẫn edit bình thường khi phiếu Nháp/Trả lại Verify: - npm run build fe-admin — 569ms pass - npm run build fe-user — 528ms pass Co-Authored-By: Claude Opus 4.7 (1M context) --- fe-admin/src/components/pe/PeDetailTabs.tsx | 8 ++++++-- .../src/pages/system/ApprovalWorkflowsV2Page.tsx | 16 ++++++++++++++++ fe-admin/src/types/purchaseEvaluation.ts | 1 + fe-user/src/components/pe/PeDetailTabs.tsx | 6 +++++- fe-user/src/types/purchaseEvaluation.ts | 1 + 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx index 55173e5..2b72382 100644 --- a/fe-admin/src/components/pe/PeDetailTabs.tsx +++ b/fe-admin/src/components/pe/PeDetailTabs.tsx @@ -974,9 +974,13 @@ function BudgetAdjustSection({ ev, readOnly }: { ev: PeDetailBundle; readOnly: b const isDrafter = currentUser?.id != null && ev.drafterUserId === currentUser.id const isDrafterPhase = ev.phase === PurchaseEvaluationPhase.DangSoanThao || ev.phase === PurchaseEvaluationPhase.TraLai - // Approver currentLevel match — phase ChoDuyet + actor in current approval level + // F4 Approver scope (Mig 30): phase ChoDuyet + actor in currentApproval.approvers + // + currentLevel có flag AllowApproverEditBudget=true (admin Designer tick per slot). const actorInCurrentLevel = ev.currentApproval?.approvers?.some(a => a.userId === currentUser?.id) ?? false - const isApproverChoDuyet = ev.phase === PurchaseEvaluationPhase.ChoDuyet && actorInCurrentLevel + const approverEditBudgetAllowed = ev.currentLevelOptions?.allowApproverEditBudget ?? false + const isApproverChoDuyet = ev.phase === PurchaseEvaluationPhase.ChoDuyet + && actorInCurrentLevel + && approverEditBudgetAllowed const canAdjust = !readOnly && (isAdmin || (isDrafter && isDrafterPhase) || isApproverChoDuyet) diff --git a/fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx b/fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx index fae853d..6db2ead 100644 --- a/fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx +++ b/fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx @@ -42,11 +42,13 @@ type LevelDto = { approverUserName: string | null approverEmail: string | null // Mig 29 (S21 t5) — 5 Allow* options per slot Approver + // Mig 30 (S22+5) — +AllowApproverEditBudget cho Section ngân sách allowReturnOneLevel: boolean allowReturnOneStep: boolean allowReturnToAssignee: boolean allowReturnToDrafter: boolean allowApproverEditDetails: boolean + allowApproverEditBudget: boolean } type StepDto = { id: string @@ -86,11 +88,13 @@ type EditLevelEntry = { approverUserId: string // Mig 29 (S21 t5) — 5 Allow* per slot (default backward compat S17: chỉ // AllowReturnToDrafter=true, 4 còn lại false). + // Mig 30 (S22+5) — +AllowApproverEditBudget cho Section ngân sách (default false). allowReturnOneLevel: boolean allowReturnOneStep: boolean allowReturnToAssignee: boolean allowReturnToDrafter: boolean allowApproverEditDetails: boolean + allowApproverEditBudget: boolean } type EditStep = { name: string; departmentId: string | null; levelEntries: EditLevelEntry[] } @@ -137,6 +141,7 @@ function copyFromDefinition(d: DefinitionDto): EditStep[] { allowReturnToAssignee: l.allowReturnToAssignee ?? false, allowReturnToDrafter: l.allowReturnToDrafter ?? true, allowApproverEditDetails: l.allowApproverEditDetails ?? false, + allowApproverEditBudget: l.allowApproverEditBudget ?? false, })), })) } @@ -152,6 +157,7 @@ function makeDefaultLevelEntry(order: LevelOrder, approverUserId: string): EditL allowReturnToAssignee: false, allowReturnToDrafter: true, allowApproverEditDetails: false, + allowApproverEditBudget: false, } } @@ -553,6 +559,7 @@ function Designer({ allowReturnToAssignee: e.allowReturnToAssignee, allowReturnToDrafter: e.allowReturnToDrafter, allowApproverEditDetails: e.allowApproverEditDetails, + allowApproverEditBudget: e.allowApproverEditBudget, })), })), }) @@ -911,6 +918,15 @@ function Designer({ /> Cho phép chỉnh sửa Section 2 (Hạng mục/NCC/Báo giá) lúc đang duyệt + ) diff --git a/fe-admin/src/types/purchaseEvaluation.ts b/fe-admin/src/types/purchaseEvaluation.ts index 2c1d81e..15c7a98 100644 --- a/fe-admin/src/types/purchaseEvaluation.ts +++ b/fe-admin/src/types/purchaseEvaluation.ts @@ -355,6 +355,7 @@ export type ApprovalWorkflowOptions = { allowReturnToAssignee: boolean allowReturnToDrafter: boolean allowApproverEditDetails: boolean + allowApproverEditBudget: boolean // Mig 30 (S22+5) — F4 Section ngân sách } // Mig 28 (S21 t4) — F1 mode Trả lại payload gửi BE diff --git a/fe-user/src/components/pe/PeDetailTabs.tsx b/fe-user/src/components/pe/PeDetailTabs.tsx index b2891d7..6756cb5 100644 --- a/fe-user/src/components/pe/PeDetailTabs.tsx +++ b/fe-user/src/components/pe/PeDetailTabs.tsx @@ -981,8 +981,12 @@ function BudgetAdjustSection({ ev, readOnly }: { ev: PeDetailBundle; readOnly: b const isDrafter = currentUser?.id != null && ev.drafterUserId === currentUser.id const isDrafterPhase = ev.phase === PurchaseEvaluationPhase.DangSoanThao || ev.phase === PurchaseEvaluationPhase.TraLai + // F4 Approver scope (Mig 30): ChoDuyet + actor in approvers + flag tick. const actorInCurrentLevel = ev.currentApproval?.approvers?.some(a => a.userId === currentUser?.id) ?? false - const isApproverChoDuyet = ev.phase === PurchaseEvaluationPhase.ChoDuyet && actorInCurrentLevel + const approverEditBudgetAllowed = ev.currentLevelOptions?.allowApproverEditBudget ?? false + const isApproverChoDuyet = ev.phase === PurchaseEvaluationPhase.ChoDuyet + && actorInCurrentLevel + && approverEditBudgetAllowed const canAdjust = !readOnly && (isAdmin || (isDrafter && isDrafterPhase) || isApproverChoDuyet) diff --git a/fe-user/src/types/purchaseEvaluation.ts b/fe-user/src/types/purchaseEvaluation.ts index e18fbca..fa922f4 100644 --- a/fe-user/src/types/purchaseEvaluation.ts +++ b/fe-user/src/types/purchaseEvaluation.ts @@ -353,6 +353,7 @@ export type ApprovalWorkflowOptions = { allowReturnToAssignee: boolean allowReturnToDrafter: boolean allowApproverEditDetails: boolean + allowApproverEditBudget: boolean // Mig 30 (S22+5) — F4 Section ngân sách } // Mig 28 (S21 t4) — F1 mode Trả lại payload gửi BE