Files
solution-erp/docs/changelog/sessions/2026-06-19-S76-pe-budget-matrix-table-grid.md
pqhuy1987 8f780b6237 [CLAUDE] Docs: S76 closeout — PE ngan sach ma tran 3 cot + bang luoi + badge quyen-NS
STATUS/HANDOFF (Mig 55->56, test 339->344, gotcha 69->70, bundle jOqxW4-p/DbsznVvR
Run #319, Phase +S76, In Progress->Recently Done) + gotcha #70 (FE absolute-set echo
stale-echo data-loss -> useIsFetching gate) + ef-core skill Mig 56 row + session log
2026-06-19-S76 + agent-memory harvest (impl-FE stray->canonical + 4 sub diary).
Curate-debt carry: reviewer 45KB + inv-codebase 35KB keep-floor-hit manual-condense.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:44:34 +07:00

49 lines
6.5 KiB
Markdown
Raw Permalink 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.

# S76 (2026-06-19) — PE ngân sách MA TRẬN 3 cột + bảng lưới `<table>` + badge quyền-NS theo role
> **Anh Kiệt FDC + chị Trà Sol — go-live.** anh giao `/ultra-on` "làm hết, step-by-step có workflow review kiểm tra đàng hoàng, hoàn chỉnh rồi deploy báo tao".
## Bối cảnh (chat Zalo anh forward)
- Chị Trà Sol + anh Kiệt: panel "TỔNG HỢP NGÂN SÁCH TRÌNH KÝ" — **mỗi phòng (PRO/CCM) nhập + điều chỉnh ngân sách của CHÍNH phòng mình**; ảnh Excel = ma trận cột **DỰ ÁN | PRO | CCM**, mỗi cột có Ban hành lần đầu + V0/hiệu chỉnh → full = tổng.
- Thêm: cột tích "quyền nhập/điều chỉnh NS" bên flow (nhìn biết ai sửa được) + hiển thị ra fe-user mục Duyệt NCC.
## 2 fork anh chốt (AskUserQuestion)
1. **Cột DỰ ÁN** = FE hiển-thị-only (`—`), sau mới có người bên dự án nhập (đơn giản nhất, FE-only).
2. **Ô tích quyền NS ở flow** = chỉ-hiển-thị, GIỮ quyền theo role (PRO→cột PRO, CCM→cột CCM) — làm trước cho nhanh, KHÔNG configurable.
## Step 1 — ĐIỀU TRA (verify-workflow: "phần này hôm qua làm chưa?")
3 lens độc-lập (code-gate + git-history + adversarial) → **CHƯA**. Hôm qua S74 chỉ thêm CcmNote. Ngân sách edit thuần ROLE (`canEditPro`/`canEditCcm`, `PurchaseEvaluationFeatures.cs:800-801`), KHÔNG có submission-count lock. Phát hiện: "Ban hành/hiệu chỉnh" cũ gán CCM, nhưng ảnh Excel cho thấy PRO mới điền → design mới phải TÁCH mỗi phòng cột riêng.
## Done — 3 commit prod-verified
### `e33481e` (feature, cicd Run #318 PASS, bundle admin `BhFDF9IJ` / user `BAkuRl3C`)
- **Part 1 — form ma trận 3 cột.** Data-model (em-main solo, additive-an-toàn):
- Entity `PeWorkItemBudget` +`ProInitialAmount`+`ProAdjustmentAmount` (decimal 18,2 nullable) — cột PRO; tái dùng `InitialAmount`/`AdjustmentAmount` làm cột CCM (đã canEditCcm-gate). `ProEstimateAmount` = LEGACY (FE bỏ).
- **Mig 56 `AddProBudgetSplitToPeWorkItemBudget`** — 2 AddColumn additive + `Sql()` data-migrate `UPDATE PeWorkItemBudgets SET ProInitialAmount=ProEstimateAmount WHERE ProEstimateAmount IS NOT NULL AND ProInitialAmount IS NULL` (giữ số PRO cũ; chạy SAU AddColumn; idempotent; **4 rows backfill prod** gotcha #64). Additive-only → tránh gotcha #63. ASCII-only comment (gotcha #30).
- Handler `UpdatePeBudgetProCommand` đổi `(PeId, ProInitialAmount, ProAdjustmentAmount, ProNote)` absolute-set, role-gate PRO/Admin Forbidden TRƯỚC side-effect + validator (ProInitial≥0, ProAdjust cho-âm) + controller `BudgetProBody` + DTO `PeBudgetSummaryDto` +2 field + capability `full` = CCM nếu hasCcm else proFull, `FullIsEstimate = !hasCcm && hasPro`.
- FE 2 app SHA-mirror: `PeBudgetSummaryTable` Block A ma trận (DỰ ÁN hiển-thị-only / PRO canEditPro / CCM canEditCcm) + `BudgetCell` compact + `BudgetNoteRow`. proFull/ccmFull = ban-hành + hiệu-chỉnh mỗi cột.
- **Part 2+3 — badge quyền-NS theo role (display-only).**
- BE: +2 cờ `CanEditProBudget`/`CanEditCcmBudget` per approver — tính qua 3 `GetUsersInRoleAsync` set-lookup (ProcurementAdmin / CostControlAdmin, **no N+1**, khớp gate `canEditPro`/`canEditCcm` bit-for-bit) → vào `AwLevelDto` (designer, `ApprovalWorkflowV2AdminFeatures.cs`) + `PurchaseEvaluationApprovalLevelApproverDto` (PE flow, 2 build-site: approvalFlow + currentApproval).
- FE: badge "✎ NS PRO"(amber)/"✎ NS CCM"(sky) cạnh approver ở `ApprovalWorkflowsV2Page` (fe-admin designer) + `PeWorkflowPanel` (2 app, `.join`→map từng approver). Types +2 cờ CẢ 2 app (purchaseEvaluation.ts types DIFFER giữa 2 app).
- **Test 339→344** (+5 PRO split: set cả ProInitial+ProAdjust gồm âm · validator · full=proFull khi CCM empty · full=CCM khi CCM present). test-specialist.
### `21d1f4e` (bảng lưới, cicd Run #319 PASS, bundle admin `jOqxW4-p` / user `DbsznVvR`)
- Anh phản hồi "giao diện vẫn chưa chia cột giống Excel" — Block A cũ dùng flex+gap (KHÔNG viền dọc) → chuyển **`<table border-collapse>` viền ô đầy đủ** (header Khoản mục|Dự án|PRO|CCM + 5 hàng: full / ban hành / hiệu chỉnh / ghi chú PRO / ghi chú CCM).
- `BudgetCell` xếp DỌC (input full ô + nút Lưu dưới — vừa cột hẹp). `BudgetNoteRow``BudgetNoteCell` (td colSpan=3, ghi chú trải hết).
- FE-only, 2 app SHA-mirror. **LESSON: flex+gap KHÔNG ra "bảng" — phải `<table>` viền ô mới giống spreadsheet.**
### Race fix (gotcha #70 NEW)
Reviewer workflow Part 2/3 escalate MAJOR data-loss: 2 ô PRO (ban hành + hiệu chỉnh) lưu qua CÙNG `proMut`, mỗi save echo field anh-em từ `bs` (server snapshot). Lưu ô A → `invalidate()` refetch BẤT-ĐỒNG-BỘ; trước khi refetch về, `bs.proInitial` còn CŨ → lưu ô B đè mất A. Vá: gate nút Lưu = `mut.isPending || useIsFetching({queryKey:['pe-detail',ev.id]}) > 0` (khoá tới khi refetch land). 2 app. Pattern absolute-set-echo có từ CCM Mig 50/55 prod chưa-báo-lỗi nhưng PRO nhân-đôi bề-mặt → vá trước go-live tài-chính.
## Workflow / harness
- HMW-mode ON (`/ultra-on`). 1 verify-workflow (Step-1) + 2 review-workflow (Part 1 · Part 2/3). Mỗi step build + review trước khi sang step kế (đúng anh giao).
- **Workflow-review-flaky:** 2/3 lane Part 1 + 1/3 lane Part 2/3 return RỖNG (#53). Lane trả về thì đầy-đủ + chính xác. → em-main self-gate lane rỗng (BE đã test-spec verify + build/test pass; FE lane cross-check). Khớp `feedback_workflow_fanout_reliability`: verify-heavy → em-main self-gate ≈ spawn lẻ.
- cwd-misland (gotcha tái diễn): impl-FE `cd fe-admin` npm build → MEMORY rơi `fe-user/.claude` stray → em-main harvest về canonical + thêm `.gitignore` guard `fe-*/.claude/`.
## State THẬT (verified)
Mig **56** · 88 bảng · **344** test (45D+299I) · gotcha **70** · menu 54 · bundle admin **`jOqxW4-p`** / user **`DbsznVvR`** (Run #319) · RAG 2428 · user-memory 29.
## 🔴 NEXT
- **Em (carry ưu-tiên):** curate L1 over-cap — reviewer **45KB** + inv-codebase **35KB** (keep-floor-hit, entries newest lớn → manual SPLIT/condense) + cicd 29KB + test-spec 28KB (strike-1). archive-gate A7 PASS 186/186.
- **Anh/anh Kiệt:** UAT bảng lưới (Ctrl+F5) bằng PRO/CCM; xem badge ✎NS trong Designer + flow.
- **Ops giữ:** tzutil VPS · anh Chương email typo · 5 real-staff pw · gán CNTT. Monthly audit 2026-07-01.