Files
solution-erp/.claude/workflows/runs/2026-07-12-S112-supplier-excel-import/sub-invest-codebase-A-mapping.md
2026-07-12 13:38:40 +07:00

7.3 KiB
Raw Blame History

sub-invest-codebase-A-mapping

HEADLINE: 30 cột Excel map GỌN vào 27 field Supplier: 1 ignore (STT) + 27 direct-field (cột 228, mỗi field dùng đúng 1 lần) + 2 cột audit-provenance (NGÀY/NGƯỜI CẬP NHẬT) KHÔNG có field khớp trực-tiếp → cần owner quyết. Seed 4 NCC (DbInitializer.cs:2775-2782) đã là precedent transform sống cho 27 mapping.

LANE A — COLUMN→FIELD MAPPING (verified vs source thật)

Nguồn verify: src/Backend/SolutionErp.Domain/Master/Supplier.cs:5-36 (27 field), SupplierType.cs:3-11, SupplierStatus.cs:3-8, precedent transform DbInitializer.cs:2775-2782 (seed 4 NCC thật đã map 30→27), audit AuditingInterceptor.cs:44-49 + BaseEntity.cs:6-9.

Bảng mapping đủ 30 dòng

# Excel col (r4) → target field kind transform / note
1 STT ignore Số dòng, không persist
2 GÓI THẦU PackageCategory direct-field Free-text. Seed vd "10-Nhôm kính+Face Mặt dựng"
3 PHÂN LOẠI (NTP/NCC/Cả hai) Type (SupplierType, non-null) enum-map Trim+ci: NCC→NhaCungCap(1) · NTP→NhaThauPhu(2) · Cả hai→CaHai(6). (Enum còn TĐ=3/ĐVDV=4/CĐT=5 nếu source có). Non-nullable → giá trị lạ phải reject-row hoặc default (owner)
4 TÊN VIẾT TẮT Code (required) direct-field = Mã NCC dùng trong mã HĐ. Trim+UPPER khuyến nghị (seed: TRUONGGIANG). Là khóa idempotent/dedup
5 TÊN CÔNG TY Name (required) direct-field Tên đầy đủ. KHÔNG tạo cột companyName mới — reuse Name gốc
6 ĐỊA CHỈ XUẤT HÓA ĐƠN Address direct-field = "địa chỉ xuất HĐ/đăng ký" (comment field khớp). Reuse cột gốc, KHÔNG tạo invoiceAddress
7 ĐỊA CHỈ VĂN PHÒNG OfficeAddress direct-field 4 NCC seed để trống → field vẫn là target đúng
8 SỐ ĐT CÔNG TY Phone direct-field Phone công-ty (phân biệt cột 21)
9 FAX Fax direct-field Chỉ TGN có (seed "0251.2814663")
10 SỐ TÀI KHOẢN+TÊN+CN.NH BankAccount direct-field · COMPOSITE Giữ RAW 1 ô (precedent: "100212127 Ngân hàng Eximbank - Chi Nhánh Hòa Bình"). Entity KHÔNG có AccountName/BankBranch → không tách
11 SỐ TK PHỤ SecondaryBankAccount direct-field 4 NCC seed để trống, field đúng target
12 MÃ SỐ THUẾ TaxCode direct-field Giữ raw kể cả có space ("0312 251 859"). Có thể null (DONGDUONG)
13 NGƯỜI ĐẠI DIỆN PHÁP LUẬT LegalRepresentative direct-field Giữ prefix "Ông/Bà" như seed
14 CHỨC VỤ ĐẠI DIỆN LegalRepTitle direct-field vd "GIÁM ĐỐC ĐIỀU HÀNH"
15 GIẤY ỦY QUYỀN AuthorizationNote direct-field Free-text dài (số GUQ+ngày+người ủy quyền)
16 Link GUQ LinkGuq direct-field · NAS path Giữ RAW backslash @"01. GPKD_HSNL_GUQ\02.Trường giang\...pdf" — KHÔNG normalize \/
17 Link GPKD LinkGpkd direct-field · NAS path như trên
18 Link HSNL LinkHsnl direct-field · NAS path như trên
19 NGƯỜI LH CHÍNH ContactPerson direct-field Người liên hệ chính (seed "Mr. Việt")
20 CHỨC VỤ NGƯỜI LH ContactTitle direct-field vd "Kinh doanh"
21 SĐT CHÍNH ContactPhone direct-field Phone người-LH (KHÁC cột 8 phone công-ty)
22 EMAIL Email direct-field
23 ĐỊA CHỈ GỬI THƯ MailingAddress direct-field Địa chỉ thứ-3 (khác cột 6 & 7)
24 NGƯỜI NHẬN THƯ/SĐT MailRecipient direct-field · COMPOSITE Giữ RAW "MS Thủy / 036 405 0016" (name+phone gộp). Entity không có field tách
25 NGUỒN GIỚI THIỆU ReferralSource direct-field vd "Tái sử dụng DA trước"
26 NGƯỜI PHỤ TRÁCH(PMH) OwnerPmh direct-field vd "Bình"
27 TÌNH TRẠNG HIỆN TẠI Status (SupplierStatus?, nullable) enum-map Strip emoji + trim: ✅ Đang hoạt động→DangHoatDong(1) · Blacklist/đen→Blacklist(2) · Ngừng hợp tác→NgungHopTac(3). Nullable → giá trị lạ = null OK
28 GHI CHÚ/LÝ DO BLACKLIST Note direct-field Target ĐÚNG cho Note. (Seed để Note=null vì đã un-cram legacy — import thì col 28 mới là Note thật; coherence: khi Status=Blacklist thì lý-do nằm ở đây)
29 NGÀY CẬP NHẬT CUỐI (audit) UpdatedAt? KHÔNG có field khớp ⚠️ Map UpdatedAt = futile: AuditingInterceptor.cs:48 GHI ĐÈ UpdatedAt=now mỗi save. → ignore / gộp-Note / đề-xuất-field-mới (xem openQuestions)
30 NGƯỜI CẬP NHẬT (audit) UpdatedBy? KHÔNG có field khớp ⚠️ UpdatedByGuid? (userId), Excel là tên người (text) → type mismatch + bị AuditingInterceptor.cs:49 ghi đè. Không direct-map được

