PRD: Phiếu kho
| Module | Kho (CORE-06) | PRD ID | PRD-TKT-001 |
| Status | In-progress | Owner | Inventory squad |
| Date | 2026-05-26 | Version | v0.1 |
| Packages | @nx/core · @nx/inventory | URD | TKT |
TL;DR
Cung cấp cho merchant một document duy nhất - Phiếu kho (Inventory Ticket) - để ghi nhận, điều phối, và thực thi mọi thao tác kho: chuyển giữa các địa điểm, điều chỉnh tồn, kiểm kê, trả hàng, và hủy bỏ. Mỗi phiếu mang line item và đi qua một vòng đời phê duyệt chung, nên một biến động đã lên kế hoạch chỉ được áp vào tồn sau khi được duyệt, với biến động cuối cùng truy vết đầy đủ về đúng phiếu đã cho phép nó.
1. Bối cảnh & Vấn đề
Các thao tác kho - chuyển tồn giữa các địa điểm, điều chỉnh số lượng, kiểm kê, trả hàng về vendor hoặc từ customer, hủy bỏ tồn hư hỏng - đều cần một document ghi nhận ý định, đi qua phê duyệt, và chỉ chạm vào tồn ở bước cuối cùng. Kho đã có địa điểm, mục, tồn, và audit trail bất biến, nhưng chưa có document thao tác gắn một biến động đã lên kế hoạch với các dòng tracking cuối cùng của nó.
Khi không có document như vậy, mọi thay đổi tồn ngoài mua hàng đều ad-hoc: không có trạng thái có kiểm soát giữa "dự định" và "đã áp", không có cổng phê duyệt, và không có một bản ghi duy nhất để chủ chỉ vào và nói "đây là lý do tồn biến động". Aggregate Phiếu kho chính là document đó. Nó được mô hình hóa để bao trùm toàn bộ không gian thao tác ngay từ đầu - nhiều loại phiếu, một vòng đời chung, reference partner/origin đa hình, và một self-link trả hàng/backorder - nên các milestone sau bổ sung hành vi thực thi mà không cần migration schema thêm.
2. Mục tiêu & Ngoài phạm vi
Mục tiêu
- Một InventoryTicket header duy nhất bao trùm mọi loại thao tác tồn: Transfer, Adjustment, Cycle Count, Return to Vendor, Return from Customer, Scrap/Disposal, cộng thêm Purchase Request, Stock In, và Internal Use.
- Một vòng đời chung
DRAFT → SUBMITTED → APPROVED → IN_PROGRESS → COMPLETED / CANCELLED, thể hiện bằng hằng số có kiểu với các guard chuyển trạng thái (canSubmit/canApprove/canStart/canComplete/canCancel). - Line item (InventoryTicketItem) mang số lượng kế hoạch so với thực tế, lưu cùng header với CRUD scoped theo merchant và soft-delete.
- Một schema dành sẵn các cột cấu trúc cho phần thực thi về sau (partner ref đa hình, origin ref đa hình, self-link trả hàng/backorder, link PO đã sinh, lùi ngày hiệu lực, mã lý do) nên không cần migration sau này để bổ sung hành vi.
Ngoài phạm vi
- Thực thi vòng đời tác động tồn - hoàn tất một phiếu để tạo dòng InventoryTracking và cập nhật tồn (URD-TKT-004) được hoãn sang một milestone sau; service CRUD chưa hiện thực các chuyển trạng thái.
- Route ghi aggregate đa dòng (header + item trong một lần gọi) - hoãn cùng với vòng đời.
- Tách thực thi một phần cho backorder - cột self-link đã dành sẵn, chưa có hành vi trong increment này.
- Đặt giữ theo báo giá / hạn mức và bắt buộc chặn tồn âm tại POS - ngoài phạm vi module theo URD.
3. Success Metrics
| Metric | Mục tiêu / tín hiệu |
|---|---|
| Độ bao phủ thao tác | Một ticket header mô hình hóa 100% các loại thao tác tồn đã lên kế hoạch - không cần document riêng cho từng loại |
| Độ bền schema | Phần thực thi về sau đáp ứng với zero migration schema bổ sung (cột dành sẵn từ đầu) |
| Cô lập tenancy | Mọi phiếu và dòng đều scoped theo merchant; đọc xuyên merchant trả về rỗng |
| Tính đúng vòng đời | Mọi thay đổi trạng thái đi qua một guard chuyển trạng thái; không chuyển trạng thái bất hợp lệ nào được lưu |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Nhân viên kho | Soạn một phiếu cho thao tác kho, gắn các dòng của nó, và điều phối đi phê duyệt |
| Chủ / Quản lý | Rà soát và duyệt phiếu trước khi chúng ảnh hưởng tồn; hủy phiếu sai |
| Hệ thống (milestone sau) | Áp một phiếu đã duyệt vào tồn và ghi audit trail khi hoàn tất |
Kịch bản chính: tạo một phiếu với loại thao tác cho trước → thêm line item (số lượng kế hoạch) → submit → approve → start → complete (thực thi tồn hoãn sang milestone sau) - hoặc hủy từ bất kỳ trạng thái chưa-kết-thúc nào.
5. User Stories
- Là nhân viên kho, tôi muốn tạo một phiếu với loại thao tác cụ thể (chuyển, điều chỉnh, kiểm kê, trả hàng, hủy bỏ), để một biến động kho đã lên kế hoạch có một nơi duy nhất.
- Là nhân viên kho, tôi muốn gắn line item với số lượng kế hoạch, để phiếu nêu chính xác cái gì nên biến động.
- Là nhân viên kho, tôi muốn submit một phiếu đi phê duyệt, để tồn không bị chạm tới cho đến khi ai đó ký duyệt.
- Là chủ, tôi muốn duyệt hoặc hủy một phiếu qua các chuyển trạng thái có guard, để chỉ các bước vòng đời hợp lệ được cho phép.
- Là chủ, tôi muốn mọi phiếu và dòng của nó được cô lập theo merchant của tôi, để merchant khác không bao giờ thấy hoặc thay đổi chúng.
- Là nền tảng, tôi muốn schema đã sẵn mang các cột partner, origin, return-link, PO-đã-sinh và mã lý do, để hành vi thực thi về sau không cần migration.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | InventoryTicket header mô hình hóa toàn bộ không gian thao tác - 9 loại (PURCHASE_REQUEST, STOCK_IN, TRANSFER, INTERNAL_USE, ADJUSTMENT, CYCLE_COUNT, RETURN_TO_VENDOR, RETURN_FROM_CUSTOMER, SCRAP_DISPOSAL), một superset của 6 loại URD liệt kê | URD-TKT-001 |
| FR-2 | Vòng đời chung DRAFT → SUBMITTED → APPROVED → IN_PROGRESS → COMPLETED / CANCELLED, dưới dạng status có kiểu với ACTIVE_SET/TERMINAL_SET và các guard canSubmit/canApprove/canStart/canComplete/canCancel | URD-TKT-002 |
| FR-3 | Line item (InventoryTicketItem) mang số lượng kế hoạch so với thực tế, lưu cùng header | URD-TKT-003 |
| FR-4 | Hoàn tất một phiếu tạo các entry tracking và cập nhật tồn | URD-TKT-004 |
| FR-5 | Line item dành sẵn cột lot/serial ở lớp schema | URD-TKT-005 |
| FR-6 | Ghi đè địa điểm theo từng mục - header mang nguồn/đích, các dòng tách theo từng bin | URD-TKT-006 |
| FR-7 | Header dành sẵn một partner reference đa hình (Vendor / Customer) và một origin reference đa hình cho liên kết về sau | URD-TKT-001 |
| FR-8 | Header dành sẵn một self-link trả hàng/backorder, một link PO đã sinh, một mã lý do, và một ngày hiệu lực để lùi ngày | URD-TKT-006 |
| FR-9 | Header và dòng scoped theo merchant với soft-delete; CRUD tôn trọng cô lập merchant | URD-TKT-002 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Kho. PRD này tham chiếu chúng thay vì lặp lại. FR-4 (hoàn tất tác động tồn) và route ghi aggregate đa dòng được lên lịch cho một milestone sau - xem §2 Ngoài phạm vi và §12.
7. Non-Functional Requirements
| Khía cạnh | Yêu cầu |
|---|---|
| Toàn vẹn dữ liệu | Khi phần thực thi tồn đáp ứng, thay đổi tồn và entry tracking của nó được ghi cùng nhau - không có thay đổi tồn nào mà thiếu một entry audit bất biến tương ứng |
| Tenancy & authz | Mọi thao tác scoped theo merchant (x-merchant-id); kiểm soát bởi permission của inventory |
| An toàn vòng đời | Chuyển trạng thái chỉ qua các guard predicate; trạng thái kết thúc (COMPLETED / CANCELLED) là bất biến |
| Độ bền schema | Cột cấu trúc dành sẵn từ đầu nên phần thực thi về sau không cần migration |
| Soft-delete | Header và dòng dùng soft-delete; bản ghi đã soft-delete bị loại khỏi listing tiêu chuẩn |
| Độ chính xác | Số học số lượng kế hoạch/thực tế dùng độ chính xác thập phân (float(value, 4)) |
| i18n | Nhãn loại/trạng thái/partner 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): danh sách phiếu, tạo/sửa phiếu theo loại thao tác, trình soạn line item, và control trạng thái vòng đời. Controller và route definition của phiếu nằm trong @nx/inventory (controllers/inventory-ticket{,-item}).
9. Data & Domain
| Thực thể | Vai trò |
|---|---|
InventoryTicket | Document thao tác - identifier ITI_…, loại, trạng thái, địa điểm nguồn/đích, partner đa hình, origin đa hình, self-link trả hàng/backorder, link PO đã sinh, mã lý do, ngày hiệu lực, timestamp vòng đời, scope merchant |
InventoryTicketItem | Một dòng phiếu - reference tới mục với số lượng kế hoạch so với thực tế; dành sẵn cột lot/serial và cột địa điểm theo từng bin |
InventoryTicketTypes | 9 loại thao tác, nhóm Procurement / Routine / Returns / End-of-life; PURCHASE_REQUEST chỉ là workflow (không tác động tồn, sinh ra một PO) |
InventoryTicketStatuses | Status vòng đời có kiểu + ACTIVE_SET/TERMINAL_SET/isTerminal và các guard chuyển trạng thái |
InventoryTicketPartnerTypes | Vendor / Customer với nhãn i18n cho việc phân biệt partner |
Chỉ mang tính khái niệm - schema và bất biến đầy đủ nằm trong domain model của inventory.
10. Phụ thuộc & Giả định
Phụ thuộc vào
- Địa điểm kho (URD-LOC) - phiếu tham chiếu một địa điểm nguồn/đích.
- Mức tồn & audit biến động (URD-STK · URD-TRK) - bước hoàn tất hoãn lại về sau sẽ đọc tồn và ghi các dòng tracking.
- Vendor / Customer (URD-VEN) - partner reference đa hình trỏ tới một vendor hoặc customer.
- Đơn mua hàng (URD-PO) - một phiếu
PURCHASE_REQUESTsinh ra một PO qua link PO-đã-sinh được dành sẵn.
Giả định
- Merchant có ít nhất một địa điểm kho cho các reference nguồn/đích.
- Phần hoàn tất tác động tồn đáp ứng ở một milestone sau trước khi tính năng dùng được đầu-cuối.
11. Rủi ro & Câu hỏi mở
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Thực thi vòng đời chưa được hiện thực - service mới là CRUD thuần | Theo dõi như một Ngoài phạm vi của increment này; các handler chuyển trạng thái và route aggregate lên lịch cho một milestone sau |
| Bề rộng schema (9 loại, ref đa hình) khi chưa có hành vi có thể lệch với nhu cầu thực | Cột dành sẵn có chủ ý để tránh migration; hành vi được kiểm chứng khi phần thực thi đáp ứng |
| Ngữ nghĩa tách thực thi một phần cho backorder chưa định nghĩa | Cột self-link đã dành sẵn; hành vi tách là một câu hỏi thiết kế mở cho milestone thực thi |
| Hoàn tác một phiếu đã hoàn tất so với tracking đã ghi | Mở: định nghĩa đường hoàn tác/bù trừ khi hoàn tất đã ghi tồn |
12. Kế hoạch Phát hành & Tiêu chí Ra mắt
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P2 (thao tác đa địa điểm) - xem danh mục tính năng URD |
| Rollout | Mọi merchant; không feature flag |
| Migration | Thực thể mới (InventoryTicket, InventoryTicketItem) được thêm với bộ cột đầy đủ; không dự kiến migration sau cho phần thực thi |
| Tiêu chí ra mắt | Increment này: schema header + dòng và CRUD scoped theo merchant đã kiểm chứng. Hoàn chỉnh tính năng (milestone sau): các chuyển trạng thái submit→approve→start→complete được thực thi và một phiếu COMPLETED ghi tracking + cập nhật tồn |
| Giám sát | Lượng phiếu theo từng merchant theo loại, số lần guard chuyển trạng thái từ chối, và (sau khi có thực thi) kiểm tra nhất quán tồn-so-với-tracking |
13. FAQ
Hoàn tất một phiếu có làm biến động tồn ngay hôm nay không? Chưa - increment này ship schema header/dòng và CRUD scoped theo merchant. Phần hoàn tất tác động tồn (URD-TKT-004) được lên lịch cho một milestone sau.
Vì sao có 9 loại phiếu khi URD liệt kê 6? Schema mô hình hóa toàn bộ không gian thao tác ngay từ đầu (thêm Purchase Request, Stock In, và Internal Use) nên các milestone sau bổ sung thực thi mà không cần migration schema.
PURCHASE_REQUEST dùng để làm gì? Đó là một loại chỉ-workflow - nó không tác động tồn trực tiếp mà thay vào đó sinh ra một đơn mua hàng qua link PO-đã-sinh được dành sẵn.
Một merchant có thể thấy phiếu của merchant khác không? Không - mọi phiếu và dòng đều scoped theo merchant (x-merchant-id) với soft-delete; đọc xuyên merchant trả về rỗng.
Giao hàng một phần/trả hàng được xử lý thế nào? Header mang một cột self-link trả hàng/backorder, dành sẵn từ bây giờ; hành vi tách thực thi một phần được định nghĩa khi phần thực thi vòng đời đáp ứng.
References
- URD: Kho - Phiếu kho (
TKT) - yêu cầu - Xây trên: Địa điểm kho · Mức tồn · Audit trail biến động · Vendor · Đơn mua hàng
- Module: Kho - tổng quan + truy vết
- Developer: @nx/inventory · domain model