4.0 KiB
IMPLFE-K7: IN-PROGRESS
Lane FE K7 — bridge KHKK→HĐ (vá-1 FE · vá-16 · vá-4b) — S167 2026-08-01
§0 ĐO TRƯỚC KHI GÕ (đĩa, không đoán)
git status TRƯỚC-Write (git status --short): 8 file dirty + 1 untracked, TẤT CẢ thuộc .claude/* + docs/STATUS.md (của lead) — src/Backend, fe-admin, fe-user SẠCH 0 dòng (git status --short -- src/Backend fe-admin fe-user → rỗng). HEAD = 1c6d77a [CLAUDE] FE-Admin: K6 ….
Đo hiện trạng nút bridge trên màn KHKK (2 app):
grep -rn -i -E "vào HĐ|create-contract|bridge|contractId" fe-user/src/pages/khkk fe-admin/src/pages/khkk
→ 0 HIT ⇒ CHƯA CÓ nút bridge nào (W6-S161 KHÔNG dựng phần này)
Tiền lệ DUY NHẤT đang sống = bridge PE: POST /purchase-evaluations/{id}/create-contract
(PurchaseEvaluationsController.cs:339-343, body CreateContractFromEvaluationBody:379), FE gọi ở
components/pe/PeDetailTabs.tsx:2186.
Baseline SHA256 (trước sửa) — 3 cặp mirror ĐỀU identical:
| file | SHA256 (cả 2 app) |
|---|---|
src/hooks/usePipelineStages.ts |
edff9931…94a19ac |
src/types/khkk.ts |
7a99b865…6f22b6 |
src/pages/khkk/KhkkDetailPage.tsx |
1863153b…95f16be |
Chữ ký hook quyền THẬT (src/hooks/usePermission.ts:14-26, 2 app identical):
usePermission() trả { can(menuKey, action: CrudAction = 'Read') } — KHÔNG phải
usePermission('X','Y') như đề bài viết. Dùng const { can } = usePermission() rồi
can('KeHoachKyKet','Read') && can('Contracts','Create').
§1 [vá-4b] Cây GĐ3/GĐ4 nối qua TẬP — usePipelineStages.ts (fe-user XONG, npx tsc -b EXIT 0)
Trạng thái đo được TRƯỚC: K5 (S166) đã đổi HÌNH DẠNG sẵn (Set contractIdsOfPackage + ghi chú
"chỗ cắm nguồn thứ hai") nhưng chỉ có 1 nguồn pe.contractId. Lượt này CẮM nguồn 2.
types/khkk.ts: +KhkkListItemDto.lineContractIds?: string[] | null(OPTIONAL — xem KHỚP-DTO) +khkkPlanContractIds(plan)gom 2 nguồn (lineContractIds∪lines[].contractId) — 1 hàm duy nhất để BE đổi tên thì sửa 1 chỗ, không vá rải.usePipelineStages.ts:contractIdsOfPackage=pe.contractId(legacy) ∪khkkPlanContractIds(k)cho mọi phiếu KHKK của gói, dedupe bằngSet(2 nguồn CỐ Ý chồng nhau ở HĐ đầu).fallbackNametra CẢ 2 nguồn (HĐ đến từ KHKK thìpeItemskhông trỏ tới nó → trước đây rơi vềnull).- Sai-thầm-lặng → thấy được: BE chưa trả field ⇒ nguồn 2 im, mà "im vì chưa nối" trông y hệt "im vì
gói chưa có HĐ".
console.warnDEV-only 1 lần/phiên (cờ modulewarnedMissingLineContractIds) khi có phiếuDaDuyetmà mọi phiếulineContractIds == null. BE trả[](gói chưa có HĐ) thì IM — phân biệt được vắng-field ⟂ rỗng-thật.
🔴 KHỚP-DTO (lead đối chiếu khi lane BE trả)
| Vế | Đo được trên đĩa lúc 2026-08-01 | FE làm gì |
|---|---|---|
KhkkLineDto.contractId |
✅ ĐÃ CÓ 2 phía: FE types/khkk.ts:201 · BE ContractSigningPlanLineDto:74 Guid? ContractId |
không phải thêm gì |
| Line-contract-id trên LIST payload | ❌ KHÔNG CÓ: ContractSigningPlanListItemDto:34-64 (17 field) không mang contract-id nào; KhkkListItemDto cũng không có lines[] |
FE thêm lineContractIds?: string[] (optional) |
| Endpoint bridge | ❌ chưa tồn tại lúc đo (0 hit grep create-contract phía KHKK) |
FE gọi POST /contract-signing-plans/{id}/create-contract theo sub-invest-fable-b2-cum3.md §K7.1:23,54 |
⚠️ Tên lineContractIds là FE chọn (BE-lane K7 sở hữu tên thật). Nếu BE đặt khác ⇒ sửa đúng 1 hàm
khkkPlanContractIds() trong types/khkk.ts ×2 app. Nếu BE không expose trên list ⇒ cây vẫn chạy
bằng nguồn legacy + có chuông DEV (không vỡ, không im).
END implfe-k7 — VERDICT=IN-PROGRESS