Completes the Mig 58 multi-winner (>=2 cung trung) wiring — the audit's joint-winner
dead-ends, CEO-approved scope ("1 HD per winner"):
- create-contract 1->N: one draft HD per IsWinner supplier (was 409 dead-end for >=2).
Command -> List<Guid>. ContractCodeGenerator self-commits its sequence per call, so
gen all N codes first (contracts built local) then atomic add + single final
SaveChanges (no partial create on failure). GiaTri: single = details ThanhTienNganSach
sum (legacy preserved); >=2 = per-winner quote total (DangSoanThao draft, editable —
anh Kiet UAT the basis). pe.ContractId = first (idempotency). Controller -> {contractIds}.
- list-card winner names: PurchaseEvaluationListItemDto +WinnerSupplierNames (EF
collection subquery over IsWinner suppliers; translates + runs on SQLite — test-verified).
FE PeListPanel shows joined names for >=2 (was blank). Dialog -> contractIds[] + "Da tao N HD".
Tests 413 -> 419 (+6: multi-contract 5 [per-winner GiaTri 140/260 vs single legacy 800,
idempotency, 0-winner, not-DaDuyet] + EF-subquery translation smoke). Full suite GREEN.
FE 2-app SHA-identical. reviewer PASS (codegen-sequencing, positional-record arg-order,
no-partial-create all independently verified).
UAT (anh Kiet): open a >=2-winner phieu -> "Tao HD" creates N draft contracts (1/winner);
confirm per-winner contract GiaTri (quote total) is the wanted basis.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PE stability audit (frozen CEO-approved spec) — D1 behavior-preserving fixes plus
one approved joint-winner financial correction:
- Block B "Gia tri ky nay" + cross-PE peer rollup re-keyed SelectedSupplierId -> IsWinner
(reported 0 / excluded peers for >=2 joint winners; now matches winnerQuoteTotal).
- CEO-notify-on-urgent: +SaveChanges after NotifyManyAsync (Director notify was added
after the only flush -> never persisted; now persists + SignalR push fires).
- HoSoLink: UpdatePeDraft null-safe + clear-via-empty (header edit no longer wipes a
set link; HoSoLinkRow sends "" to clear; header forms omit = preserve).
- #70 stale-echo guard added to PRO budget row3/row8 (|| peFetching).
- Relocate SetPeCcmBudgetPeriodCommand -> PeWorkItemBudgetFeatures (was misplaced in
PeSuggestedPriceFeatures). DTO/comment cleanups.
Tests 402 -> 413 (+11: HoSoLink preserve/clear/set, Block B >=2-winner, CEO-notify
persist x6). Full suite GREEN. FE 2-app SHA-identical. test-specialist + reviewer
returns truncated (#53, over-budget MEMORY) -> em-main self-gate from disk + suite run.
D2 deferred (create-contract 1-HD-per-winner + list-card winner names) — needs focused
care + anh Kiet UAT on per-winner contract value.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tách c/d/e (Giá chào thầu + Đề xuất PRO/CCM + Bảng so sánh + Link hồ sơ) khỏi
Section 3 thành khối NỔI BẬT riêng "4. Thông tin chọn thầu" — header xanh #1F7DC1
giống bảng ngân sách "giá trị thực hiện". Đánh số lại 1->5:
- 1. Tên NCC/TP + Giá trị (chào thầu): winner "mang từ trên xuống", hiển-thị nổi bật
(Section 3 giữ ô CHỌN NccSelectorRow; multi-winner -> tên cách dấu phẩy)
- 2-3. Giá đề xuất PRO/CCM (SuggestedPriceRows) · 4. Bảng so sánh giá · 5. Link hồ sơ
- Ý kiến cấp duyệt: Section 4 -> 5.
FE-only (PeDetailTabs ChonNccSection + new ThongTinChonThauSection), 2 app SHA-mirror,
build sạch. Mockup anh Kiệt duyệt trước khi build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CCM (Lưu Trần / anh Kiệt FDC) — làm 3/4 mục (mục 3 "CCM sửa ngân sách" để riêng):
1. Multi-winner: chọn NHIỀU NTP/NCC/ĐVDV cùng trúng → winnerQuoteTotal = SUM
ThanhTien MỌI đơn vị isWinner (vd 3 ông 37.8+9+10 = 56.8tr). Cột mới
PurchaseEvaluationSupplier.IsWinner (Mig 58, backfill từ SelectedSupplierId).
SelectWinner → multi-toggle SupplierIds[]. FE: bảng so sánh tick nhiều ô +
dòng "Tổng chi phí đã chọn"; mọi guard/checklist/computeGiaChaoThau/tạo-HĐ
đổi sang isWinner (selectedSupplierId = null khi liên-danh ≥2).
2. Ngân sách = 0 hợp lệ: nới submit-guard + 3 validator (chỉ chặn khi NULL,
số 0 cố ý đi qua; fallback ProInitial chỉ khi null). Mirror BE + FE.
3. Cấp KẾT THÚC quy trình: ApprovalWorkflowLevel.AllowApproverFinalize (Mig 58)
— admin bật per-cấp trong Workflow Designer; duyệt tới cấp đó TỰ DaDuyet,
bỏ qua CEO (AUTO theo cấu hình quy trình, không ô-tích runtime — anh Kiệt
chốt). FE: banner cảnh báo + bắt chọn giá chốt.
Mig 58 AddPeMultiWinnerAndLevelFinalize (2 AddColumn bool + backfill IsWinner,
additive/reversible). Test 377→395 (+PeMultiWinnerTests +PeApproverFinalizeTests
+budget=0; auto-model gọn bớt 2 test bypass/opt-out). FE 2 app SHA-mirror.
Build sạch BE + 2 FE local.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phiếu cũ thiếu workflow (tạo lúc bundle cũ chưa có D5 auto-chọn) → checklist D4 toàn xanh
nhưng submit chặn "chưa chọn quy trình" = MISLEADING. Bổ sung dòng "Quy trình duyệt" vào
checklist (xanh ✓ khi có workflow, đỏ ✗ khi thiếu) → người dùng thấy đúng blocker.
3 phiếu thiếu workflow đã fix prod-data (gán QT-DN-V2-001 cho type-1). R4 auto-assign-at-submit
đã thử nhưng REVERT: phá 2 test S83 (test-DB có sẵn workflow → auto-gán thay vì block) + nới
block ngược ý "ràng". SQL fix + create-block/D5 (R1) đã đủ chặn phiếu thiếu workflow.
FE-only PeDetailTabs ×2 app SHA-identical. Both build PASS, test 371 (revert verified).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anh chốt "không chọn quy trình thì không cho tạo phiếu, ràng mấy cái rủi ro lại hết":
- Form TẠO: nút "Tạo phiếu" disabled khi thiếu (Quy trình duyệt / Hạng mục / Dự án) + hint
ĐỎ liệt kê rõ còn thiếu gì (✓ xanh khi đủ). Defense-in-depth với BE validator NotEmpty (S83).
- Detail (D4): checklist xanh ✓ "đã khai" / đỏ ✗ "chưa khai" cho 4 trường bắt buộc gửi duyệt
(NCC winner · giá>0 · ngân sách · bảng so sánh) hiện phía trên nút "Lưu & Gửi Duyệt"
(mirror missingForApproval predicate, khớp annotation anh Kiệt "xanh=đã khai, đỏ=chưa khai").
FE-only 2 component × 2 app SHA-identical. Both build PASS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
D2 — Người KHAI phiếu tự GỠ cờ GẤP của mình (nới luật S77 "GỠ=chỉ TP"). BE handler
restructure SET/UNSET: GẮN giữ role-only (PRO/CCM/Admin); GỠ +drafter (DrafterUserId==actor)
→ drafter/Admin clear CẢ 2 cờ, TP-vai clear cờ vai mình. FE canToggle +isDrafter.
D3 — "Ngân sách kỳ này" (row3) tự nhảy từ "Ngân sách Ban hành lần đầu"
(PeWorkItemBudget.ProInitialAmount) khi chưa nhập tay. Submit-guard BE + FE missingForApproval
dùng effective = budgetPeriodAmount ?? proInitialAmount (mirror 2 tầng, chống bypass gotcha #44).
BE 2 file (Urgent handler + Workflow submit-guard). FE PeDetailTabs ×2 app SHA-identical.
Test +5 PeUrgentToggleAuthzTests (drafter-self-unset authz matrix) → 371 PASS. BE slnx + 2 FE build PASS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Modal Duyet them picker multi-file -> upload TRUOC khi chuyen phase (file loi/>20MB = throw, khong duyet). File hien o muc 'File dinh kem khi duyet' (download/preview) trong Panel quy trinh, gan ten nguoi tai + thoi gian. Fix 2 filter dung supplierId=null lam proxy Bang-so-sanh (banSoSanhAttachments + submit-guard) loai purpose=5 tranh lan section + false-pass. FE 2 app SHA-identical. authz: approver upload duoc (handler khong guard drafter-only). Test 354 PASS, no migration. UAT Tra Sol / 5 tester.
Bich Phuong hoi 'chi Tra tra ve thi bam nop lan 2 cho nao'. Phieu Tra lai o che do XEM (readOnly) khong co nut 'Luu & Gui Duyet' (nut do chi hien khi Sua) -> NV khong biet gui lai. Them banner amber khi phase==TraLai && readOnly: huong dan ra danh sach -> ✏️ Sua (but chi) -> dieu chinh -> 'Luu & Gui Duyet ->' o cuoi phieu; ly do tra lai xem o Lich su. Khop dung cau tra loi cua anh cho Bich Phuong. FE-only, 2 app SHA256-identical PeDetailTabs. Build PASS x2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tra Sol + anh Kiet (Zalo chot 14:25): tranh NV khac lo tay go co cua nguoi da gan. Handler SetPurchaseEvaluationUrgent gate BAT DOI XUNG theo IsUrgent: GAN (true) = role chuc nang (Procurement->do / CostControl->xanh / Admin->ca 2); GO (false) = role chuc nang + DeptManager (Truong phong) hoac Admin. FE PeDetailTabs nut toggle gate theo trang thai hien tai (da gap->can quyen GO; chua gap->can quyen GAN) → an nut GO voi NV thuong. Test PeUrgentToggleAuthzTests rewrite asymmetric (354 PASS 0 fail). FE 2 app SHA256-identical. Build slnx 0-err.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tra Sol + anh Kiet (Zalo, annotate anh do): muc con (khong co so) thut vao + gach dau dong '–' de phan biet voi muc cha co so (1-9). BudgetRow +indent prop (pl-5 + dash span). Ap dung: Block A '– Ngan sach Ban hanh lan dau' + '– Ngan sach V0/hieu chinh tang giam' (con cua Ngan sach full); Block B '– Gia tri ky nay' + '– So sanh voi ngan sach ky nay' + '– So voi NS' + '– So sanh voi Ngan sach full'. Muc 1-9 giu cap cha. FE-only, 2 app SHA256-identical PeDetailTabs. Build PASS x2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tra Sol (Zalo): cai nao la so am thi ngoac + mau do. Hang 7 (Ngan sach con lai) / 8 (Gia tri thuc hien du kien con lai) / 9 (Gia tri tong thuc hien du kien) dang dung fmtVnd (dau tru, mau mac dinh) -> chuyen sang fmtVndSigned (ngoac '(abs) d' cho so am, da co san) + span text-red-600 khi <0; dong bo voi cac hang 'So sanh' (cmpPeriod/cmp56/cmpFull da do+ngoac tu truoc). FE-only, 2 app SHA256-identical PeDetailTabs. Build PASS x2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Theo Tra Sol + anh Kiet FDC (Zalo): A) o nhap tien VndInlineEdit + BudgetCell nhay phan cach vi-VN (300.000.000) on-keystroke (o dialog da co san). B) them o ghi chu PRO + CCM canh nut Luu trong khoi Gia de xuat (giai thich vi sao chon Min/Max) — Mig 57 AddPeSuggestedPriceNotes (+ProSuggestedPriceNote +CcmSuggestedPriceNote nvarchar(1000) null, additive no-backfill no-table); 2 setter command +Note absolute-set rides role-gate PRO/CCM/Admin; DTO +2 field; controller body +note. C) sua chinh ta 'd. Ban so sanh' -> 'd. Bang so sanh gia' (2 app). GUARD gotcha #70: o gia + ghi chu echo nhau absolute-set -> them peFetching khoa nut Luu toi khi pe-detail refetch land, tranh stale-echo mat du lieu (mirror bang ngan sach S76; em-main review bat impl-frontend sot guard). BE slnx 0-warn 0-err; FE build PASS x2; test 344->351 (+7); PeDetailTabs/PeWorkspaceCreateView 2 app SHA256-identical.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
anh Kiet/Tra Sol UAT: list state dang canh giua (max-w-5xl) trong 2 ben -> tra ve bo cuc goc 8e68ed1: grid lg:[400px_1fr_360px], list bam trai + 2 placeholder panel lap day man hinh, KHONG canh giua. Giu nguyen focus overlay S78 (bam phieu -> overlay truot tu phai che het menu+list; Duyet/Thu gon/Esc -> dong ve danh sach). <lg single-col compact. 2 app SHA256-identical. FE-only, 0 BE, 0 migration. Build PASS x2. Recover tu agent process-death (edit hoan chinh tren disk, em-main build-verify + mirror fe-admin).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface co gap GAP tren MOI danh sach phieu de CEO/nguoi duyet thay urgency ngay tren danh sach khong can mo phieu (anh Kiet FDC). Cay danh sach: emoji -> pill labeled. Khung 'Danh sach phieu' cho duyet (Workspace + picker) + inbox 'phieu cho toi duyet': them pill (truoc day thieu). NEW PeUrgentChips.tsx single-source-of-truth (style khop badge detail S69) x2 app. FE-only, 0 BE, 0 migration — DTO da co IsUrgentByPro/Ccm tu S69 Mig 53. Build PASS x2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anh: "giao dien van chua chia cot dung, muon giong file Excel". Block A dang dung
flex + spacing (khong co vien doc chia cot) -> chuyen sang <table border-collapse>
vien o day du: header [Khoan muc | Du an | PRO | CCM] + 5 hang (full / ban hanh /
hieu chinh / ghi chu PRO / ghi chu CCM). BudgetCell xep doc (input full o + nut Luu
duoi) cho vua cot. BudgetNoteRow -> BudgetNoteCell (td colSpan=3). Mirror
fe-user/fe-admin identical. FE-only, build 2 app PASS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
S76 (anh Kiet FDC + chi Tra Sol) — form ngan sach + hien thi quyen nhap NS trong flow:
- Part 1: form ngan sach -> MA TRAN 3 cot, moi phong nhap+dieu chinh cot minh
(PRO canEditPro / CCM canEditCcm / Du an FE hien-thi-only). Mig 56
+ProInitialAmount/ProAdjustmentAmount (additive-nullable + data-migrate
ProEstimate->ProInitial). full moi cot = ban hanh + hieu chinh.
- Part 2: Workflow Designer (fe-admin) +badge "NS PRO/CCM" canh approver
(suy tu role Admin|Procurement / Admin|CostControl, hien-thi-only no-authz).
- Part 3: flow quy trinh fe-user/fe-admin (Duyet NCC) +badge tuong tu.
- Fix race mat-du-lieu Part 1 (useIsFetching khoa Luu khi refetch — dong
cua-so stale-echo, reviewer Part2/3 bat).
- Test 339->344 (+5). 2 workflow review (Part 1 PASS + Part 2/3 PASS).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Theo note anh Kiệt FDC (go-live so-sánh-giá thứ Hai):
- (1) Giá chào thầu thêm giá đề xuất NGOÀI giá NCC: PRO nhập dải Min/Max +
CCM nhập 1 giá (2 lệnh role-gate Procurement/CostControl, fail-closed).
Khi duyệt cấp cuối, người duyệt CHỌN 1 giá chốt (Ncc/ProMin/ProMax/Ccm)
-> luu ApprovedPriceAmount/Source (bind tai moi nhanh DaDuyet, bat buoc
chon; auto-approve he thong mien).
- (3) CCM duyet-done mien CEO: DOI tu AUTO-threshold (S69) sang O-TICH-TAY
(finalizeByCcmDelegation) -- CCM chu dong tich, fail-closed theo nguong
+ role + gia goi. An toan hon (khong vo tinh bo CEO).
- Mig 54 additive-nullable (5 cot PE) - FE 2 app SHA-mirror - test 306->334
(+28: opt-in 6->11, +10 gia chot, +13 setter authz).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Yêu cầu anh Kiệt FDC (sau họp sếp). Mig 53 AddPeUrgentAndCeoApprovalThreshold — 3 AddColumn, no new table (Mig 52→53). Rollout an toàn: cột nullable, ngưỡng null = giữ luồng duyệt cũ 100% cho tới khi admin set.
B — CCM duyệt-final theo NGƯỠNG GIÁ TRỊ ("gói CEO phân quyền theo giá trị"):
- ApprovalWorkflow += CeoApprovalThreshold (decimal?, admin nhập trong Workflow Designer).
- ApproveV2Async: actor role CostControl (CCM) + winnerQuoteTotal (tổng giá NCC được chọn) < ngưỡng → DaDuyet luôn (bỏ CEO); ≥ ngưỡng → đẩy lên CEO như cũ. Ngưỡng null = luồng tuyến tính cũ. Q4 chốt nhận diện theo ROLE người duyệt.
- reviewer PASS 0 blocker: cascade-safe (Off/role không lan), tested load-bearing (CCM dưới ngưỡng → DaDuyet skip CEO).
A — cờ gấp per-vai (visibility-only, Q3 KHÔNG đổi luồng):
- PE += IsUrgentByPro (PRO đỏ) / IsUrgentByCcm (CCM xanh).
- Endpoint PUT /purchase-evaluations/{id}/urgent role-gated (Procurement→ByPro, CostControl→ByCcm, Admin→cả 2, khác→Forbidden) + notify CEO (Director) khi MỚI bật (best-effort).
FE ×2 app: Workflow Designer ô "Ngưỡng giá trị gói CEO" (fe-admin) + PE detail nút bật/tắt cờ gấp đỏ/xanh theo role + badge GẤP + hint "giá trị gói vs ngưỡng → CCM duyệt-final/cần CEO" + PE list badge gấp.
DTO: PE detail += isUrgentByPro/Ccm + winnerQuoteTotal + ceoApprovalThreshold; list += isUrgentByPro/Ccm; workflow V2 += ceoApprovalThreshold.
+14 test (292→306): PeCcmThresholdFinalizeTests 5 (B routing) + PeUrgentToggleAuthzTests 9 (A authz). Build slnx 0/0 · npm build ×2 0 err · dotnet test 306 PASS.
C (sau duyệt xong chuyển phiếu đến dự án) — chờ anh Kiệt làm chi tiết form, CHƯA làm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anh: hiển thị cha-con với gốc SOLUTION COMPANY trên cùng, phòng ban fan-out xuống
(giống NamGroup "Nam Group" là gốc). Gộp nút "Tất cả phòng ban" + list phẳng thành
1 node gốc công ty trong EmployeesListPage org-tree panel: chevron mở/gập
(companyOpen, mở mặc định) + bấm tên = pickDept(null) tất cả NV + CountBadge tổng;
các phòng ban render TreeNode depth=1 toả xuống dưới. Build PASS fe-user (tsc -b).
fe-user only (mirror fe-admin defer cùng Phase B).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Anh: bố trí Hồ sơ Nhân sự giống NamGroup HRM. Dựng lại EmployeesListPage:
- Panel trái: cây tổ chức (consume GET /departments/tree) — expand/collapse + badge
số đếm (totalEmployeeCount) + click lọc theo phòng. Co thành toggle màn hẹp.
- Panel giữa: list (search + status filter) + avatar gradient + status badge.
- Panel phải: chi tiết 5 tab (Tổng quan/Thân nhân/Trình độ/Kinh nghiệm/Hợp đồng) +
avatar header lớn (gradient brand). Tổng quan 2 cột.
GIỮ 100% 5 satellite CRUD (16 endpoint byte-identical grep-verified) + search + filter
+ query keys. Foundation màu mới + brand #1F7DC1 giữ. Build PASS (tsc -b). fe-admin mirror defer.
(frontend-designer return-rỗng/#53 → em main recover từ disk + build-verify + self-gate.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Root cause: o "Gia tri thuc hien du kien con lai" (row 8 bang Tong hop ngan sach) khi gia tri NCC vuot ngan sach -> so du con lai ra AM; BE validator ExpectedRemainingAmount>=0 + FE VndInlineEdit khong bat allowNegative -> chan cung "am ko luu duoc" (testing bao qua anh Kiet)
- BE: AdjustPurchaseEvaluationBudgetCommandValidator GO rule ExpectedRemainingAmount.GreaterThanOrEqualTo(0) -> cho luu so am (mirror tien le LeaveBalance AllowsNegativeRemaining). GIU BudgetPeriodAmount>0 + submit-guard "da nhap NS ky nay" khong doi
- FE x2 app SHA256 identical: (a) allowNegative cho VndInlineEdit row 8; (b) banner amber "Vuot ngan sach - van luu & gui duyet duoc" trong PeBudgetSummaryTable khi cmpPeriod<0 || cmpFull<0. Tang to mau do cu GIU NGUYEN
- Spec change: flip test AdjustBudget_Validator_ExpectedRemainingNegative_FailsValidation -> _PassesValidation (am gio hop le); test BudgetPeriodZero_FailsValidation GIU (budget>0 van enforced)
- Build FE x2 PASS + test 263 PASS (45 Domain + 218 Infra, 0 fail/skip). Reviewer PASS 0 issue (row8 am an toan arithmetic additive-only, submit guard nguyen, mirror byte-identical, no scope creep)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Mig 50 ReplaceBudgetModuleWithPeWorkItemBudgets: bang moi PeWorkItemBudgets (1 record/cap Du an x Hang muc, UNIQUE filtered [IsDeleted]=0) + drop 5 bang Budget cu + PE/Contracts drop BudgetId + backfill BudgetManualAmount->BudgetPeriodAmount TRUOC DropColumn (phieu UAT giu so) + DELETE menu/permission Bg_* IN-list children-first
- BE: PUT {id}/budget/pro (role Procurement) + {id}/budget/ccm (role CostControl, Adjustment cho phep AM) fail-closed Forbidden-truoc-side-effect + EnsureTrackedAsync race-safe (catch unique -> re-fetch winner, loi khac rethrow) + auto-create record khi tao phieu + budgetSummary DTO (luy ke trinh-truoc/chon-thau-truoc/de-xuat-ky-nay + full fallback du-tru-PRO + canEdit flags) + submit-guard (3) doi predicate BudgetPeriodAmount -> "chua nhap Ngan sach ky nay" + PATCH budget-adjust absolute-set 2 field moi + Contract GIU BudgetManual* (HD nhap tay khong doi) + ke thua HD map BudgetPeriodAmount
- FE x2 app SHA256 identical: bang "TONG HOP NGAN SACH TRINH KY" block A (full dam + ban hanh + V0 hieu chinh + du tru PRO + ghi chu, editable theo canEditPro/canEditCcm) + block B 9 dong cong thuc Excel (5=1+3, 6=2+4, 7=full-5, 8 tu nhap default 7, 9=4+8) + to mau vuot ngan sach #C00000 / am do / red-soft row8>row7 + "Chua chon" khi count=0 + banner phieu chua gan Hang muc + o "Ngan sach ky nay" o create/header + XOA pages/components/types budgets + routes + menuKeys + Layout staticMap 4-place
- Tests: +22 PeWorkItemBudgetTests (auto-create x3, ensure/race x2, authz matrix PRO x5 + CCM x3, budgetSummary aggregates x5, adjust x4) - 14 BudgetPolicyTests xoa theo module - 1 test via-BudgetId -> 263 PASS (45 Domain + 218 Infra, 0 fail)
- database-agent advise adopted: khong FK vat ly PE/Contracts->Budgets (DropColumn khong can DropForeignKey) + DropIndex truoc DropColumn (SQL 5074) + IN-list thay LIKE Bg_% (underscore wildcard + miss root) + khong Serializable wrap (nested-tx conflict codegen)
- Reviewer PASS-with-minor 0 blocker (verdict-first survived); 2 minor da sua truoc commit (comment adjustMut absolute-set + dead key budgetId); note: F4 approver-edit-budget UI entry tam drafter-only, BE van cho approver scope - cho UAT anh Kiet
- Scaffold-bug caught: EF tu sinh RenameColumn BudgetManualAmount->ExpectedRemainingAmount (SAI semantics) -> thay bang Add+UPDATE+Drop
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Domain policy: xoa MOI transition -> TuChoi o ca 4 policy (NccOnly + NccWithPlan + ForV2Schema + FromDefinition) -> NextPhases het tra TuChoi, nut FE tu bien mat
- Service guard S60: chan targetPhase=TuChoi moi caller ke ca Admin (dung truoc moi branch — spec bo han, khong escape hatch); message huong dan dung Tra lai / Xoa nhap
- FE x2 app: filter phong thu next.filter(p != TuChoi) PeWorkflowPanel (SHA256 identical); dialog/isCancel giu dead-safe de flip lai de
- Enum TuChoi + phieu TuChoi cu + tab filter "Tu choi" GIU display (data cu render binh thuong)
- SlaExpiryJob chi dung Contract — PE khong auto-TuChoi, khong anh huong
- Tests spec-change cung commit: Domain flip BothPolicies_TuChoi_RemovedFromAllTransitions_S60 + NEW V2SchemaPolicy fact; Infra NEW TargetTuChoi_WithRejectDecision_Throws_TuChoiRemoved_S60 (guard #45 test cu giu nguyen PASS — van dung truoc)
- Test 254 -> 256 PASS (59 Domain + 197 Infra)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Rename muc 3: "Chon NCC / TP thang thau" -> "Don vi NCC/TP duoc chon" (anh Kiet chot chu) x2 app + wording phu nhat quan
- Guard gui duyet du CA 4 (anh chot): don vi duoc chon + gia chao thau >0 + ngan sach (Budget link HOAC nhap tay) + bang so sanh dinh kem
+ BE ConflictException gop moi muc thieu 1 lan, ap ca Admin (TransitionAsync submit branch)
+ FE pre-check missingForApproval cung predicate -> disable nut + tooltip liet ke du (computeGiaChaoThau extract single-source)
- Bypass drafter-in-chain (luat GENERIC theo cap, anh chot): V2-only, BUOC DAU only - nguoi soan la approver cap k -> auto qua Cap 1..k khi gui
+ Audit 3 tang: Approval row AutoApprove per cap + LevelOpinion CHI slot chinh chu (khong gan chu ky NV bi skip) + Changelog
+ Pointer: k<max -> Cap k+1; het buoc -> Buoc 2 Cap 1; workflow 1 buoc -> terminal DaDuyet
+ TraLai resubmit ap lai idempotent (opinion UPSERT)
- Tests: +14 PeSubmitGuardAndBypassTests (240 -> 254 PASS)
- Reviewer die mid-run (gotcha #53 class) -> em main self-gate evidence-checklist PASS 0 blocker
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 1 phieu = 1 hang muc chon tu header (S57bis/S58, hang muc dau auto-seed khi tao
phieu) -> nut them hang muc thu 2+ sai mo hinh nghiep vu, go khoi ItemsTab header.
- AddItemDialog giu (dead code) de flip lai de neu doi y.
- SHA256 mirror x2 app IDENTICAL, build x2 PASS.
- PeDetailTabs Section 5 Dieu chinh ngan sach: bo input "Ten (khong bat buoc)"
(user khong hieu "y nghia du phong la gi") - manual budget chi con So tien (VND).
State manualName drop, payload budgetManualName: null. Ten cu phieu truoc van
hien read-only, ve null khi Luu dieu chinh lan toi.
- PeHeaderForm: payload budgetManualName null + hasManual detect theo CA amount
(phieu moi name=null sau khi bo o Ten -> van nhan dung manual mode).
- PeWorkspaceCreateView: khong doi (chua tung co o Ten, payload '' || null = null san).
- SHA256 mirror x2 app IDENTICAL, build tsc+vite x2 PASS.
- PeWorkflowPanel x2: nguoi duyet == nguoi soan (drafterUserId == currentUser.id)
-> an ca "Tra lai" + "Tu choi" (anh chot: tra cho chinh minh vo nghia, huy phieu
= nho cap khac tu choi / xoa phieu Nhap).
- SuppliersController: POST tao NCC mo cho moi user dang nhap (anh chot - nghiep vu
di thau phat sinh NTP moi lien tuc); PUT/DELETE van khoa Admin+CatalogManager (S57).
- PeDetailTabs AddSupplierDialog x2: Select -> SearchableSelect (go-tim bo dau,
sort A-Z theo ma) + nut "+ NCC moi" quick-create (Ma/Ten/Loai/SDT/Email) ->
POST /suppliers -> auto-select vao phieu.
- Upload file bao gia + bang so sanh x2: input multiple + upload tuan tu tung file
(UAT "moi lan chi chon duoc 1 file").
- SHA256 mirror x2 app, build tsc+vite x2 PASS, BE 0 err, test 240/240 PASS local.
- NEW ui/SearchableSelect: combobox tu render, go loc theo label, match BO DAU
tieng Viet (go "be tong" trung "Be tong"), keyboard arrows/Enter/Esc, clear (x),
style mirror ui/Input density S55. Khong them lib ngoai.
- PeWorkspaceCreateView + PeHeaderForm: Hang muc + Du an doi Select -> SearchableSelect
(UAT: "nen co loc de tu danh chu" / "nen co tu go chu" - 70+ muc kho do).
- Auto dia diem (UAT "dia chi nen tu auto"): chon Du an tu dien diaDiem tu
Project.Location (S55), chi ghi de khi user chua go tay (track lastAutoLoc ref).
- Dieu khoan thanh toan nhap tay: Input 1 dong -> Textarea 3 dong (UAT "khong cho
xuong dong?") o CreateView + PeDetailTabs inline-edit; render detail da pre-wrap san.
- SHA256 mirror x2 app (4 file IDENTICAL), build tsc+vite x2 PASS.