Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-k7.md
2026-08-01 12:11:32 +07:00

4.0 KiB
Raw Blame History

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 DaDuyetmọ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