ADR-0002. Liên kết vendor chỉ qua VendorItem - không có vendorId trên principal
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-03-20 |
| Người quyết định | Phat Nguyen |
| Thay thế | - |
Bối cảnh
- Một
Material(hoặcProductVariant) có thể được nhiều vendor cung cấp với giá và UoM khác nhau. - Một vendor cung cấp nhiều item.
- Quan hệ thực tế là M:N với các thuộc tính không tầm thường (giá, UoM, hệ số quy đổi, isPreferred, snapshot lastInvoiced).
- Ý tưởng ban đầu: thêm cột
vendorIdvàoMaterial(vendor ưu tiên). Phương án này đã bị từ chối.
Quyết định
Liên kết vendor↔principal chỉ tồn tại trong bảng nối VendorItem. Material và ProductVariant không có cột vendorId. Để biểu diễn vendor ưu tiên cho một item, đặt VendorItem.isPreferred = true (lật trạng thái liền mạch qua setPreferredAtomic, partial unique theo (merchantId, itemType, itemId)).
Hệ quả
| Ưu điểm | Nhược điểm |
|---|---|
| Một nguồn sự thật duy nhất cho quan hệ vendor | Truy vấn "vendor ưu tiên cho material X" cần JOIN |
| Hỗ trợ tự nhiên quan hệ M:N: cùng một material từ 3 vendor với giá khác nhau | Cho phép trạng thái "material không có vendor ưu tiên" (không ràng buộc NOT NULL) |
Snapshot lastInvoiced thuộc phạm vi VendorItem (một lịch sử cho mỗi cặp vendor-item) | Cần helper lật trạng thái liền mạch (setPreferredAtomic) |
recordPurchase cập nhật một dòng, không phải một cột trên Material | Giao diện phải hiển thị bộ chọn vendor thay vì cố định cứng |
Phương án thay thế đã cân nhắc
| Phương án | Ưu điểm | Nhược điểm | Lý do từ chối |
|---|---|---|---|
Material.vendorId (đơn) | Đọc đơn giản, không cần JOIN | Không mô hình hóa được M:N; "vendor phụ" vẫn cần cấu trúc song song | Không khớp với thực tế thu mua |
Material.preferredVendorId + bảng VendorItem | Tra cứu nhanh | Hai nguồn sự thật, đồng bộ lệch là không tránh khỏi | Anti-pattern |
Vendor.itemIds[] jsonb | Đọc một dòng | Không có ràng buộc, không truy vấn được theo item | Tệ hơn cả không quyết định |
Tham chiếu
core/src/models/schemas/inventory/vendor-item/schema.tsinventory/src/services/vendor-item.service.ts-setPreferred,recordPurchase- Memory:
feedback_vendor_via_vendoritem_only.md