Skip to content

PRD: Công thức / Bill of Material

ModuleKho (CORE-06)PRD IDPRD-REC-001
StatusIn-progressOwnerInventory squad
Date2026-04-15Versionv0.1
Packages@nx/inventory · @nx/sale · @nx/coreURDREC · MAT

TL;DR

Cho phép merchant F&B khai báo một sản phẩm tiêu hao những nguyên vật liệu nào dưới dạng công thức (bill of materials) có phiên bản, rồi tự động trừ các nguyên vật liệu đó ngay khi món được chế biến. Khi một kitchen-ticket item tiến triển - hoặc khi payment thành công - công thức đang hiệu lực được bung ra, mỗi nguyên vật liệu bị trừ tại location mặc định của merchant, và một biến động "Used as Material" bất biến được ghi lại. Kết quả: tồn nguyên vật liệu luôn chính xác mà không cần ai thao tác thủ công.

1. Context & Problem

Merchant F&B bán các sản phẩm đã chế biến - món ăn, đồ uống - mà tác động lên tồn không nằm ở thành phẩm mà ở các nguyên vật liệu thô bên dưới. Kho đã theo dõi biến thể và nhận hàng qua đơn mua hàng, nhưng chưa có cách khai báo một sản phẩm tiêu hao nguyên vật liệu nào, cũng như chưa thể trừ các nguyên vật liệu đó khi một món được chế biến. Không có công thức, tồn nguyên vật liệu chỉ có thể chỉnh bằng điều chỉnh thủ công - dễ sai và phá vỡ việc theo dõi chi phí/mức tiêu hao cho ngành F&B mà KICKO nhắm tới.

Hạng mục này giới thiệu Công thức nguyên vật liệu (bill of materials): một công thức có phiên bản gắn vào một biến thể sản phẩm, một tập dòng công thức (nguyên vật liệu + số lượng + đơn vị), và một luồng runtime bung công thức đang hiệu lực và trừ các nguyên vật liệu - được nối từ vòng đời kitchen-ticket và từ luồng payment-success. Nó xây trên danh mục nguyên vật liệu hiện có và các primitive tồn/tracking.

2. Goals & Non-Goals

Goals

  • Một công thức có phiên bản gắn vào một biến thể sản phẩm (phiên bản mặc định 1.0), unique theo (principal, version).
  • Dòng công thức khai báo một nguyên vật liệu, một số lượng (decimal, 4 chữ số), và một đơn vị; cùng một nguyên vật liệu xuất hiện nhiều nhất một lần mỗi công thức; soft-delete cho phép thêm lại.
  • Activate / deactivate sao cho chỉ phiên bản công thức được kích hoạt mới được dùng ở runtime.
  • Bung ở runtime: một thay đổi trạng thái kitchen-ticket-item (và luồng payment-success) kích hoạt tra cứu công thức, trừ từng thành phần tại location mặc định, ghi một tracking entry "Used as Material", và phát một event material.stock-changed.
  • Nguyên vật liệu là một inventory item type hạng nhất - tạo inventory cho nguyên vật liệu, với SALE_ORDER được thêm vào InventoryTrackingReferenceTypes.

Non-Goals

  • BOM nhiều cấp / cụm lắp ráp con - chỉ một cấp.
  • Năng suất công thức (yield) và phần trăm hao hụt (scrap).
  • Tôn trọng một location bếp không-mặc-định (URD-REC-208) - runtime dùng location mặc định của merchant.
  • BOM bung-khi-bán cho bán lẻ ngoài F&B.

3. Success Metrics

MetricMục tiêu / tín hiệu
Độ phủ tự động trừ100% lần hoàn tất món-chế-biến trừ nguyên vật liệu qua công thức hiệu lực (không điều chỉnh thủ công)
Độ chính xác tồnTồn nguyên vật liệu sau khi bung = tổng số lượng dòng công thức × số món chế biến
IdempotentCùng (referenceType, referenceId) phát lại tạo đúng một tracking entry
Toàn vẹn phiên bảnChỉ phiên bản công thức được kích hoạt mới được bung; các phiên bản trước được giữ

4. Personas & Use Cases

PersonaMục tiêu trong tính năng này
OwnerĐịnh nghĩa công thức theo từng món, kiểm soát phiên bản nào đang chạy, xem mức tiêu hao nguyên vật liệu
Nhân viên bếp / khoĐể nguyên vật liệu được trừ tự động khi món được chế biến
SystemBung công thức hiệu lực khi có event kitchen/payment và ghi audit trail

