61 lines
4.0 KiB
Markdown
61 lines
4.0 KiB
Markdown
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ằng `Set` (2 nguồn CỐ Ý chồng nhau ở HĐ đầu).
|
||
`fallbackName` tra CẢ 2 nguồn (HĐ đến từ KHKK thì `peItems` khô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.warn` DEV-only **1 lần/phiên** (cờ module `warnedMissingLineContractIds`)
|
||
khi có phiếu `DaDuyet` mà **mọi** phiếu `lineContractIds == 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
|