# Session 2026-04-23 ~23:00 — Module Duyệt NCC (tiền-HĐ) E2E **Focus:** Build module mới "Quy trình chọn Thầu phụ - NCC" từ user spec (Excel form trình duyệt so sánh giá + 2 flowchart A/B). Đây là đầu vào của HĐ — phiếu duyệt xong kế thừa làm HĐ cho NCC đó. 4 commit (`2c6f0ca` → `a385d70`), 1 migration (12), ~2500 LOC BE + FE. ## User input **2 file từ user:** 1. **Excel form** "BẢNG TỔNG HỢP TRÌNH DUYỆT SO SÁNH GIÁ" — dự án SOVI, gói thầu Cung cấp bê tông, so sánh 4 NCC × hạng mục (nhóm A.I Bê tông, A.II Phụ gia, A.III Bơm, A.IV Vận chuyển) + ý kiến 4 phòng ban + D Điều kiện TT + E Thông tin liên hệ 2. **Flowchart** 2 quy trình: - A "Duyệt NCC" (3 step): Purchasing → CCM → CEO - B "Duyệt NCC - Phương án" (5 step): Purchasing → Dự án → CCM → CEO (duyệt PA) → CEO (duyệt NCC) **User confirm:** - Menu: Quy trình chọn Thầu phụ - NCC → Duyệt NCC / Duyệt NCC Phương Án, mỗi cái 3 sub (Danh sách / Thao tác / Duyệt) - Kế thừa HĐ: user click "Tạo HĐ" → list phiếu đã duyệt → chọn → kế thừa - Mã phiếu: tính sau (auto gen PE-YYYYMM-XXXX tạm) - Tách Quotes ra bảng riêng (row-based) - "7 bảng core" (thực tế 7 + 3 workflow config tách riêng vì Phase enum khác) - "Config quy trình y như HĐ" (admin tự config version mới) ## Design **10 bảng mới (migration 12 `AddPurchaseEvaluations`):** Core 7: 1. `PurchaseEvaluations` — Header (Type enum A/B, Phase 7 state, WorkflowDefinitionId pinned, SelectedSupplierId, PaymentTerms JSON, ContractId? FK kế thừa) 2. `PurchaseEvaluationSuppliers` — N:M NCC tham gia + contact + payment term per NCC 3. `PurchaseEvaluationDetails` — hạng mục so sánh + ngân sách (GroupCode A.I/II/III/IV) 4. `PurchaseEvaluationQuotes` — báo giá per NCC per Detail + IsSelected flag (matrix cell) 5. `PurchaseEvaluationApprovals` — workflow history 6. `PurchaseEvaluationChangelogs` — audit log unified 7. `PurchaseEvaluationAttachments` — file upload (báo giá + spec + phiếu export) Workflow config 3: 8. `PurchaseEvaluationWorkflowDefinitions` — versioned per Type (A/B), UK(Code, Version) 9. `PurchaseEvaluationWorkflowSteps` — Order + Phase + Name + SlaDays 10. `PurchaseEvaluationWorkflowStepApprovers` — Kind (Role/User) + AssignmentValue **Phase enum (PurchaseEvaluationPhase, 7 state + TuChoi):** - 1 DangSoanThao / 2 ChoPurchasing / 3 ChoDuAn (chỉ B) / 4 ChoCCM - 5 ChoCEODuyetPA (chỉ B) / 6 ChoCEODuyetNCC / 7 DaDuyet / 99 TuChoi **Policy default (hardcoded fallback khi admin chưa author DB):** - A NccOnly: DangSoanThao → ChoPurchasing (PRO) → ChoCCM (CCM) → ChoCEODuyetNCC (BOD) → DaDuyet - B NccWithPlan: DangSoanThao → ChoPurchasing (PRO) → ChoDuAn (PM) → ChoCCM (CCM) → ChoCEODuyetPA (BOD) → ChoCEODuyetNCC (BOD) → DaDuyet - SLA default: soạn 3d, step 2d, CEO 1d - Reject path mọi phase → DangSoanThao **Kế thừa HĐ flow:** - Phiếu DaDuyet + SelectedSupplierId + !ContractId → banner emerald FE - Click "Tạo HĐ từ phiếu" → dialog pick ContractType 7 loại + TenHopDong + bypass flag - POST `/api/purchase-evaluations/{id}/create-contract` - BE: verify → clone Supplier/Project/DepartmentId/GiaTri(sum details) → gen MaHopDong ngay → pin ContractWorkflowDefinition[Type] → log Changelog cả 2 bảng → link 2 chiều PE.ContractId = contract.Id - Navigate `/contracts/{newId}` ## Commits ### 1. `2c6f0ca` — Domain+Infra (migration 12) - 10 entity files ở `Domain/PurchaseEvaluations/` - 1 EF config file (10 configuration class) - Policy + Registry + FromDefinition mirror HĐ - MenuKeys +Pe_* + PeWorkflows constants - DbInitializer seed 13 menu + 2 WorkflowDefinition v01 ### 2. `(commit 2)` — App+Api CQRS - `IPurchaseEvaluationWorkflowService` + `PurchaseEvaluationWorkflowService` impl - 4 Features file (~900 LOC): - `PurchaseEvaluationFeatures.cs` — Create/Update/Transition/List/Inbox/Get/Delete/Changelog - `PurchaseEvaluationSupplierFeatures.cs` — Add/Update/Remove supplier - `PurchaseEvaluationDetailFeatures.cs` — Add/Update/Delete hạng mục + Upsert/Delete Quote + SelectWinner - `PurchaseEvaluationDtos.cs` — DTO records cho GetBundle - `PurchaseEvaluationsController.cs` — 15 endpoint REST - DI register ### 3. `(commit 3)` — FE 2 app - `types/purchaseEvaluation.ts` — PEType/Phase enum + DTOs (copy-share) - `pages/pe/PurchaseEvaluationsListPage.tsx` — 3-panel: list | detail tabs | workflow - `pages/pe/PurchaseEvaluationCreatePage.tsx` — form create/edit header - `components/pe/PeDetailTabs.tsx` — 5 tab + 4 dialog (AddSupplier/EditSupplier/DetailDialog/QuoteDialog) + matrix clickable - `components/pe/PeWorkflowPanel.tsx` — timeline + nextPhase buttons - Menu resolver Layout.tsx: `Pe__` + `PeWf_` (admin only) - App.tsx 3 route mới - MenuKeys.ts +PurchaseEvaluations + PeWorkflows - fe-user mirror (cùng pages, no admin hidden items) ### 4. `a385d70` — Kế thừa HĐ (Phase 4) - `CreateContractFromEvaluationFeatures.cs` — Command + Query (list approved pending) - 2 endpoint: `GET /approved-pending-contract` + `POST /{id}/create-contract` - PeDetailTabs InfoTab: banner emerald + `CreateContractDialog` pick ContractType ## Build results - Backend: 0 error, 2 pre-existing warning (DocxRenderer) — build pass - fe-admin + fe-user: `tsc --noEmit` 0 error ## Skip MVP (tương lai) - [ ] PE Workflow admin designer UI `/system/pe-workflows/:typeCode` (framework đã có, mirror `/system/workflows/:typeCode`) - [ ] PE Attachments upload endpoint + FE drag-drop (pattern reuse ContractAttachment) - [ ] Auto-map PE Details → Contract Details per-type khi gen HĐ (phức tạp vì 7 ContractType schema khác nhau) - [ ] Demo data PE (1-2 phiếu sample cho UAT) ## Stats | | Trước session | Sau session | Δ | |---|---|---|---| | BE LOC | ~8800 | ~11100 | +2300 | | DB tables | 36 | 46 | +10 | | Migrations | 11 | 12 | +1 | | API endpoints | ~93 | ~110 | +17 | | FE pages | ~23 | ~26 | +3 (× 2 app) | | Commits session | — | 4 | `2c6f0ca` → `a385d70` | ## Notes 1. **Workflow config tách bảng riêng** thay vì share WorkflowDefinition với HĐ — vì Phase enum khác (PurchaseEvaluationPhase vs ContractPhase). Code duplication ~250 dòng (FromDefinition builder) nhưng design clean. 2. **Quote Dialog matrix UX** — click cell → popup nhập giá + IsSelected per hạng mục (cho phép mỗi hạng mục NCC khác). `SelectWinner` riêng set winner tổng thể (trường hợp 1 NCC thắng toàn bộ). 3. **Kế thừa HĐ non-copy details** — PE detail schema flat (GroupCode/NoiDung/ KhoiLuong/DonGia...) khác 7 ContractType details schemas — user điền lại manual. Link qua PE.ContractId cho reference. 4. **MaPhieu format PE-YYYYMM-XXXX** — tạm random. Có thể đổi format sau (vd theo dự án: `{ProjectCode}/PE/{seq}`) — user confirm format sau.