Core scenarios: owner tạo một công thức cho một biến thể → thêm dòng công thức (nguyên vật liệu + số lượng + đơn vị) → activate → một kitchen-ticket item tiến triển (hoặc payment thành công) → công thức hiệu lực bung ra, nguyên vật liệu bị trừ tại location mặc định, một entry "Used as Material" được ghi, và một event material.stock-changed được phát.

5. User Stories

  • Là một owner, tôi muốn gắn một công thức vào một biến thể sản phẩm, để món biết nó tiêu hao những nguyên vật liệu nào.
  • Là một owner, tôi muốn thêm dòng công thức với một nguyên vật liệu, số lượng và đơn vị, để mỗi lần trừ nguyên vật liệu đều chính xác.
  • Là một owner, tôi muốn activate đúng một phiên bản công thức, để runtime luôn dùng đúng định nghĩa.
  • Là một owner, tôi muốn việc sửa một công thức đang hiệu lực tạo ra một phiên bản mới, để các công thức lịch sử được giữ.
  • nhân viên bếp, tôi muốn nguyên vật liệu tự động trừ khi một món được chế biến, để không bao giờ phải chỉnh tồn nguyên vật liệu thủ công.
  • system, tôi muốn việc bung là idempotent và no-op an toàn khi không có công thức hay location mặc định, để các lần phát lại và trường hợp biên không làm hỏng tồn.

6. Functional Requirements

#Yêu cầuURD ref
FR-1Tạo một công thức có phiên bản gắn vào một biến thể sản phẩm (mặc định 1.0); (principal, version) uniqueURD-REC-001..003
FR-2Dòng công thức khai báo nguyên vật liệu + số lượng (4dp) + đơn vị; cùng nguyên vật liệu nhiều nhất một lần; soft-delete cho phép thêm lạiURD-REC-004..006 · URD-REC-101..105
FR-3Activate / deactivate một công thức; chỉ phiên bản được kích hoạt mới dùng ở runtimeURD-REC-007..008 · URD-REC-011
FR-4Sửa một công thức đang hiệu lực tạo phiên bản mới; bản gốc được giữ; phiên bản liệt kê được theo principalURD-REC-009..010
FR-5Một thay đổi trạng thái kitchen-ticket-item kích hoạt tra cứu công thức và chuẩn bị trừ tại location mặc địnhURD-REC-201
FR-6Mỗi thành phần bị trừ; một tracking entry "Used as Material" được tạo; tồn cập nhật tại location mặc địnhURD-REC-202..203
FR-7Công thức được kích hoạt của biến thể là cái được bung; một event material.stock-changed được phát sau khi bungURD-REC-204..205
FR-8Không có location mặc định → ghi warning, bỏ qua (không lỗi cứng); không có công thức hiệu lực → no-op âm thầmURD-REC-206..207
FR-9Nguyên vật liệu là một inventory item type hạng nhất với việc tạo inventory cho nguyên vật liệu; hỗ trợ barcode/các scheme định danhURD-MAT-001..007 · URD-MAT-101..106

Toàn văn yêu cầu và tiêu chí nghiệm thu nằm trong URD Kho. PRD này tham chiếu chúng thay vì lặp lại. URD-REC-208 (location bếp không-mặc-định) được loại khỏi phạm vi hạng mục này một cách tường minh.

7. Non-Functional Requirements

AreaYêu cầu
Data integrityMỗi lần trừ nguyên vật liệu và tracking entry "Used as Material" của nó được ghi cùng nhau - không thay đổi tồn mà không có audit entry bất biến tương ứng
IdempotencyViệc bung là idempotent theo (referenceType, referenceId); phát lại không tạo biến động trùng
Tenancy & authzMọi thao tác scope theo merchant (x-merchant-id); mutation công thức được gate bởi permission của inventory
Độ chính xácSố lượng dòng công thức và phép tính tồn dùng float(value, 4)
ResilienceThiếu location mặc định hoặc thiếu công thức hiệu lực suy giảm mượt mà (warn / no-op), không bao giờ lỗi cứng trên luồng kitchen/payment
EventingViệc bung ở runtime được định tuyến qua một material worker chuyên dụng và phát material.stock-changed
i18nTên nguyên vật liệu và nhãn hiển thị cho người dùng là song ngữ ({ en, vi })

8. UX & Flows

