Files
solution-erp/.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/sub-implementer-frontend-6.md
2026-07-27 12:24:07 +07:00

34 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# sub-implementer-frontend-6 — WAVE 5 · [F-7] nối dây FE cho `PUT /approval-workflows-v2/{id}` (vá F3 HIGH)
> run `2026-07-27-S155-pe-delete-approver` · WAVE 5 (vá 3 FLAG HIGH trước deploy) · vai `implementer-frontend`
> Ghi TRONG LÚC LÀM, flush từng phần (#53 đã ăn 5/5 sub run này). File luôn hợp lệ giữa chừng.
## 0. F3 nói gì (đọc nguyên văn `reviewer-diff-dot1.md:84-113`, không tóm tắt lại theo trí nhớ)
- **Đo được, không phải cảm giác:** `grep -rn "api.put" fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx`**0 hit**.
3 đường ghi duy nhất của Designer: `api.delete :286` · `api.patch …/user-selectable :297` · `api.post('/approval-workflows-v2') :589`.
- **Hệ quả:** ~600 dòng BE mới (`UpdateAwDefinitionCommand` + Validator + Handler + 3 helper) là **mã chết** với người dùng UAT.
Owner tick cờ F6 → Lưu → POST → sinh **Id MỚI** → phiếu đang treo pin **Id CŨ** (`PurchaseEvaluationWorkflowService.cs:674` `w.Id == awId`) ⇒ cờ **không bao giờ tới** phiếu cần cứu.
- **Reviewer cho 3 đường (a)/(b)/(c); owner đã chốt (a) = nối dây FE trong đợt 1.**
- **Tiêu chí nghiệm thu reviewer đặt (`:113`):** tick cờ F6 cho 1 NV trên version đang có phiếu treo → lưu bằng đường "Sửa tại chỗ" → `GET /api/approval-workflows-v2` trả `allowApproverDelete=true` trên **đúng `id` cũ**, `Version` **KHÔNG tăng**.
## 1. Hợp đồng BE — đọc THẲNG từ mã, không tin MEMORY-PACK
| Neo | File:line | Sự thật |
|---|---|---|
| Endpoint | `ApprovalWorkflowsV2Controller.cs:45-51` | `[HttpPut("{id:guid}")] [Authorize(Policy="Workflows.Create")]`, `mediator.Send(cmd with { Id = id })`**204 NoContent** |
| Command | `ApprovalWorkflowV2AdminFeatures.cs:449-464` | `{ Id, Name, Description, Steps, Reason?=null, Code?=null, ApplicableType?=null, CeoApprovalThreshold?=null }` |
| Step input | `:442-447` | `Id` **BẮT BUỘC** (Guid, không nullable) · `Order` · `Name` · `DepartmentId` · `Levels` |
| Level input | `:424-440` | `Id` **Guid?** (`null` = dòng MỚI) · `Order` · `Name` · `ApproverUserId` · **7 cờ an-toàn** (4×Return, EditDetails, EditBudget, **AllowApproverDelete**) · **2 cờ echo `bool?`** (SkipToFinal, Finalize) |
**3 bẫy payload (task nêu) — đối chiếu mã, cả 3 đều THẬT:**
1. **`CeoApprovalThreshold` ECHO NGHIÊM** — `:529` `if (request.CeoApprovalThreshold != def.CeoApprovalThreshold) throw ConflictException`.
KHÔNG phải "null = bỏ qua" (khác hẳn `Code`/`ApplicableType``:521`/`:525` dùng `is string`/`is int` nên null mới được bỏ qua).
⇒ gửi thiếu ⇒ `null != 5_000_000`**409**. Comment BE `:459-463` tự khai lý do: null LÀ giá trị có nghĩa (= bỏ ngưỡng).
2. **Chỉ trường hạng AN TOÀN.** Cấm (409): ±Bước (`:539`) · đổi `Step.Order` (`:554`) · đổi `Level.Order` từng dòng (`:575`) · ±Cấp / bỏ trống Cấp (`:618-630`) · `Code` · `ApplicableType` · `CeoApprovalThreshold` · F5 `AllowApproverFinalize` (`:580`) · F2 `AllowApproverSkipToFinal` (`:583`) · bỏ/đổi người đang có **chữ ký sống** (`:658-673`).
Cho sửa: thêm/bớt người trong Cấp CÓ SẴN · đổi `ApproverUserId` · 7 cờ quyền-tại-chỗ (gồm **F6**) · tên (workflow/step/level) · `Step.DepartmentId` (`:705-706`, BE **không** kiểm NV có thuộc Phòng hay không).
3. **Payload liệt kê tay từng field** (`:605-621` khối POST) — thêm field mà quên dây = **silent drop**, TS xanh, BE default `false`, UI vẫn tick. Đúng bẫy đã xảy ra thật ở `sub-implementer-frontend-2.md §2.4`.
<!-- phần 2+ ghi tiếp sau khi áp thay đổi -->