PRD: Đơn hàng bán & giỏ hàng
| Module | Đơn hàng (CORE-07) | PRD ID | PRD-ORD-001 |
| Status | Shipped | Owner | Orders squad |
| Date | 2025-12-31 | Version | v1.0 |
| Packages | @nx/sale | URD | ORD |
TL;DR
Cho phép merchant dựng một giao dịch bán dưới dạng giỏ nháp, thêm và sửa các dòng hàng, rồi đưa nó qua checkout thành một đơn hàng có thể thanh toán và đạt trạng thái cuối đã thanh toán/hoàn tất. Đây là bộ khung "giỏ → đơn hàng → thanh toán" đầu cuối đầu tiên của module Đơn hàng - mỗi đơn hàng giờ có một vòng đời được kiểm soát, giá được khoá tại thời điểm checkout, và nơi lưu thông tin thanh toán cùng giao hàng.
1. Context & Problem
Package đơn hàng khởi đầu chỉ là các controller khung (cart, cart-item, order, order-item, payment-info, shipping-info) chưa có vòng đời hoạt động: chưa có cách dựng một đơn hàng dưới dạng giỏ, thay đổi các dòng hàng, và đưa nó qua checkout đến thanh toán. Thiếu bộ khung đó, không có gì ở phía sau - thu thanh toán, phiếu bếp, phiên POS, tích điểm - có một đơn hàng để 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 entity duy nhất đóng cả vai trò giỏ (khi ở DRAFT) lẫn đơn đã chốt, với việc sửa dòng hàng khi còn nháp, một đường checkout để kiểm tra và khoá giá, và service đơn hàng điều khiển các 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á.
- Lưu thông tin thanh toán và giao hàng gắn với đơn hàng (payment-info, shipping-info).
- Cung cấp contract request/response cho đơn hàng và một endpoint 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 |
Core scenarios: 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 ghi nhận thông tin thanh toán và giao hàng gắn với đơn hàng, để đơn mang đủ thông tin mà thanh toán cần.
- 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 | Lưu payment-info và shipping-info gắn với đơn hàng | 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 apps/client): 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
| Entity | Vai trò |
|---|---|
SaleOrder | Chứng từ đơn hàng - đóng cả vai trò giỏ (DRAFT) lẫn đơn đã chốt; mang trạng thái và tổng tiền |
OrderItem | Một dòng hàng - tham chiếu sản phẩm, số lượng, giá đã khoá |
PaymentInfo | Thông tin thanh toán lưu gắn với đơn hàng |
ShippingInfo | Thông tin giao hàng lưu gắn với đơn hàng |
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 (
@nx/payment) - 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 - tổng quan + truy vết
- Liên quan: Kho hàng · Thanh toán
- Developer: @nx/sale · domain model