Màn hình chính (trong apps/client): trình soạn công thức trên một biến thể sản phẩm (thêm/sửa dòng công thức, activate/deactivate phiên bản) và danh mục nguyên vật liệu. Việc bung ở runtime không có UI - nó được điều khiển bằng event.

9. Data & Domain

EntityVai trò
MaterialMột nguyên vật liệu thô được theo dõi tách biệt với sản phẩm bán được; có các định danh (SKU/BARCODE/QR) và tên i18n
MaterialRecipeMột công thức có phiên bản gắn vào một biến thể sản phẩm; một phiên bản được kích hoạt điều khiển runtime
MaterialRecipeItemMột dòng công thức - tham chiếu nguyên vật liệu, số lượng (4dp), đơn vị
Inventory item của nguyên vật liệuMột inventory item hạng nhất cho nguyên vật liệu, để tồn và tracking áp dụng được
Movement recordTracking entry "Used as Material" bất biến được ghi khi trừ

Chỉ là khái niệm - schema và bất biến đầy đủ trong domain model của inventory.

10. Dependencies & Assumptions

Phụ thuộc vào

  • Danh mục nguyên vật liệu (URD-MAT) - dòng công thức tham chiếu các nguyên vật liệu đã tồn tại.
  • Mức tồn & audit biến động (URD-STK · URD-TRK) - việc trừ xây trên các primitive tồn và tracking.
  • Location kho (URD-LOC) - các thành phần bị trừ tại location mặc định của merchant.
  • Event sale / kitchen (@nx/sale) - thay đổi trạng thái kitchen-ticket-item và luồng payment-success kích hoạt việc bung.

Giả định

  • Merchant có một location kho mặc định.
  • Nguyên vật liệu đã tồn tại và đã liên kết tới inventory item trước khi một công thức tham chiếu chúng.
  • Biến thể sản phẩm mà một công thức gắn vào đã có trong danh mục.

11. Risks & Open Questions

Rủi ro / câu hỏiGiảm thiểu / trạng thái
Việc trừ và tracking entry có thể lệch nhau khi lỗi một phầnĐược ghi cùng nhau; không thay đổi tồn mà không có movement record tương ứng
Món kitchen không có công thức hiệu lựcNo-op âm thầm - đã ghi tài liệu, không phải lỗi
Merchant không có location mặc địnhGhi warning, bỏ qua việc bung; không lỗi cứng
Location bếp không-mặc-định chưa được tôn trọngNgoài phạm vi (URD-REC-208); runtime dùng location mặc định của merchant - giữ REC In-progress
Có thể cần BOM nhiều cấp / cụm lắp ráp con về sauNgoài phạm vi; chỉ một cấp ở hạng mục này

12. Release Plan & Launch Criteria

AspectKế hoạch
PhaseP3 (BOM + Advanced) - xem feature catalog của URD
RolloutMerchant F&B; không feature flag
MigrationEntity mới (material recipe + recipe item); không backfill
Launch criteriaTạo→activate→event kitchen→trừ nguyên vật liệu + entry "Used as Material" được kiểm chứng end-to-end; phát lại idempotent được kiểm chứng; các luồng no-op/bỏ qua được kiểm chứng
MonitoringLượng event material.stock-changed, tỷ lệ lỗi/bỏ-qua khi bung, kiểm tra nhất quán tồn-vs-movement của nguyên vật liệu

13. FAQ

Tại sao trừ nguyên vật liệu thay vì thành phẩm? Tác động lên tồn của F&B nằm ở nguyên liệu, không phải món. Công thức ánh xạ một biến thể tới các nguyên vật liệu nó tiêu hao để đúng tồn được biến động.

Cái gì kích hoạt việc trừ? Một thay đổi trạng thái kitchen-ticket-item, và cả luồng payment-success. Cả hai định tuyến qua một material worker chuyên dụng.

Phiên bản công thức nào được dùng? Chỉ phiên bản được kích hoạt. Sửa một công thức đang hiệu lực tạo phiên bản mới và giữ bản gốc.

Điều gì xảy ra nếu không có công thức hay không có location mặc định? Không có công thức hiệu lực thì no-op âm thầm; không có location mặc định thì ghi warning và bỏ qua - cả hai không chặn luồng kitchen hay payment.

Có hỗ trợ BOM nhiều cấp không? Không - chỉ một cấp ở hạng mục này. Cụm lắp ráp con và yield/scrap của công thức nằm ngoài phạm vi.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.