[CLAUDE] Master: nạp master data thật từ Excel (62 dự án + 71 hạng mục + 3 NCC) + Project +4 cột (Mig 48)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m33s

Nạp master data công ty từ file Excel 'HẠNG MỤC CÔNG VIỆC DỰ ÁN':
- 62 Projects (Mã + Năm; tên/CĐT/địa điểm/gói thầu cho ~6 dự án có chi tiết)
- 71 WorkItems: Vật tư 16 · Thầu phụ 30 · MEP 9 · Thiết bị 16
- 3 Suppliers (TRUONGGIANG/TANPHU/TGN)

Mig 48 AddProjectMasterFields: Project +4 cột nullable (Year/Investor/Location/Package) + ProjectFeatures DTO/Create/Update + ProjectsPage form ×2 app (SHA256 mirror).
SeedRealMasterDataAsync per-code idempotent, UNGATED → reaches prod (coexist demo). FLOCK01 collision → skip (demo wins).

Verify: build 0-err · test 216 PASS · runtime Dev proof (data landed, Investor col populates). Provenance: scripts/master-import-data.generated.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-09 09:27:04 +07:00
parent f8640d6f18
commit 69cb3937bb
17 changed files with 7069 additions and 9 deletions

View File

@ -23,9 +23,13 @@ type FormState = {
endDate: string
budgetTotal: string
note: string
year: string
investor: string
location: string
package: string
}
const emptyForm: FormState = { code: '', name: '', startDate: '', endDate: '', budgetTotal: '', note: '' }
const emptyForm: FormState = { code: '', name: '', startDate: '', endDate: '', budgetTotal: '', note: '', year: '', investor: '', location: '', package: '' }
const fmtMoney = (v: number | null) => (v == null ? '—' : v.toLocaleString('vi-VN'))
const fmtDate = (s: string | null) => (s ? new Date(s).toLocaleDateString('vi-VN') : '—')
@ -61,6 +65,10 @@ export function ProjectsPage() {
managerUserId: null,
budgetTotal: d.budgetTotal ? Number(d.budgetTotal) : null,
note: d.note || null,
year: d.year ? Number(d.year) : null,
investor: d.investor || null,
location: d.location || null,
package: d.package || null,
}
if (d.id) await api.put(`/projects/${d.id}`, payload)
else await api.post('/projects', payload)
@ -92,6 +100,10 @@ export function ProjectsPage() {
endDate: p.endDate ? p.endDate.slice(0, 10) : '',
budgetTotal: p.budgetTotal?.toString() ?? '',
note: p.note ?? '',
year: p.year?.toString() ?? '',
investor: p.investor ?? '',
location: p.location ?? '',
package: p.package ?? '',
})
setOpen(true)
}
@ -99,6 +111,7 @@ export function ProjectsPage() {
const columns: Column<Project>[] = [
{ key: 'code', header: 'Mã DA', sortable: true, render: p => <span className="font-mono text-xs">{p.code}</span>, width: 'w-32' },
{ key: 'name', header: 'Tên dự án', sortable: true, render: p => p.name },
{ key: 'investor', header: 'Chủ đầu tư', render: p => p.investor ?? '—' },
{ key: 'startDate', header: 'Bắt đầu', render: p => fmtDate(p.startDate), width: 'w-32' },
{ key: 'endDate', header: 'Kết thúc', render: p => fmtDate(p.endDate), width: 'w-32' },
{ key: 'budgetTotal', header: 'Ngân sách', align: 'right', render: p => fmtMoney(p.budgetTotal) },
@ -203,6 +216,22 @@ export function ProjectsPage() {
<Label>Ngày kết thúc</Label>
<Input type="date" value={form.endDate} onChange={e => setForm({ ...form, endDate: e.target.value })} />
</div>
<div className="space-y-1.5">
<Label>Năm</Label>
<Input type="number" value={form.year} onChange={e => setForm({ ...form, year: e.target.value })} />
</div>
<div className="space-y-1.5">
<Label>Chủ đu </Label>
<Input value={form.investor} onChange={e => setForm({ ...form, investor: e.target.value })} />
</div>
<div className="col-span-2 space-y-1.5">
<Label>Đa điểm</Label>
<Input value={form.location} onChange={e => setForm({ ...form, location: e.target.value })} />
</div>
<div className="col-span-2 space-y-1.5">
<Label>Gói thầu</Label>
<Input value={form.package} onChange={e => setForm({ ...form, package: e.target.value })} />
</div>
<div className="col-span-2 space-y-1.5">
<Label>Ghi chú</Label>
<Textarea rows={3} value={form.note} onChange={e => setForm({ ...form, note: e.target.value })} />

View File

@ -52,6 +52,10 @@ export type Project = {
managerUserId: string | null
budgetTotal: number | null
note: string | null
year: number | null
investor: string | null
location: string | null
package: string | null
createdAt: string
updatedAt: string | null
}