PRD: Đơn hàng bán & giỏ hàng
| Module | Bán hàng | PRD ID | PRD-ORD-001 |
| Trạng thái | Sẵn sàng dev | FEAT | ORD |
| Epic | — | Plane | BANA-1520 |
| Ngày | 2025-12-31 | Phiên bản | v1.0 |
| Gói | @nx/sale | URD | ORD |
| Surface | Sale · POS | ||
| Phụ trách | Phát Nguyễn | ||
TL;DR
Thu ngân dựng đơn bán dưới dạng giỏ nháp, sửa dòng hàng tuỳ ý, rồi checkout - giá khoá lại và đơn bước vào vòng đời kiểm soát, kết thúc ở PARTIAL hoặc COMPLETED theo tiến trình thanh toán. Đây là bộ xương "giỏ → đơn → thanh toán" đầu tiên của module Đơn hàng; tiến trình thanh toán (trạng thái, mốc thời gian, số đã trả) theo dõi ngay trên đơn - không có bản ghi thông tin giao hàng trong increment này.
1. Context & Problem
Năng lực Đơn hàng khởi đầu chỉ là bộ khung chưa có vòng đời hoạt động: chưa có cách dựng đơn dưới dạng giỏ, thay đổi dòng hàng, rồi đưa qua checkout đến thanh toán. Thiếu bộ xương đó, mọi thứ ở phía sau - thu thanh toán, phiếu bếp, phiên POS, tích điểm - đều không có đơn hàng nào để gắn vào.
Phần tăng trưởng này thiết lập vòng đời đơn hàng bán nền tảng: một bản ghi vừa là giỏ (khi DRAFT) vừa là đơn đã chốt, có thể sửa dòng hàng khi còn nháp, checkout kiểm tra và khoá giá, và logic vòng đời điều khiển mọi chuyển trạng thái. Nó làm nền cho feature ORD trong URD Đơn hàng mà mọi thứ khác trong module dựa vào.
2. Goals & Non-Goals
Goals
- Dựng một đơn hàng dưới dạng giỏ nháp và thêm/sửa/xoá dòng hàng khi còn ở DRAFT.
- Một vòng đời được kiểm soát từ lúc tạo, qua checkout vào trạng thái xử lý, đến trạng thái cuối đã thanh toán/hoàn tất, kèm đường revert và huỷ.
- Checkout kiểm tra giỏ (không rỗng, giá ≥ 0, số lượng ≥ 1) và khoá giá.
- Theo dõi tiến trình thanh toán trên đơn (trạng thái, mốc thời gian, và số tiền đã trả) - một bản ghi thông tin giao hàng riêng chưa được dựng trong increment này.
- Cung cấp contract request/response cho đơn hàng và một thao tác checkout hoạt động được.
Non-Goals
- Luồng hoàn tiền / trả hàng - là non-goal trong URD (dự kiến sau).
- Thay đổi tồn kho - thuộc Kho hàng.
- Tích hợp nhà cung cấp thanh toán - thuộc Thanh toán.
- Combo fan-out, tách/gộp, gắn khách hàng, và đa tiền tệ - các tinh chỉnh sau (URD-ORD-005, URD-ORD-012..016).
- Tách hoá đơn, phiếu bếp, station, phiên POS, đặt bàn, tích điểm - các feature F&B sau (
CHK/KIT/STA/POS/RSV/PNT).
3. Success Metrics
| Metric | Mục tiêu / tín hiệu |
|---|---|
| Độ phủ vòng đời | 100% giao dịch bán đi qua vòng đời đơn hàng (không tạo đơn ngoài luồng DRAFT → checkout) |
| Tính toàn vẹn checkout | Không đơn nào vào PROCESSING với giỏ rỗng, giá âm, hoặc số lượng bằng 0 |
| Ổn định giá | Giá đã khoá tại checkout không trôi trước khi thanh toán |
| Thời gian chu kỳ | Thời gian trung vị DRAFT → COMPLETED mỗi merchant giảm dần |
4. Personas & Use Cases
| Persona | Mục tiêu trong feature này |
|---|---|
| Thu ngân | Dựng giỏ, sửa dòng hàng, checkout, và đưa đơn hàng tới thanh toán |
| Quản lý / Chủ | Tin rằng mọi giao dịch bán đều theo một vòng đời đơn hàng được kiểm soát, có thể truy vết |
Kịch bản chính: tạo giỏ nháp → thêm/sửa/xoá dòng hàng khi còn ở DRAFT → checkout (kiểm tra + khoá giá) vào PROCESSING → đạt PARTIAL khi thanh toán một phần hoặc COMPLETED khi thanh toán đủ → huỷ một đơn chưa ở trạng thái cuối hoặc revert từ PROCESSING về DRAFT.
5. User Stories
- Là thu ngân, tôi muốn tạo một đơn hàng nháp và thêm dòng hàng vào nó, để dựng dần một giao dịch bán dưới dạng giỏ.
- Là thu ngân, tôi muốn sửa hoặc xoá dòng hàng khi đơn còn ở DRAFT, để chỉnh giỏ trước khi chốt.
- Là thu ngân, tôi muốn checkout một đơn hàng nháp, để giỏ được kiểm tra, giá được khoá, và đơn sẵn sàng thanh toán.
- Là thu ngân, tôi muốn revert một đơn đã checkout về lại DRAFT, để sửa giỏ sau khi đã bắt đầu checkout.
- Là thu ngân, tôi muốn đơn theo dõi tiến trình thanh toán, để biết rõ số tiền đã thu; chưa có bản ghi thông tin giao hàng trong increment này.
- Là thu ngân, tôi muốn huỷ một đơn chưa ở trạng thái cuối, để đơn nhầm không đi tiếp tới thanh toán.
- Là quản lý, tôi muốn đơn đạt PARTIAL khi thanh toán một phần và COMPLETED khi thanh toán đủ, để vòng đời phản ánh đúng số đã thanh toán.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Tạo một đơn hàng nháp (giỏ) kèm dòng hàng | URD-ORD-001 |
| FR-2 | Thêm, sửa, xoá dòng hàng chỉ khi ở DRAFT | URD-ORD-002 |
| FR-3 | Thêm cùng một sản phẩm sẽ gộp số lượng vào dòng đã có | URD-ORD-003 |
| FR-4 | Đặt số lượng dòng hàng về 0 sẽ xoá dòng đó | URD-ORD-004 |
| FR-5 | Checkout: DRAFT → PROCESSING (kiểm tra dòng hàng, khoá giá) | URD-ORD-006 |
| FR-6 | Kiểm tra checkout: giỏ không rỗng, giá ≥ 0, số lượng ≥ 1 | URD-ORD-007 |
| FR-7 | Revert: PROCESSING → DRAFT | URD-ORD-008 |
| FR-8 | Huỷ từ DRAFT, PROCESSING, hoặc PARTIAL (kèm lý do tuỳ chọn) | URD-ORD-009 |
| FR-9 | Thanh toán một phần → trạng thái PARTIAL | URD-ORD-010 |
| FR-10 | Thanh toán đủ → trạng thái COMPLETED | URD-ORD-011 |
| FR-11 | Theo dõi tiến trình thanh toán trên đơn (trạng thái, mốc thời gian, số tiền đã trả) - thông tin giao hàng chưa được dựng trong increment này | URD-ORD-001 |
Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong URD Đơn hàng. PRD này tham chiếu chúng thay vì lặp lại.
7. Non-Functional Requirements
| Khía cạnh | Yêu cầu |
|---|---|
| Toàn vẹn dữ liệu | Dòng hàng chỉ sửa được khi ở DRAFT; checkout khoá giá nên tổng không trôi trước khi thanh toán |
| Toàn vẹn vòng đời | Các chuyển trạng thái bị ràng buộc theo đồ thị trạng thái đã định nghĩa; không nhảy thẳng từ DRAFT sang trạng thái đã thanh toán |
| Tenancy & authz | Mọi thao tác đều scope theo merchant và yêu cầu xác thực |
| Nhất quán | Việc sửa giỏ và checkout là transactional; lỗi giữa chừng không để lại đơn dựng dở |
| i18n | Nhãn/trạng thái hiển thị cho người dùng là song ngữ ({ en, vi }) |
8. UX & Flows
Màn hình chính (trong ứng dụng quản trị merchant): trình dựng giỏ/đơn hàng, sửa dòng hàng, thao tác checkout, và nút huỷ/revert. Danh sách màn hình đầy đủ nằm trong luồng module Đơn hàng.
9. Data & Domain
| Thực thể | Vai trò |
|---|---|
| Đơn hàng | Chứng từ đơn hàng - đóng cả vai trò giỏ (DRAFT) lẫn đơn đã chốt; mang trạng thái, tổng tiền, và số tiền đã trả |
| Dòng hàng | Một dòng hàng - tham chiếu sản phẩm, số lượng, giá đã khoá |
| Tiến trình thanh toán | Theo dõi trên đơn qua trạng thái, mốc thời gian, và số tiền đã trả - không có thực thể thông tin thanh toán riêng trong increment này |
| Thông tin giao hàng | Chưa dựng trong increment này |
Chỉ ở mức khái niệm - schema và bất biến đầy đủ nằm trong domain model của sale.
10. Dependencies & Assumptions
Phụ thuộc vào
- Sản phẩm (Sản phẩm) - dòng hàng tham chiếu biến thể sản phẩm.
- Thanh toán (Thanh toán) - sự kiện thanh toán điều khiển các chuyển trạng thái PARTIAL / COMPLETED / CANCELLED.
Giả định
- Mỗi request đều có ngữ cảnh merchant (scope theo merchant, đã xác thực).
- Có sản phẩm tồn tại để thêm thành dòng hàng trước khi checkout.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Sửa giỏ sau checkout có thể làm sai tổng đã khoá | Dòng hàng chỉ sửa được khi ở DRAFT; revert về DRAFT là đường được hỗ trợ để sửa |
| Giá trị trạng thái vòng đời thay đổi khi package trưởng thành | Các trạng thái URD (DRAFT → PROCESSING → PARTIAL → COMPLETED / CANCELLED) là nguồn chân lý; các feature sau căn theo chúng |
| Phần tăng trưởng này chưa có đường hoàn/trả hàng | Ngoài phạm vi; thuộc một feature hoàn tiền dự kiến sau |
| Chưa hỗ trợ combo / tách / đa tiền tệ | Hoãn sang các phần tăng trưởng sau (URD-ORD-005, URD-ORD-012..016) |
12. Release Plan & Launch Criteria
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P1 (nền tảng) - xem feature catalog của URD |
| Rollout | Mọi merchant; không feature flag |
| Migration | Entity mới; migration schema cho các bảng đơn hàng |
| Launch criteria | Tạo giỏ → sửa dòng hàng → checkout → thanh toán được kiểm chứng đầu cuối; kiểm tra checkout từ chối giỏ rỗng / giá sai / số lượng sai; giá được khoá tại checkout |
| Monitoring | Số lượng đơn mỗi merchant, tỷ lệ từ chối checkout, lỗi chuyển trạng thái vòng đời |
13. FAQ
Có thể sửa dòng hàng sau khi checkout không? Không - dòng hàng chỉ sửa được khi ở DRAFT. Dùng revert PROCESSING → DRAFT để sửa, hoặc huỷ.
Checkout thực sự làm gì? Nó kiểm tra giỏ (không rỗng, giá ≥ 0, số lượng ≥ 1), khoá giá, và chuyển đơn DRAFT → PROCESSING để sẵn sàng thanh toán.
Khác biệt giữa PARTIAL và COMPLETED là gì? PARTIAL nghĩa là đơn còn thiếu tiền; COMPLETED nghĩa là đơn đã thanh toán đủ.
Phần tăng trưởng này có xử lý combo, tách hoá đơn, hay đa tiền tệ không? Không - đó là các feature/tinh chỉnh sau. Phần này làm nền cho vòng đời đơn hàng đơn lẻ cốt lõi.
Tồn kho được giữ chỗ hay tiêu thụ ở đâu? Không ở đây - thay đổi tồn kho thuộc Kho hàng. Feature này chỉ điều khiển vòng đời đơn hàng.
References
- URD: Đơn hàng -
ORDĐơn hàng bán - yêu cầu và tiêu chí chấp nhận - Module: Đơn hàng - URD
- Liên quan: Kho hàng · Thanh toán
- Developer: @nx/sale · domain model