Inventory Tracking
1. Tổng quan
| Thuộc tính | Giá trị |
|---|---|
| ID | FEAT-INV-TRACK |
| Status | Stable |
| Owner | inventory-team |
| Phụ thuộc | InventoryStock (mọi row đều tham chiếu một cái), DiscriminationType (validate type / referenceType / reason) |
InventoryTracking là audit trail duy nhất cho mọi thay đổi stock trong hệ thống. Mọi mutation adjustStock BẮT BUỘC ghi một row tracking. Bảng này cũng đóng vai trò sổ cái idempotency cho Kafka worker — xem ADR-0004.
2. Mô hình Entity
Trường InventoryTracking
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
inventoryStockId | text | ✓ | FK tới bucket được thay đổi |
merchantId | text | ✓ | Denormalize từ stock chain |
referenceType | text | ✓ | Một trong §4; typed<TInventoryTrackingReferenceType> |
referenceId | text | ID doc khởi nguồn (PO id, sale order id, v.v.) — nullable cho adjustment mồ côi | |
uomId | text | ✓ | Đơn vị lúc ghi |
multiplier | decimal(15,4) | ✓ | Hệ số UoM-to-base (mặc định 1) |
quantityBefore | decimal(15,4) | ✓ | Snapshot trước khi thay đổi |
quantityChange | decimal(15,4) | ✓ | Delta có dấu |
quantityAfter | decimal(15,4) | ✓ | Snapshot sau khi thay đổi |
effectivePrice | decimal(15,4) | Cost mỗi đơn vị (chỉ với write PURCHASE) | |
fromLocationId / toLocationId | text | Source / destination TRANSFER | |
reasonCode | text | Một trong §5 (13 reason) | |
lotNumber / serialNumber / expiryDate | text / timestamptz | Snapshot bất biến của bucket được di chuyển | |
remainingQuantity | decimal(15,4) | Tracker layer FIFO (giảm dần khi outbound tiêu thụ) | |
note | text | Tự do (xem InventoryTrackingNotes bên dưới) | |
createdBy / modifiedBy | text | Audit user (cho phép ẩn danh) |
Chú ý: không có cột
typetrong schema. "Loại movement" (một trong 19FixedInventoryTrackingTypes) được suy ra từ(referenceType, reasonCode, dấu của quantityChange)lúc đọc, không lưu riêng. Code service thường ghinoteđể phân biệt.
Mutability: append-only. Service xem bảng này là bất biến; không bao giờ ghi deletedAt hay update row trong path bình thường.
3. Loại Tracking
Nguồn:
FixedInventoryTrackingTypestrong@nx/core/src/models/schemas/inventory/inventory-tracking/constants.ts. Tổng cộng 19 + 1CUSTOM.
Inbound (6)
| Type | Dùng bởi |
|---|---|
STOCK_IN | Nhận hàng thủ công không qua PO |
PURCHASE | Luồng PO receive |
TRANSFER_IN | Chuyển cross-location (phía destination) |
RETURN_FROM_CUSTOMER | Phiếu return của customer |
ADJUSTMENT_IN | Tăng thủ công của admin |
PRODUCTION_COMPLETE | Output ProductionOrder được ghi |
Outbound (10)
| Type | Dùng bởi |
|---|---|
STOCK_OUT | Trừ thủ công không qua bán hàng |
SALE | Trừ khi sale payment success |
TRANSFER_OUT | Chuyển cross-location (phía source) |
RETURN_TO_VENDOR | Phiếu return cho vendor |
ADJUSTMENT_OUT | Giảm thủ công của admin |
EXPIRED | Scrap do hết hạn |
LOST | Mất/trộm |
DAMAGED | Write-off do hư hỏng |
USED_INTERNAL | Phiếu dùng nội bộ |
USED_AS_MATERIAL | Tiêu thụ kitchen ticket (bung BOM) |
Neutral (2)
| Type | Dùng bởi |
|---|---|
INVENTORY_COUNT | Đối chiếu cycle count |
ADJUSTMENT_NEUTRAL | Nhập admin delta-zero (chỉ để annotation) |
Custom (1)
| Type | Dùng bởi |
|---|---|
CUSTOM | Mở rộng tự do — bất kỳ loại merchant tự định nghĩa qua DiscriminationType |
4. ReferenceTypes
Nguồn:
InventoryTrackingReferenceTypes.
| ReferenceType | Sử dụng |
|---|---|
PURCHASE_ORDER | PO receive |
SALE_ORDER | Sale payment success → trừ product + reserve material |
KITCHEN_TICKET | Vòng đời kitchen ticket |
KITCHEN_TICKET_ITEM | Tiêu thụ BOM theo từng item |
INVENTORY_TICKET | Workflow ticket (transfer, adjust, count, scrap, return) |
PRODUCTION_ORDER | Tiêu thụ + output sản xuất |
ADJUSTMENT | Nhập tay của admin không có doc cha |
UNKNOWN | Fallback / chưa phân loại |
5. Reasons
Nguồn:
InventoryTrackingReasons.
| Reason | Sử dụng |
|---|---|
DAMAGED | Stock bị hỏng |
LOST | Đặt sai chỗ / trộm |
EXPIRED | Quá hạn dùng |
CYCLE_COUNT | Đối chiếu audit |
CORRECTION | Sửa thủ công |
CUSTOMER_RETURN | RMA từ customer |
VENDOR_RETURN | RMA cho vendor |
TRANSFER_IN / TRANSFER_OUT | Cross-location |
PRODUCTION_CONSUME | Material dùng trong sản xuất |
PRODUCTION_OUTPUT | Hàng hóa được sản xuất |
RESERVATION | Material được reserve cho bán |
RESERVATION_RELEASE | Reservation bị hủy (kitchen VOIDED) |
6. Notes
Nguồn:
inventory/src/common/constants.ts:1-18(InventoryTrackingNotes).
| Hằng số | Giá trị |
|---|---|
ADJUSTMENT_FROM_PRODUCT_VARIANT_CREATE | "Adjustment from product variant create form" |
ADJUSTMENT_FROM_PRODUCT_VARIANT_UPDATE | "Adjustment from product variant update form" |
ADJUSTMENT_FROM_PRODUCT_VARIANT_CDC | "Adjustment from product variant CDC bridge" |
OVERSELL_BLOCKED | "OVERSELL_BLOCKED: deduct skipped; insufficient stock with allowOversell=false" |
INBOUND_FROM_PURCHASE_ORDER | "Inbound from purchase order" |
OUTBOUND_FROM_MATERIAL_USED | "Outbound from material used" |
ADJUSTMENT_FROM_MATERIAL_CREATE | "Adjustment from material create from" |
ADJUSTMENT_FROM_MATERIAL_UPDATE | "Adjustment from material update from" |
MATERIAL_RESERVED_FROM_SALE_ORDER | "Material reserved at sale-order payment success" |
7. Vận hành
Bề mặt service
InventoryTrackingService (inventory-tracking.service.ts:21-41) là MerchantScopedService chỉ kế thừa CRUD — không có mutator tùy biến. Read được filter theo merchant. Write xảy ra trong các luồng stock-mutation của service khác; không có public write API hôm nay (chủ ý — để bảo toàn tính toàn vẹn audit).
Bề mặt REST
| Verb | Path | Auth | Permission |
|---|---|---|---|
| 6× CRUD | /inventory-trackings | JWT/BASIC | InventoryTracking.<crud> |
Thực tế là read-only —
POSTvà endpoint mutation tồn tại qua CRUD nhưng service layer không lộ entry point write tùy biến nào.
8. Vai trò Idempotency
Mọi Kafka worker dùng InventoryTracking như sổ cái dedup trước bất kỳ stock mutation nào:
Xem ADR-0004 để có lý do đầy đủ.
9. Pattern Truy vấn
| Câu hỏi | Truy vấn |
|---|---|
| Movement cho một SaleOrder | WHERE reference_type = 'SALE_ORDER' AND reference_id = '<id>' |
| Lịch sử stock cho một bucket | WHERE inventory_stock_id = '<id>' ORDER BY created_at DESC |
| Sự cố oversell (24h gần nhất) | WHERE note LIKE 'OVERSELL_BLOCKED%' AND created_at > now() - interval '24h' |
| Hàng nhận từ một vendor (qua PO) | join PurchaseOrder trên referenceId where vendorId = '<id>' |
| Khối lượng phát hàng theo ngày theo type | GROUP BY type, date_trunc('day', created_at) |
10. Side effects khi ghi
| Side effect | Khi nào |
|---|---|
Denormalize merchantId | Từ InventoryStock.merchantId lúc ghi |
Snapshot multiplier | Từ UoM của line entity lúc ghi |
Snapshot effectivePrice | Từ unitPrice của line PO (chỉ trên type PURCHASE) |
11. Trang liên quan
- Inventory Stock — mọi thay đổi đều ghi tracking row
- Purchase Order — bên ghi type
PURCHASE - Material & BOM — bên ghi
USED_AS_MATERIAL - ADR-0004 Worker idempotency qua Tracking
- Vận hành — Pattern truy vấn audit