Skip to content

Type Deep Dive — Stock Movement Engine

1. Request / document / shipping là gì?

Inventory operations không đi theo một object duy nhất.

text
inventory_request   = intent / approval
inventory_document  = execution
shipping_note       = physical ship / receive
product_supplying   = movement ledger

Đây là mô hình quan trọng nhất của toàn package.

2. inventory_request

2.1 Dùng cho gì?

  • inventory_request_check
  • inventory_request_transfer

Create request không tạo movement ngay. Insert event chủ yếu mới gửi notification.

2.2 Khi nào request tạo side effects?

Khi status update:

  • check balanced -> tự sinh phiếu nhập/xuất bù chênh
  • transfer completed -> tự sinh order_transfer
  • transfer canceled -> gửi notification từ chối

Kết luận:

  • inventory_request là request-layer thật,
  • execution bắt đầu ở inventory_request_update_status, không phải ở lúc insert.

3. inventory_document

3.1 Dùng cho gì?

inventory_document là execution container của import/export:

  • gắn order_id hoặc inventory_request,
  • gắn from_warehouse_id, to_warehouse_id, supplier_id,
  • có array product_supplyings.

3.2 Action hiện tại

Action backend rất hẹp:

  • chỉ đổi status_id sang inventory_released hoặc inventory_canceled.

Nghĩa là:

  • action không đại diện cho full state machine,
  • nhiều semantics thực bị dồn sang event update-status.

3.3 Event side effects

inventory_document_update_status mới là nơi làm việc nặng:

  • complete order_material,
  • chuyển order_transfer sang delivering hoặc completed,
  • auto-sinh import document cho transfer,
  • cancel order hoặc release hold,
  • rebuild capture.

4. shipping_note

4.1 Boundary riêng

shipping_note không phải request cũng không phải inventory document.

Nó là lớp physical ship/receive:

  • DELIVERY -> xuất âm khỏi kho gửi,
  • RECEIVED -> nhập dương vào kho nhận,
  • CANCEL -> xóa movement theo shipping_note_code nếu chưa nhận.

4.2 Hậu quả thiết kế

  • cùng là “chuyển kho” nhưng request, document và shipping là ba lớp khác nhau,
  • trace end-to-end phải theo nhiều key: request id, order id, inventory document id, shipping_note_code.

5. product_supplying

5.1 Đây là ledger gì?

product_supplying là movement ledger gốc. Nó chứa ít nhất các semantics:

  • import
  • export
  • hold
  • release
  • dispose

Ngoài ra còn gắn được:

  • inventory_document_id
  • order_id
  • reference_id
  • shipping_note_code

5.2 Tại sao khó?

Vì tên bảng nghe giống “nhập hàng”, nhưng thực tế là sổ cái movement tổng.

Điều này làm tài liệu cũ rất dễ mắc lỗi:

  • gọi nhầm đây là snapshot,
  • hoặc chỉ mô tả như bảng supplier/import.

6. Rủi ro / Findings kỹ thuật

IDMứcFinding
ME-F01P1changeInventoryDocumentStatus quá hẹp so với semantics thực của execution flow.
ME-F02P1inventory_request_insert gần như chỉ noti, nên request-layer khá mỏng; invariant thật nằm ở update-status event.
ME-F03P1shipping_note_insert_update có nhiều chỗ assume mảng có phần tử đầu tiên, dễ panic khi dữ liệu rỗng.
ME-F04P1shipping_note nhánh RECEIVED có nguy cơ dùng sai dữ liệu dòng đầu tiên của product_supplying cho note nhiều SKU/lot.
ME-F05P1product_supplying đang bị upsert ở một số path, nên tính chất ledger không hoàn toàn append-only.