wal: flush 20260713T1611
This commit is contained in:
@ -7,7 +7,7 @@
|
||||
|
||||
## Stages
|
||||
- [x] Stage 1 — invest (fable-clone ensemble, 4× investigator-codebase) → **DONE 4/4 clean 0-garble** (`wf_eaf52972-d18`, ~11', 516K tok). Kết luận: **FE-ONLY** (BE+DB đã nhận âm; ngân-sách bất-biến bằng kiến-trúc). Spec `spec-pe-negative-quote-13-07-2026.md` ghi xong.
|
||||
- [x] gate — anh Kiệt CHỐT: R1 = CHO HĐ âm (no-op) · R2 = GIỮ chặn net≤0 (no-op). Implement = thuần FE + test.
|
||||
- [x] gate — anh Kiệt CHỐT: R1 = CHO HĐ âm (no-op) · R2 = **NỚI guard** `Sum()<=0`→`All(==0)` (anh hỏi lại: 1-NCC-âm phải gửi được, mâu thuẫn R1 → refine). Implement = FE + 1 điều-kiện BE guard + test.
|
||||
- [!] Stage 2 — review (fable-clone ensemble, 3× reviewer)
|
||||
- [ ] Stage 3 — review (fable-real, reviewer deep-pass)
|
||||
- [ ] gate — owner-decisions (nếu invest/review lòi ra)
|
||||
|
||||
@ -7,30 +7,31 @@
|
||||
|
||||
**Rule chốt (Duy Nguyen xác nhận 11:51):** số âm = khoản trừ/phát-sinh-giảm của **riêng NCC**; **NGÂN SÁCH GIỮ NGUYÊN** — quote âm KHÔNG cộng/trừ vào ngân sách dự án.
|
||||
|
||||
## ② Cách implement — **FE-ONLY** (0 BE · 0 migration · 0 bảng/cột mới)
|
||||
## ② Cách implement — **FE + 1 điều-kiện BE** (0 migration · 0 bảng/cột mới)
|
||||
|
||||
**Đã verify (invest 4-lane hội-tụ):** BE + DB **đã chấp nhận âm sẵn** — `UpsertPurchaseEvaluationQuoteCommand` (`PurchaseEvaluationDetailFeatures.cs:272`) KHÔNG validator, cột `ThanhTien decimal(18,2)` (`PurchaseEvaluationConfiguration.cs:131`) 0 CHECK constraint. Ngân sách (`PeWorkItemBudgets`) chỉ ghi bởi command budget role-gated → **quote âm không đụng ngân sách** (rule thỏa bằng kiến-trúc, 0 code). ⇒ **CHỈ sửa FE + gỡ đúng 3 chốt chặn âm.**
|
||||
**Đã verify (invest 4-lane hội-tụ):** BE + DB **đã chấp nhận âm sẵn** — `UpsertPurchaseEvaluationQuoteCommand` (`PurchaseEvaluationDetailFeatures.cs:272`) KHÔNG validator, cột `ThanhTien decimal(18,2)` (`PurchaseEvaluationConfiguration.cs:131`) 0 CHECK constraint. Ngân sách (`PeWorkItemBudgets`) chỉ ghi bởi command budget role-gated → **quote âm không đụng ngân sách** (rule thỏa bằng kiến-trúc, 0 code). ⇒ **Sửa FE (gỡ 3 chốt chặn âm) + nới 1 điều-kiện submit-guard BE (R2-revised).**
|
||||
|
||||
**4 thay đổi FE (mirror 2 app `fe-user` + `fe-admin` byte-identical — SHA-mirror bắt buộc):**
|
||||
**5 thay đổi (mirror 2 app `fe-user` + `fe-admin` byte-identical — SHA-mirror bắt buộc):**
|
||||
|
||||
1. **Input quote — AddSupplierDialog** `PeDetailTabs.tsx:2365` — thêm `neg` state + nút toggle **±**, hiển thị `formatVndInput(Math.abs(thanhTien))`, lưu `neg ? -parseVnd : parseVnd`. **Tái dùng pattern có sẵn `VndInlineEdit:1003`** (prop `allowNegative` + `neg` state `:1015` + toggle `:1025-1037` + save `neg?-n:n` `:1019`). KHÔNG reinvent.
|
||||
2. **Input quote — QuoteDialog** `:2917` — cùng pattern; `neg` init từ dấu của `existing.thanhTien` (mở lại quote âm phải hiện đúng, không trắng ô).
|
||||
3. **Submit gate — AddSupplierDialog** `:2226` `if (detailId && form.thanhTien > 0)` → `!== 0` (âm tạo quote; rỗng/0 vẫn skip = "chưa báo giá"). Toast `:2239` cùng sửa.
|
||||
4. **KHÔNG đụng** `parseVnd`/`formatVndInput` (dùng-chung ô ngân sách cùng file `:51-52`) + **KHÔNG** truyền allowNegative cho ô ngân-sách `thanhTienNganSach:2830` (giữ ≥0).
|
||||
5. **Submit-guard R2-revised (BE + FE mirror):** `PurchaseEvaluationWorkflowService.cs:206` `selectedThanhTien.Sum() <= 0` → `selectedThanhTien.All(x => x == 0)` (hoặc `!Any(x => x != 0)`) + FE mirror `PeDetailTabs.tsx:201` (`gia <= 0` → all-zero). Chặn **CHỈ khi chưa nhập giá nào**; có ≥1 giá thật (âm/dương, kể cả 1 NCC 1 hạng mục âm) → CHO gửi. Message giữ nguyên. `Count==0` (chưa chọn NCC) vẫn chặn riêng, không đổi.
|
||||
|
||||
**Semantics giữ:** rỗng/0 = "chưa báo giá" (skip tạo quote); âm = quote thật (≠ rỗng). `formatVndInput(-n)→''` là lý do PHẢI tách magnitude+dấu (không chỉ nới parseVnd).
|
||||
|
||||
**Tests (regression-lock invariant tài chính — test-specialist):**
|
||||
1. **Ngân sách giữ nguyên**: upsert quote âm → assert `PeWorkItemBudget` amounts UNCHANGED (`PeWorkItemBudgetTests`).
|
||||
2. `winnerQuoteTotal` = SUM mixed +/- selected (`PeMultiWinnerTests`).
|
||||
3. submit-guard: winner thuần-âm → blocked; mixed net>0 → submittable (`PeSubmitGuardAndBypassTests`).
|
||||
3. submit-guard R2-revised: **all-zero → blocked** (giữ test `:104`); **thuần-âm / net-âm → SUBMITTABLE** (có giá thật, kể cả 1 NCC 1 hạng mục âm); mixed net-any → submittable (`PeSubmitGuardAndBypassTests`).
|
||||
4. CCM-threshold với total giảm do âm (`PeCcmThresholdFinalizeTests`).
|
||||
|
||||
## ✅ Owner-decisions (anh Kiệt CHỐT S116 via AskUser)
|
||||
- **R1 — Contract.GiaTri âm: CHO PHÉP** (khuyến nghị). Luồng PE→HĐ giữ số âm; **KHÔNG thêm clamp/floor**; validator tạo-tay `ContractFeatures.cs:46` (GiaTri≥0) GIỮ nguyên (đường khác). → **code no-op** (allow = không chặn thêm).
|
||||
- **R2 — submit-guard net≤0: GIỮ CHẶN** (khuyến nghị). Guard `PurchaseEvaluationWorkflowService.cs:206` `Sum()<=0` + FE mirror `:201` GIỮ nguyên. → **code no-op**.
|
||||
- **R2 — submit-guard: NỚI (anh Kiệt refine S116)** — đổi chặn `Sum()<=0` → chặn CHỈ khi TẤT CẢ selected = 0 (`All(==0)`). Có ≥1 giá thật (âm/dương, **kể cả 1 NCC 1 hạng mục âm**) → CHO gửi. Lý do: rào cũ `Sum()<=0` bắt nhầm ca 1-NCC-âm → **mâu thuẫn R1** (cho HĐ âm nhưng không gửi được phiếu tạo ra nó). → **BE `:206` + FE mirror `:201` (fix nhỏ 2-tier).**
|
||||
- R3 (default): BgVat/ChuaVat giữ nguyên (FE chỉ expose input âm cho thanhTien).
|
||||
→ **Cả 2 chốt = giữ hành-vi hiện tại ⇒ implement thuần 4 thay-đổi FE + 4 test, 0 đụng BE.**
|
||||
→ **R1 no-op + R2 nới-guard ⇒ implement = 4 thay-đổi FE + 1 điều-kiện BE (submit-guard) + 4 test.**
|
||||
|
||||
## ③ Checklist (vai · deliverable · acceptance ĐO ĐƯỢC)
|
||||
| # | Vai | Deliverable | Acceptance đo được |
|
||||
@ -38,7 +39,8 @@
|
||||
| C1 | implementer-frontend | ± toggle + neg-state cho 2 input quote (`:2365`, `:2917`) × 2 app | Nhập `-5.000.000` → ô hiện `-5.000.000` (KHÔNG trắng); reopen quote âm hiện đúng dấu; SHA `fe-user`==`fe-admin` |
|
||||
| C2 | implementer-frontend | Submit gate `:2226` `>0`→`!==0` + toast `:2239` × 2 app | Thêm NCC với quote âm → tạo quote (không bị nuốt im lặng); rỗng/0 vẫn "chỉ tạo NCC" |
|
||||
| C3 | implementer-frontend | Ô ngân-sách `:2830` GIỮ ≥0 (không allowNegative) | Nhập `-` vào ngân sách hạng mục → bị chặn/không nhận |
|
||||
| C3b | implementer-backend + implementer-frontend | Submit-guard R2-revised: BE `:206` `Sum()<=0`→`All(==0)` + FE mirror `:201` × 2 app | Phiếu **1 NCC 1 hạng mục âm → GỬI được**; phiếu selected toàn 0 → vẫn chặn "chưa báo giá" |
|
||||
| C4 | test-specialist | 4 test regression-lock (ngân-sách-giữ-nguyên + winnerTotal + submit-guard + CCM-threshold) | `dotnet test` xanh; test #1 chứng budget bất-biến khi quote âm |
|
||||
| C5 | reviewer + cicd | build 2-app + deploy | `npm build` 2-app pass; bundle rotate; prod nhập âm được (anh UAT incognito) |
|
||||
|
||||
**Trạng thái sau implement dự kiến:** Mig 65 (GIỮ) · 89 bảng (GIỮ) · test 486→~490 · FE 2-app bundle rotate. FE-only → CI chạy (path-filter không skip vì `.tsx`).
|
||||
**Trạng thái sau implement dự kiến:** Mig 65 (GIỮ) · 89 bảng (GIỮ) · test 486→~490 · FE 2-app bundle rotate + BE 1 điều-kiện guard. → CI chạy (path-filter không skip).
|
||||
|
||||
Reference in New Issue
Block a user