[CLAUDE] Contract: W2 BE-DTO nền GĐ3 — ContractSourceDto reverse-join KHKK + CurrentWorkflowStepIndex + WorkflowSteps cây thô khuôn KHKK; types ×2 app khớp tên JSON BE (vá reviewer F-1/F-2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-08-10 18:20:41 +07:00
parent 7bad4ae186
commit 01a7c0b855
4 changed files with 285 additions and 2 deletions

View File

@ -174,6 +174,67 @@ export type ContractDetail = {
approvalWorkflowId: string | null
currentApprovalLevelOrder: number | null
levelOpinions: ContractLevelOpinion[] | null
// ========= [W2 S187 · YC-023 GĐ3] Nguồn gốc KHKK + cây quy trình V2 (3 field) ==========
// 🔴 Khai `?` KÈM `| null` CÓ CHỦ ĐÍCH — 2 nghĩa KHÁC NHAU, đừng gộp:
// • `undefined` (vắng key) = payload đến từ API/bundle CHƯA có W2, hoặc cache TanStack cũ;
// • `null` = BE đã trả lời "HĐ này KHÔNG có nguồn KHKK / chưa pin quy trình".
// BE append 3 field này ở CUỐI `ContractDetailDto` với default null (hôm nay field cuối là
// `LevelOpinions` — `ContractDtos.cs:64`) ⇒ wire cũ không vỡ. Nơi đọc PHẢI null-check,
// TUYỆT ĐỐI không suy "vắng field ⇒ HĐ tạo tay".
/** HĐ kế thừa từ phiếu KHKK đã duyệt (bridge K7). HĐ tạo tay ⇒ null, FE không render card. */
source?: ContractSource | null
/** INDEX 0-based vào mảng `workflowSteps` (KHÔNG phải `order`) — mirror khuôn KHKK. */
currentWorkflowStepIndex?: number | null
/** Cây quy trình THÔ (xem `ContractWorkflowStep`). */
workflowSteps?: ContractWorkflowStep[] | null
}
// [W2 S187 · YC-023] Khối "Nguồn gốc KHKK" — BE reverse-join `ContractSigningPlanLines
// WHERE ContractId = id` → phiếu KHKK + hạng mục + Σ tiền (spec `§2 W2(a)`). Link nằm ở
// `ContractSigningPlanLine.ContractId`, KHÔNG có con-trỏ ngược trên `Contract` ⇒ HĐ 0 dòng
// nối trả null.
// ✅ FLAG-A ĐÓNG @S188 (reviewer F-1): BE đặt `Source` (`ContractDtos.cs:87`) đúng AC spec ⇒ FE
// rename khớp JSON BE từng tên: `contractSource`→`source` · `tenHangMuc`→`tenHangMucs` ·
// `totalApprovedAmount`→`approvedAmountTotal` (JSON bind theo TÊN; System.Text.Json camelCase).
export type ContractSource = {
/** Mã phiếu KHKK, vd `KHKK/2026/001`. null khi phiếu cha đã xoá mềm (F-2 — BE trả null qua global filter). */
maKeHoach: string | null
planId: string
/** Nhóm duyệt N1N8 của phiếu (Mig 71). null = phiếu không mang nhóm. */
approvalGroup?: number | null
/** Tên các hạng mục của phiếu đã nối sang HĐ này (có thể rỗng). */
tenHangMucs: string[]
/** Σ `ApprovedAmount` các dòng nối — số đã đóng băng tại choke-point finalize của phiếu. */
approvedAmountTotal?: number | null
/** Phiếu Duyệt NCC gốc — chuỗi PE → KHKK → HĐ. */
purchaseEvaluationId?: string | null
}
// [W2 S187] Cây quy trình THÔ do BE trả — mirror khuôn KHKK (`types/khkk.ts:275-296`, BE
// `ContractSigningPlanFeatures.cs:131-152`).
// 🔴 KHÁC PE: BE **KHÔNG** precompute `status` Done/Current/Pending. FE tự suy từ CẶP con-trỏ
// `currentWorkflowStepIndex` (INDEX 0-based vào mảng steps) + `currentApprovalLevelOrder`
// (GIÁ TRỊ `level.order`, KHÔNG phải index).
export type ContractWorkflowLevel = {
id: string
order: number
name: string | null
approverUserId: string
approverFullName: string | null
/** Cờ per-Cấp "được KẾT THÚC quy trình tại cấp này" — spec `§2 W2(b)` gọi là "cờ per-level". */
allowApproverFinalize: boolean
}
export type ContractWorkflowStep = {
id: string
order: number
name: string
levels: ContractWorkflowLevel[]
// 2 field dưới có trong khuôn KHKK nhưng spec W2 KHÔNG nêu tên ⇒ khai `?` để nơi đọc buộc
// null-check, thay vì hứa một field payload có thể không mang (bài học `khkk.ts:403-407`).
departmentId?: string | null
departmentName?: string | null
}
// [Plan B S29 2026-05-22 Chunk E3] Mirror BE ContractLevelOpinionDto 12 fields.