Kiểm chứng độ-phủ (0 sót)

  • 27/27 field entity được map đúng 1 lần (9 core + 18 expansion) — cột 228 (27 cột).
  • Cột 1 STT = ignore.
  • Cột 2930 = audit-provenance, KHÔNG field khớp trực tiếp → quyết định owner.
  • Tổng: 1 ignore + 27 direct + 2 no-field = 30 ✓.

3 nhóm cần transform đặc-biệt (đã đánh dấu trong bảng)

  • COMPOSITE (2): cột 10 BankAccount + cột 24 MailRecipient → giữ RAW (precedent seed đã giữ raw, entity thiếu sub-field để tách).
  • ENUM-MAP (2): cột 3 Type (trim+ci, non-null → cần rule giá-trị-lạ) + cột 27 Status (strip emoji, nullable → lạ=null).
  • NAS path (3): cột 16/17/18 → giữ raw backslash, KHÔNG đổi \/.
  • Chung mọi cột: normalize \n/whitespace trong header r4 (multi-line) + trim cell; skip #REF! ở r2 (chỉ parse tên r4).

Lưu ý reuse-cột (tránh orphan)

Cột 5/6 map thẳng Name/Address gốc — KHÔNG tạo companyName/invoiceAddress mới (sẽ orphan cột seed live). 18 expansion field vốn purpose-built đúng cho Excel này (Mig 62), khớp 1-1 cột 2,7,9,10,11,13-18,20,21,23-27.

Open Questions

1. Cột 29-30 (NGÀY/NGƯỜI CẬP NHẬT) xử lý sao? — KHÔNG có field khớp (audit fields UpdatedAt/UpdatedBy bị AuditingInterceptor ghi đè + UpdatedBy là Guid≠tên). 3 lựa chọn: (a) ignore — audit tự stamp import-time (mất provenance nguồn); (b) gộp-Note — nối "Cập nhật cuối 01/07/2027 bởi Bình" vào Note (giữ provenance, không thêm schema); (c) đề-xuất-field-mới SourceUpdatedAt DateTime? + SourceUpdatedBy string? (+2 cột Mig 63, sạch nhất nhưng thêm migration).

2. PHÂN LOẠI (col 3, non-nullable Type) khi gặp giá-trị-lạ ngoài NTP/NCC/Cả hai → reject-row hay default về NhaCungCap? (Status nullable nên không vướng — lạ=null).

3. Composite cột 10 & 24 — xác nhận giữ RAW (theo precedent seed) hay owner muốn tách sub-field (cần thêm cột AccountName/BankBranch/RecipientPhone → Mig mới)?

4. Code (col 4) là khóa idempotent — import gặp Code đã tồn tại thì skip / fill-nulls / overwrite? (Ảnh hưởng Lane B robustness).