ADR-0001. Một entity SaleOrder duy nhất cho giỏ hàng và đơn đã chốt
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-01-10 |
| Người quyết định | Phat Nguyen |
| Thay thế cho | - |
Bối cảnh
- Quy trình POS xem "giỏ hàng" và "đơn" là cùng một entity được chốt dần: nhân viên pha chế dựng bản nháp, bấm thanh toán, rồi tới bước trả tiền.
- Tách thành hai entity (Cart + Order) buộc phải sao chép trạng thái khi thanh toán, làm phức tạp việc gộp/tách và nhân đôi số phòng mà WebSocket phải quản lý.
- Cần một nguồn sự thật duy nhất cho thứ người dùng đang thao tác, với vòng đời rõ ràng.
Quyết định
Dùng một entity SaleOrder duy nhất với trường trạng thái. DRAFT = giỏ hàng (item có thể sửa). PROCESSING / PARTIAL / COMPLETED = đã chốt. CANCELLED = trạng thái cuối.
Các chuyển trạng thái được kiểm soát bởi canModifyItems() (chỉ DRAFT), canCheckout() (chỉ DRAFT), canRevertToCart() (chỉ PROCESSING), canCancel() (mọi trạng thái còn hoạt động).
Hệ quả
| Ưu | Nhược |
|---|---|
| Một entity = một nguồn sự thật | Trường trạng thái gánh logic máy trạng thái - dễ lệch khớp |
| Gộp / tách hoạt động đồng nhất qua mọi trạng thái | Truy vấn DB muốn "chỉ đơn" phải lọc status != DRAFT |
| Bên đăng ký WebSocket chỉ thấy một vòng đời entity | Báo cáo audit phải cẩn thận với bản nháp đã huỷ |
| Giao diện mobile/POS không cần sao chép trạng thái | Thêm item đồng thời cần khoá tường minh (ADR-0002) |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do từ chối |
|---|---|---|---|
Tách Cart + Order thành entity riêng | Mỗi entity có schema gọn hơn | Sao chép khi thanh toán; nhân đôi phòng WS; logic gộp/tách nhân đôi | Chi phí triển khai lớn hơn lợi ích schema gọn |
SaleOrder + view Cart | View DRAFT vật chất hoá | View phức tạp; vẫn vướng cùng vấn đề khoá | Lợi ích không đáng kể |
Tham chiếu
core/src/models/schemas/sale/sale-order/schema.tssale/src/services/sale.service.ts:createDraftOrdercore/src/models/schemas/sale/sale-order/constants.ts:SaleOrderStatuses