PRD: Giữ tồn & chặn bán quá tay
| Module | Kho | PRD ID | PRD-RSV-001 |
| Trạng thái | Chưa tạo item | FEAT | RSV |
| Epic | — | Plane | — |
| Ngày | 2026-07-13 | Phiên bản | v1.0 |
| Gói | @nx/inventory | URD | RSV |
| Surface | BackendClient · Chủ/QL | ||
| Phụ trách | Phát Nguyễn | ||
Giữ tồn là gì
Một chi nhánh (Merchant) có thể có nhiều kho (InventoryLocation), và mỗi mặt hàng tại mỗi kho mang bốn con số tồn.
Giữ tồn (Reservation) là một lời hứa dành sẵn N đơn vị của một mặt hàng cho một người giữ (Holder) cụ thể: một đơn bán, một phiếu chuyển kho, hoặc một lệnh sản xuất. Hàng vẫn nằm trên kệ, nhưng không ai khác bán được nữa. Ngay khi thu ngân bấm một món vào đơn trên POS, hệ thống giữ luôn phần hàng tương ứng.
Bốn chỉ số trong tồn kho
Trích từ Kho & mức tồn để khỏi phải mở PRD khác. Mỗi mặt hàng ở mỗi kho mang bốn con số:
| Con số | Nghĩa |
|---|---|
| Thực có | Hàng đang nằm trong kho |
| Đang giữ | Đã hứa cho một chứng từ khác, không bán cho ai được nữa |
| Khả dụng | Phần còn bán được |
| Đang về | Đã rời kho gửi, chưa tới kho nhận |
Bất biến, đúng ở mọi thời điểm:
Khả dụng = Thực có - Đang giữVì sao bán quá tay là lỗi đắt nhất
Bán quá tay là hứa cùng một món cho hai khách. Khách thứ hai trả tiền xong mới biết hết hàng, merchant phải xin lỗi và hoàn tiền. Lỗi này xảy ra vì hệ thống chỉ nhìn con số "còn bao nhiêu hàng" thay vì con số "còn bán được bao nhiêu".
Giữ tồn đóng lỗ hổng đó. Hàng được giữ ngay lúc bấm vào đơn, không đợi lúc thanh toán, nên hai thu ngân ở hai máy POS không thể cùng bán một lon nước cuối cùng. Cùng cơ chế đó phục vụ phiếu chuyển kho (hàng đã cam kết cho kho khác) và lệnh sản xuất (nguyên liệu đã cam kết cho một mẻ hàng).
Vế thứ hai là truy nguồn. Một con số tổng "đang giữ 3 lon" không nói được ai đang giữ và gỡ ở đâu, nên chủ quán thấy hàng kẹt mà không xử lý được. Vì vậy mỗi lần giữ đều mang tên người giữ.
Một lon nước cuối cùng, từ giỏ hàng tới thanh toán
Coca tại Quầy bar: thực có 10, chưa ai giữ. Hai máy POS bán cùng lúc.
| Việc xảy ra | Thực có | Đang giữ | Khả dụng |
|---|---|---|---|
| POS 1 bấm 3 lon vào đơn #123 | 10 | 3 | 7 |
| POS 2 bấm 8 lon vào đơn #124 | 10 | 3 | 7 |
| POS 2 bấm lại 7 lon vào đơn #124 | 10 | 10 | 0 |
| Khách của đơn #123 bỏ bớt 1 lon | 10 | 9 | 1 |
| Đơn #123 thanh toán xong, 2 lon rời kệ | 8 | 7 | 1 |
- Yêu cầu 8 lon của POS 2 bị từ chối ngay tại giỏ hàng: khả dụng lúc đó chỉ còn 7. Khách chưa trả tiền, thu ngân còn đổi món được.
- Giữ tồn không làm thực có giảm. Thực có chỉ giảm khi đơn hoàn tất và hàng rời kệ thật.
- Mở màn chi tiết đang giữ của Coca lúc này: đơn #124 giữ 7 lon. Hàng kẹt ở đâu thì gỡ được ở đó.
Chỗ dễ sai nhất
Kho không tự nhả tồn theo thời gian
Không có đồng hồ đếm ngược, không có cơ chế tự hết hạn: một đơn để mở qua đêm vẫn giữ nguyên phần hàng của nó.
Kho không biết đơn đó còn sống hay đã chết. Một đơn để mở 2 tiếng có thể là bàn khách đang ăn dở. Chỉ nơi tạo ra lần giữ mới biết, nên chính nơi đó ra lệnh nhả: đơn bán khi hủy hoặc hoàn tất, phiếu chuyển khi hàng rời kho gửi, lệnh sản xuất khi mẻ hàng chạy xong hoặc bị hủy.
Việc nhả diễn ra im lặng, không bật thông báo nào. Đơn treo giữ hàng thì chủ merchant tìm ra nó trên màn chi tiết đang giữ và hủy đơn đó.