Match form chính thức 4 section đánh số:
1. Thông tin gói thầu — chỉ a. Tên gói thầu + b. Dự án (Địa điểm + Mô tả compact bên dưới nếu có).
2. Chọn NCC / TP — đúng a/b/c/d:
a. NCC/TP được chọn — selectedSupplierName badge xanh
b. Ngân sách — link Budget với mã + tên + tổng
c. Giá chào thầu — tự compute = sum quotes của winner supplier (filter quotes.purchaseEvaluationSupplierId === winnerRowId)
d. Bản so sánh — embed GeneralAttachmentsSection (attachments không gắn supplier-row, purpose=ComparisonTable)
+ ĐKTT + HĐ kế thừa link bonus
+ Banner emerald 'Tạo HĐ từ phiếu' khi DaDuyet + chưa có Contract
3. NCC/TP tham gia — section riêng giữ table 5 cột (NCC/Liên hệ/ĐKTT/File/Action — nhiều info hơn spec table 3 cột, useful cho UX web).
4. Hạng mục + Báo giá — matrix với cột 'NS link · Δ' + footer aggregate (giữ nguyên).
Side change:
- FormRow helper mới (label 176px + value flex) thay cho dl grid 2-col cũ — match style form giấy
- Drop Field helper cũ (now unused)
- InfoTab signature đổi: bỏ readOnly param (chỉ display, action move sang ChonNccSection)
TS build pass cả 2 app. Mirror fe-user identical.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PART A: Section 'Bang so sanh' (file tong ho so so sanh)
User request: 'theo them cho thong tin ve Bang so sanh, cho dinh kem
file so sanh tong len'.
BE:
- PurchaseEvaluationAttachmentPurpose.ComparisonTable = 4 (new enum value)
Backend validator IsInEnum pass, khong can migration (int column).
FE types (2 app):
- PeAttachmentPurpose.ComparisonTable + Label '4: Bang so sanh'.
FE PeDetailTabs:
- Them section thu 4 'Bang so sanh (file tong)' sau 'Hang muc + Bao gia'.
- Component GeneralAttachmentsSection: upload KHONG truyen supplierRowId
(BE luu NULL) → purpose=ComparisonTable default. Filter attachments
co supplierRowId===null de render.
- Card layout khac SupplierAttachmentsCell: full-width card + brand color
+ purpose chip + date. Upload button to hon ([+ Tai len bang so sanh]).
- readOnly hide upload + delete, giu download.
PART B: Demo email rebrand @solutionerp.local → @solutions.com.vn
User request: 'tao nguoi dung demo theo email cua ben nay'.
BE DbInitializer:
- Rename 18 email in source: AdminEmail const + 17 demo users
(bod/pm/ccm/pro/fin/act/equ/hra/qs/nv) — keep password + role unchanged.
- Them BackfillUserEmailDomainAsync (idempotent): scan user co email
@solutionerp.local, rename sang @solutions.com.vn, update Email +
NormalizedEmail + UserName + NormalizedUserName. Skip neu co conflict
user da ton tai voi email moi. Chay truoc SeedAdmin de tranh tao
duplicate admin.
Admin permission tao user da co san qua /system/users page.
Comment input khi duyet da co san o PeWorkflowPanel (Ghi chu tuy chon
Textarea) + ContractDetailContent (Yeu cau sua / Duyet tiep dialog).
User request: 'cho tat ca cai nay the hien tren dung 1 man hinh nhe, cai
duyet va lich su thi dua sang panel 3'.
Panel 2 (PeDetailTabs): truoc 5 tab (Info/NCC/Items/Approvals/History).
Sau bo tabs, flat render 3 section stack doc voi divider + title uppercase:
Thong tin → NCC tham gia (N) → Hang muc + Bao gia (N)
Panel 3 (PeWorkflowPanel): truoc chi workflow timeline + transition btn.
Sau them 2 section ben duoi:
Workflow timeline → Lich su duyet (PeApprovalsSection) → Lich su thay doi
(PeHistorySection)
Export PeApprovalsSection + PeHistorySection tu PeDetailTabs — reuse
ApprovalsTab + HistoryTab logic cu, wrap them <h3> section title.
Dong bo ca fe-admin + fe-user (copy identical file).
BE:
- CreateContractFromEvaluationCommand: guard DaDuyet + SelectedSupplier
+ ContractId=null → tạo Contract draft mới với SupplierId/ProjectId/
DepartmentId kế thừa từ PE. GiaTri = sum(details.thanhTienNganSach).
DraftData = PE.PaymentTerms. Gen MaHopDong ngay + pin WorkflowDefinitionId
theo ContractType user chọn. Log Changelog cả 2 bảng (Contract +
PurchaseEvaluation), link 2 chiều PE.ContractId = contract.Id.
- ListApprovedPurchaseEvaluationsQuery: DaDuyet + ContractId=null cho
FE picker.
- 2 endpoint mới:
GET /api/purchase-evaluations/approved-pending-contract
POST /api/purchase-evaluations/{id}/create-contract
FE:
- PeDetailTabs InfoTab: nếu Phase=DaDuyet && !ContractId && SelectedSupplierId
→ banner emerald + button "Tạo HĐ từ phiếu" → CreateContractDialog
(pick ContractType dropdown 7 loại + TenHopDong + bypass CCM flag)
- Sau khi tạo → navigate /contracts/{newId}
- Mirror fe-user.
KHÔNG auto-map PE Details → Contract Details per-type (PE schema ≠ 7
ContractType details schemas — user điền lại sau). PE → Contract link
qua FK ContractId cho navigation + history.