Files
Leonard-ThindPad-P50 2c7bcde741 improve BA skill
2026-09-09 06:34:57 +07:00

536 lines
32 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# BR — Business Rules — Giỏ hàng & Checkout (e-commerce)
| | |
|---|---|
| **Version** | 1.0 |
| **Date** | 2026-09-08 |
| **Author** | BA (qua skill ba-2-analysis) |
| **Status** | 🟡 Draft |
| **Approved by** | — |
| **Profile** | screen · greenfield · standard |
| **Source** | `01-discovery/BRIEF_CartCheckout_v1.0.md` · `01-discovery/RISK_CartCheckout_v1.0.md` · `PROCESS_CartCheckout_v1.0.md` · `BACKLOG_CartCheckout_v1.0.md` · `e-commerce/docs/sections/06-luong-xu-ly.md` §6.4 (BR-01, BR-02, tham chiếu kỹ thuật, không phải nguồn quyết định BA) · `e-commerce/docs/sections/05-thiet-ke-du-lieu.md` §5.2.3–5.2.4 (tham chiếu entity, không chép schema vật lý) |
| **Scope** | Module Giỏ hàng & Checkout — RQ-001…RQ-004 |
## Change Log
| Version | Date | Người sửa | Thay đổi | CR |
|---|---|---|---|---|
| 1.0 | 2026-09-08 | BA (qua skill ba-2-analysis) | Bản đầu — 8 business rule, ERD, 2 vòng đời trạng thái | — |
---
> ⚠️ **Ngoại lệ gate G1** — xem cảnh báo đầy đủ ở đầu `PROCESS_CartCheckout_v1.0.md` và `DEC-02`
> ở `00-index/DECISION_e-commerce.md`. Ba quy tắc dưới đây (`BR-CART-01`, `BR-CART-03`,
> `BR-CART-06`) phụ thuộc giả định **chưa được PO/Tech Lead xác nhận** — không được coi là đã
> chốt cho tới khi `OQ` liên quan được trả lời.
## 1. Danh sách quy tắc
### BR-CART-01 — Tách đơn hàng theo seller khi checkout
| | |
|---|---|
| **Loại** | Quy trình / Tính toán |
| **Nguồn** | 🟠 Quyết định mô hình kinh doanh đã chốt (marketplace đa seller) — `00-project-brief.md` vòng 1; **cơ chế tách chi tiết ("luôn đúng N đơn cho N seller, không gộp") chưa được PO xác nhận riêng cho module này** (`ASM-03`, chưa xác minh) |
| **Người chốt** | STK-01 (PO sàn) — *ở mức mô hình kinh doanh*; cơ chế tách chi tiết **chưa chốt**, xem `OQ-011` |
| **RQ** | RQ-002 |
| **US áp dụng** | US-004 |
| **Khi vi phạm** | Chặn — không tạo được `Order` nếu không nhóm được `CartItem` theo `seller_id` hợp lệ |
| **Có ngoại lệ** | Chưa xác định — nếu PO xác nhận có ngoại lệ gộp seller (VD cùng kho vận), rule này phải viết lại hoàn toàn (xem `ASM-03`) |
| **Có thể đổi trong 1 năm** | Có — đây là quyết định thiết kế nghiệp vụ, không phải quy định pháp luật |
**Phát biểu:**
> Khi Customer/Guest xác nhận đặt hàng (checkout), hệ thống nhóm `CartItem` theo `seller_id`
> và tạo một `OrderSeller` (đơn con) riêng cho mỗi nhóm; `Order` (đơn cha) là tập hợp các
> `OrderSeller` con, mỗi `OrderSeller` có vòng đời trạng thái độc lập (xem §3).
**Điều kiện áp dụng:** Áp dụng cho mọi giỏ hàng có ≥1 sản phẩm hợp lệ (đủ tồn kho theo
`BR-CART-02`) tại thời điểm checkout, không phân biệt Customer hay Guest.
**Ví dụ đúng / sai:**
| Trường hợp | Dữ liệu | Kết quả mong đợi |
|---|---|---|
| Hợp lệ | Giỏ có 2 sản phẩm của seller A, 1 sản phẩm của seller B | Tạo 1 `Order` + 2 `OrderSeller` (A, B) |
| Biên | Giỏ có sản phẩm của 1 seller duy nhất | Tạo 1 `Order` + 1 `OrderSeller` — vẫn đúng cấu trúc cha-con dù chỉ 1 con |
| Chưa xác định | Hai seller cùng thuộc một kho vận trung tâm (nếu có mô hình này trong tương lai) | **Chưa có quy tắc — `OQ-011`, không tự giả định là gộp hay không gộp** |
---
### BR-CART-02 — Giữ tồn kho khi checkout (chống oversell)
| | |
|---|---|
| **Loại** | Điều kiện hành động |
| **Nguồn** | 🟠 Chính sách vận hành (bảo vệ trải nghiệm khách + quyền lợi seller khỏi bán vượt tồn kho); cơ chế kỹ thuật tham khảo SAD §6.4 BR-02, cần Tech Lead xác nhận khả thi |
| **Người chốt** | *(chưa có Tech Lead thật xác nhận — xem ngoại lệ gate)* |
| **RQ** | RQ-001, RQ-002 |
| **US áp dụng** | US-004 |
| **Khi vi phạm** | Chặn — trả lỗi, không tạo `Order`, giữ nguyên giỏ hàng để khách điều chỉnh |
| **Có ngoại lệ** | Không |
| **Có thể đổi trong 1 năm** | Có — là quyết định vận hành, có thể tinh chỉnh ngưỡng/cơ chế khi có dữ liệu tải thật |
**Phát biểu:**
> Tại thời điểm checkout, hệ thống phải kiểm tra tồn kho khả dụng cho từng sản phẩm trong
> giỏ hàng; nếu bất kỳ sản phẩm nào không đủ số lượng yêu cầu, hệ thống chặn việc tạo đơn và
> báo lỗi thay vì tạo đơn với số lượng vượt tồn kho thực có.
**Điều kiện áp dụng:** Áp dụng cho mọi lần `POST /checkout` (theo tên gọi tham chiếu SAD),
không phân biệt Customer/Guest, không phân biệt phương thức thanh toán.
**Ví dụ đúng / sai:**
| Trường hợp | Dữ liệu | Kết quả mong đợi |
|---|---|---|
| Hợp lệ | Tồn kho khả dụng 10, khách mua 3 | Cho qua, tạo đơn |
| Vi phạm | Tồn kho khả dụng 2, khách mua 3 | Chặn, báo lỗi mã `E-CART-0001` *(mã cụ thể — GĐ3 xác nhận)* |
| Biên | Tồn kho khả dụng đúng bằng số lượng yêu cầu | Cho qua (biên `>=`, không phải `>`) |
---
### BR-CART-03 — Giới hạn giá trị đơn hàng thanh toán COD
| | |
|---|---|
| **Loại** | Điều kiện hành động |
| **Nguồn** | 🟠 Chính sách rủi ro tài chính (đề xuất, chưa có chính sách chính thức) |
| **Người chốt** | ☐ **Chưa chốt** — xem `OQ-006` |
| **RQ** | RQ-003 |
| **US áp dụng** | US-007 |
| **Khi vi phạm** | *(Chưa xác định — phụ thuộc phương án PO chọn)* |
| **Có ngoại lệ** | *(Chưa xác định)* |
| **Có thể đổi trong 1 năm** | Có |
**Phát biểu:**
> 🔴 **Chưa có phát biểu chính thức.** `ASM-05` (GĐ1) giả định "COD không có giới hạn giá trị
> đơn ở MVP", nhưng `RISK-01` (🔴 mức cao) cảnh báo hệ quả nếu giả định này sai: seller chịu
> phí hoàn hàng khi khách từ chối một phần đơn COD đa seller. BA **không tự đặt một con số**
> (VD "giới hạn 5.000.000đ") vì đây là quyết định tài chính/rủi ro, phải do PO quyết — xem
> `OQ-006`.
**Điều kiện áp dụng:** *(Chưa xác định — chờ PO chọn 1 trong 2 phương án dưới)*
**Hai phương án BA đề xuất cho PO chọn (theo `RISK-01`):**
| Phương án | Mô tả | Ưu điểm | Nhược điểm |
|---|---|---|---|
| (a) Giới hạn giá trị | Đặt ngưỡng tối đa cho tổng giá trị đơn COD đa seller — vượt ngưỡng phải chọn thanh toán trước | Đơn giản, dễ thực hiện | Cần chốt con số cụ thể, có thể chặn nhầm khách hàng hợp lệ giá trị cao |
| (b) Xác thực bổ sung | Yêu cầu OTP/đặt cọc cho đơn COD giá trị cao | Không chặn hoàn toàn, chỉ tăng ma sát ở đơn rủi ro | Phức tạp hơn kỹ thuật, cần tích hợp OTP |
**Ví dụ đúng / sai:** *(chưa viết được — phụ thuộc phương án PO chọn)*
---
### BR-CART-04 — Điều kiện chọn phương thức thanh toán
| | |
|---|---|
| **Loại** | Điều kiện hành động |
| **Nguồn** | 🟠 Quyết định sản phẩm đã chốt (đối tác thanh toán mặc định VNPay/Momo/COD) |
| **Người chốt** | STK-01 (PO sàn), qua `00-project-brief.md` vòng 1 |
| **RQ** | RQ-003 |
| **US áp dụng** | US-007, US-008 |
| **Khi vi phạm** | Chặn — không cho tiếp tục checkout nếu chưa chọn phương thức |
| **Có ngoại lệ** | Không |
| **Có thể đổi trong 1 năm** | Có |
**Phát biểu:**
> Customer và Guest đều được chọn một trong ba phương thức thanh toán: VNPay, Momo, hoặc COD,
> cho mọi đơn hàng trong phạm vi module này — không có ràng buộc phân biệt theo vai trò ở mức
> GĐ2 (GĐ3 xác nhận lại nếu phát sinh ràng buộc theo khu vực địa lý/giá trị đơn).
**Điều kiện áp dụng:** Áp dụng tại bước B6 (`PROCESS_CartCheckout_v1.0.md`), sau khi `Order`/
`OrderSeller` đã được tạo (BR-CART-01).
**Ví dụ đúng / sai:**
| Trường hợp | Dữ liệu | Kết quả mong đợi |
|---|---|---|
| Hợp lệ | Guest chọn COD | Cho qua |
| Hợp lệ | Customer chọn VNPay | Cho qua |
| Vi phạm | Không chọn phương thức nào, bấm tiếp tục | Chặn, báo lỗi bắt buộc chọn |
---
### BR-CART-05 — Không lưu trữ thông tin thẻ thanh toán
| | |
|---|---|
| **Loại** | Ràng buộc dữ liệu |
| **Nguồn** | 🔴 Tuân thủ pháp lý — phạm vi PCI-DSS thu hẹp, `NFR-05` (`e-commerce/docs/sections/02-phan-tich-yeu-cau.md`) |
| **Người chốt** | STK-01 (PO sàn) + yêu cầu kỹ thuật/pháp lý đã chốt ở cấp dự án |
| **RQ** | RQ-003 |
| **US áp dụng** | US-008 |
| **Khi vi phạm** | Chặn — về mặt thiết kế, hệ thống sàn không được có trường lưu số thẻ/CVV ở bất kỳ đâu trong phạm vi module này |
| **Có ngoại lệ** | Không |
| **Có thể đổi trong 1 năm** | Không — đây là ràng buộc pháp lý/hợp đồng với đối tác thanh toán, không tự ý thay đổi |
**Phát biểu:**
> Hệ thống sàn không được lưu trữ số thẻ thanh toán, mã CVV, hoặc bất kỳ dữ liệu thẻ nhạy cảm
> nào; mọi xử lý thẻ do VNPay/Momo thực hiện, hệ thống sàn chỉ lưu tham chiếu giao dịch
> (`gateway_transaction_ref`) và kết quả (thành công/thất bại).
**Điều kiện áp dụng:** Áp dụng cho toàn bộ luồng thanh toán VNPay/Momo (US-008). Không áp dụng
cho COD (không có dữ liệu thẻ).
**Ví dụ đúng / sai:**
| Trường hợp | Dữ liệu | Kết quả mong đợi |
|---|---|---|
| Hợp lệ | Hệ thống chỉ lưu `gateway_transaction_ref`, `status`, `amount` | Đúng thiết kế |
| Vi phạm | Bất kỳ trường nào lưu số thẻ/CVV | Vi phạm nghiêm trọng — chặn ở review thiết kế GĐ3, không chờ tới UAT |
---
### BR-CART-06 — Xác thực webhook xác nhận thanh toán
| | |
|---|---|
| **Loại** | Điều kiện hành động (kỹ thuật, ảnh hưởng nghiệp vụ) |
| **Nguồn** | 🟢 Đề xuất kỹ thuật, cần Tech Lead xác nhận khả thi (`ASM-01` chưa xác minh) |
| **Người chốt** | ☐ **Chưa chốt** — xem `OQ-010` |
| **RQ** | RQ-003 |
| **US áp dụng** | US-008 |
| **Khi vi phạm** | Chặn — webhook không hợp lệ (chữ ký sai/quá hạn) thì không được cập nhật `Payment.status` |
| **Có ngoại lệ** | Không |
| **Có thể đổi trong 1 năm** | Có — là cơ chế kỹ thuật, có thể đổi nếu VNPay/Momo đổi API |
**Phát biểu:**
> Hệ thống chỉ chấp nhận cập nhật `Payment.status = success` khi nhận được webhook có chữ ký
> hợp lệ từ VNPay/Momo **và** trong khoảng thời gian hợp lệ kể từ khi giao dịch được khởi tạo
> — 🔴 **con số cụ thể (bao nhiêu phút) chưa được PO/Tech Lead chốt cho module này**, chỉ có
> giả định kỹ thuật tham khảo (không phải quyết định BA) ở tài liệu SAD.
**Điều kiện áp dụng:** Áp dụng cho US-008 (VNPay/Momo). Không áp dụng cho COD (US-007, không
có webhook).
**Ví dụ đúng / sai:**
| Trường hợp | Dữ liệu | Kết quả mong đợi |
|---|---|---|
| Hợp lệ | Webhook có chữ ký đúng, trong hạn | Cập nhật `Payment.status = success` |
| Vi phạm | Chữ ký sai | Từ chối, không cập nhật, ghi log |
| Chưa xác định | Webhook không tới trong thời gian chờ | Xem `PROCESS` B9 — cần cơ chế đối soát bù, ngoài phạm vi US module này |
---
### BR-CART-07 — Điều kiện tối thiểu cho Guest checkout
| | |
|---|---|
| **Loại** | Điều kiện hành động |
| **Nguồn** | 🟠 Quyết định sản phẩm đã chốt (Guest checkout được xác nhận ở cấp dự án) |
| **Người chốt** | STK-01 (PO sàn), qua `sections/01-tong-quan.md` §1.2 |
| **RQ** | RQ-004 |
| **US áp dụng** | US-006 |
| **Khi vi phạm** | Chặn — thiếu thông tin liên hệ tối thiểu thì không cho xác nhận đặt hàng |
| **Có ngoại lệ** | Không |
| **Có thể đổi trong 1 năm** | Có |
**Phát biểu:**
> Guest phải cung cấp tối thiểu thông tin liên hệ và địa chỉ giao hàng để hoàn tất checkout mà
> không cần tạo tài khoản (không cần mật khẩu) — 🔴 **danh sách field bắt buộc cụ thể (họ tên,
> số điện thoại, email có bắt buộc không) chưa được chốt ở mức GĐ2**, để GĐ3 làm bảng field
> đầy đủ khi có thiết kế màn hình.
**Điều kiện áp dụng:** Áp dụng cho toàn bộ luồng checkout khi `customer_id = null` (Guest).
**Ví dụ đúng / sai:**
| Trường hợp | Dữ liệu | Kết quả mong đợi |
|---|---|---|
| Hợp lệ | Guest điền đủ trường bắt buộc (danh sách — GĐ3 xác nhận) | Cho qua |
| Vi phạm | Thiếu trường bắt buộc | Chặn, báo lỗi field cụ thể (GĐ3) |
## 2. Bảng tổng hợp
| ID | Tên | Loại | Nguồn | US áp dụng | Khi vi phạm | Mã lỗi (GĐ3) |
|---|---|---|---|---|---|---|
| BR-CART-01 | Tách đơn theo seller | Quy trình/Tính toán | 🟠 (cơ chế chi tiết chưa chốt — `OQ-011`) | US-004 | Chặn | E-CART-00nn |
| BR-CART-02 | Giữ tồn kho khi checkout | Điều kiện hành động | 🟠 | US-004 | Chặn | E-CART-0001 |
| BR-CART-03 | Giới hạn giá trị đơn COD | Điều kiện hành động | ☐ Chưa chốt — `OQ-006` | US-007 | *(chưa xác định)* | *(chưa xác định)* |
| BR-CART-04 | Điều kiện chọn phương thức thanh toán | Điều kiện hành động | 🟠 | US-007, US-008 | Chặn | E-CART-00nn |
| BR-CART-05 | Không lưu thông tin thẻ | Ràng buộc dữ liệu | 🔴 | US-008 | Chặn (thiết kế) | N/A — chặn ở review thiết kế |
| BR-CART-06 | Xác thực webhook thanh toán | Điều kiện hành động | 🟢 (chưa chốt — `OQ-010`) | US-008 | Chặn | E-CART-00nn |
| BR-CART-07 | Điều kiện tối thiểu Guest checkout | Điều kiện hành động | 🟠 (field cụ thể — GĐ3) | US-006 | Chặn | E-CART-00nn |
## 3. Vòng đời trạng thái
*Bắt buộc với mọi thực thể có trạng thái (quy tắc W6). Ba thực thể có trạng thái trong phạm vi
module này: `CART`, `ORDER_SELLER` (chỉ đoạn khởi tạo — phần sau thuộc module khác), `PAYMENT`.*
### Thực thể: `CART`
**Bốn câu phải trả lời:**
| Câu hỏi | Trả lời |
|---|---|
| Trạng thái khởi tạo | `active` (Đang hoạt động) |
| Trạng thái cuối (không đi tiếp được) | `converted` (Đã chuyển thành đơn) hoặc `abandoned` (Bỏ quên) |
| Từ trạng thái cuối quay lại được không | Không — giỏ hàng mới phải được tạo lại |
| Trạng thái nào cho phép xoá | Chỉ `active` — Customer/Guest được xoá từng `CartItem`, không "xoá" bản ghi `Cart` (chỉ chuyển trạng thái) |
**Sơ đồ:**
```mermaid
stateDiagram-v2
state "Đang hoạt động" as Active
state "Đã chuyển thành đơn" as Converted
state "Bỏ quên" as Abandoned
[*] --> Active
Active --> Converted: Checkout thành công (BR-CART-01, BR-CART-02)
Active --> Abandoned: Hết hạn phiên (tự động, hệ thống)
Converted --> [*]
Abandoned --> [*]
```
**Bảng chuyển trạng thái:**
| # | Nguồn | Sự kiện | Điều kiện | Đích | Ai được làm | BR | Ghi vết |
|---|---|---|---|---|---|---|---|
| 1 | Active | Checkout | Đủ tồn kho tất cả item (BR-CART-02) | Converted | Customer/Guest | BR-CART-01, BR-CART-02 | ✅ (thông qua `Order` được tạo) |
| 2 | Active | Hết hạn phiên | Thời hạn cụ thể — **chưa chốt ở GĐ2, tham khảo kỹ thuật SAD §5.3.1 (Guest 7 ngày/Customer 30 ngày), cần Tech Lead xác nhận áp dụng đúng con số này** | Abandoned | Hệ thống (tự động) | — | ➖ Không ghi vết chi tiết (chấp nhận mất theo thiết kế kỹ thuật tham khảo) |
**Chuyển trạng thái KHÔNG được phép:**
| Từ | Sang | Vì sao cấm |
|---|---|---|
| Converted | Active | Mất dấu vết đơn đã tạo — giỏ đã chuyển thành đơn không thể "mở lại" để sửa tiếp |
| Abandoned | Converted | Giỏ đã hết hạn — khách phải thêm lại sản phẩm vào giỏ mới, không checkout trực tiếp từ giỏ bỏ quên |
### Thực thể: `ORDER_SELLER` *(chỉ đoạn khởi tạo trong phạm vi module này)*
🔴 Vòng đời đầy đủ của `OrderSeller` (packed/shipped/delivered/returned…) thuộc module Quản lý
đơn hàng (FR-08/FR-19, ngoài phạm vi RQ-001…004). Phần dưới đây **chỉ mô tả đoạn khởi tạo** mà
module Giỏ hàng & Checkout chịu trách nhiệm, để BA GĐ3 của module kế tiếp kế thừa đúng điểm nối.
**Bốn câu phải trả lời (trong phạm vi module này):**
| Câu hỏi | Trả lời |
|---|---|
| Trạng thái khởi tạo | `pending` (Chờ thanh toán) |
| Trạng thái cuối (trong phạm vi module này) | `confirmed` (Đã xác nhận — bàn giao module khác) hoặc `cancelled` (Đã huỷ) |
| Từ trạng thái cuối quay lại được không | Không, trong phạm vi module này (huỷ sau `confirmed` là nghiệp vụ FR-08, ngoài phạm vi) |
| Trạng thái nào cho phép xoá | Không — không cho phép xoá `OrderSeller`, chỉ chuyển trạng thái (bắt buộc giữ dấu vết tài chính/đối soát) |
**Sơ đồ:**
```mermaid
stateDiagram-v2
state "Chờ thanh toán" as Pending
state "Đã xác nhận" as Confirmed
state "Đã huỷ" as Cancelled
[*] --> Pending: Checkout tạo đơn con (BR-CART-01)
Pending --> Confirmed: Thanh toán thành công (COD hoặc webhook VNPay/Momo — BR-CART-06)
Pending --> Cancelled: Thanh toán thất bại/hết hạn chờ, hoặc khách huỷ trước khi thanh toán
Confirmed --> [*]: Bàn giao module Quản lý đơn hàng seller (FR-19, ngoài phạm vi)
Cancelled --> [*]
```
**Bảng chuyển trạng thái:**
| # | Nguồn | Sự kiện | Điều kiện | Đích | Ai được làm | BR | Ghi vết |
|---|---|---|---|---|---|---|---|
| 1 | Pending | Thanh toán COD | Đơn không vượt giới hạn COD (nếu `BR-CART-03` được chốt) | Confirmed | Hệ thống (tự động khi US-007 xác nhận) | BR-CART-03 (chưa chốt), BR-CART-04 | ✅ |
| 2 | Pending | Webhook thanh toán thành công | Webhook hợp lệ (BR-CART-06) | Confirmed | Hệ thống (tự động) | BR-CART-06 | ✅ |
| 3 | Pending | Thanh toán thất bại / hết hạn chờ | *(Thời hạn chờ cụ thể — chưa chốt, ngoài phạm vi US module này, xem `PROCESS` B9)* | Cancelled | Hệ thống (tự động) | — | ✅ |
**Chuyển trạng thái KHÔNG được phép:**
| Từ | Sang | Vì sao cấm |
|---|---|---|
| Confirmed | Pending | Mất dấu vết đơn đã xác nhận thanh toán — ảnh hưởng đối soát tài chính |
| Cancelled | Confirmed | Đơn đã huỷ không thể tự khôi phục — khách phải đặt lại từ đầu |
### Thực thể: `PAYMENT`
**Bốn câu phải trả lời:**
| Câu hỏi | Trả lời |
|---|---|
| Trạng thái khởi tạo | `pending` |
| Trạng thái cuối | `success` hoặc `failed` *(trong phạm vi module này — `refunded` thuộc FR-25, ngoài phạm vi)* |
| Từ trạng thái cuối quay lại được không | Không, trong phạm vi module này |
| Trạng thái nào cho phép xoá | Không — bản ghi thanh toán không bao giờ bị xoá (bắt buộc giữ cho đối soát/kiểm toán) |
**Sơ đồ:**
```mermaid
stateDiagram-v2
state "Chờ xử lý" as Pending
state "Thành công" as Success
state "Thất bại" as Failed
[*] --> Pending: Khởi tạo thanh toán (US-007/US-008)
Pending --> Success: COD xác nhận / webhook VNPay-Momo hợp lệ (BR-CART-06)
Pending --> Failed: Webhook báo lỗi / hết hạn chờ (cơ chế cụ thể ngoài phạm vi US module này)
Success --> [*]
Failed --> [*]
```
**Bảng chuyển trạng thái:**
| # | Nguồn | Sự kiện | Điều kiện | Đích | Ai được làm | BR | Ghi vết |
|---|---|---|---|---|---|---|---|
| 1 | Pending | Xác nhận COD | 🔴 **Chưa chốt — `Payment.status` của COD ghi `success` ngay hay giữ `pending` tới khi thực thu? Xem `OQ-013`** | Success (giả định, chưa chốt) | Hệ thống | *(chưa xác định)* | ✅ |
| 2 | Pending | Webhook VNPay/Momo thành công | Chữ ký hợp lệ, trong hạn (BR-CART-06) | Success | Hệ thống | BR-CART-06 | ✅ |
| 3 | Pending | Webhook báo lỗi/hết hạn | *(cơ chế cụ thể — ngoài phạm vi US module này)* | Failed | Hệ thống | — | ✅ |
**Chuyển trạng thái KHÔNG được phép:**
| Từ | Sang | Vì sao cấm |
|---|---|---|
| Success | Pending | Mất dấu vết giao dịch đã ghi nhận thành công — sai lệch đối soát |
| Failed | Success | Không tự động — nếu cần xử lý lại phải tạo bản ghi `Payment` mới, không sửa bản ghi cũ |
## 4. Mô hình dữ liệu khái niệm (ERD)
🔴 **Mục bắt buộc vì US-004 chạm ≥2 thực thể.** Mô hình khái niệm — không kiểu dữ liệu vật lý,
không index, không bảng trung gian (đó là việc của Solution Architect/dev; tham chiếu
`e-commerce/docs/sections/05-thiet-ke-du-lieu.md` §5.2.3–5.2.4 chỉ để đối chiếu tên thực thể,
không chép nguyên cấu trúc bảng).
```mermaid
erDiagram
CUSTOMER ||--o{ CART : "sở hữu (nếu đăng nhập)"
CART ||--o{ CART_ITEM : "chứa"
CART_ITEM }o--|| PRODUCT_VARIANT : "tham chiếu"
CART_ITEM }o--|| SELLER : "thuộc về"
CUSTOMER ||--o{ ORDER : "đặt (nếu đăng nhập)"
ORDER ||--o{ ORDER_SELLER : "tách thành"
ORDER ||--o| PAYMENT : "thanh toán bởi"
ORDER_SELLER ||--o{ ORDER_ITEM : "chứa"
ORDER_SELLER }o--|| SELLER : "thuộc về"
ORDER_ITEM }o--|| PRODUCT_VARIANT : "tham chiếu"
CART {
string id PK "khoá kỹ thuật"
string customer_id FK "nullable — null nếu Guest"
string session_id "định danh phiên — dùng khi Guest"
enum status "active/converted/abandoned — xem BR §3"
}
CART_ITEM {
string id PK
string cart_id FK
string product_variant_id FK
string seller_id FK
int quantity "> 0"
}
ORDER {
string id PK
string customer_id FK "nullable — Guest checkout (RQ-004)"
string order_number "khoá nghiệp vụ, duy nhất, dễ đọc"
decimal total_amount "VND — tổng các OrderSeller con"
enum status "pending_payment/… — dẫn xuất từ trạng thái các OrderSeller con, chi tiết ở module khác"
}
ORDER_SELLER {
string id PK
string order_id FK
string seller_id FK
string sub_order_number "khoá nghiệp vụ, duy nhất"
decimal subtotal_amount "VND"
enum status "pending/confirmed/cancelled — xem BR §3 (đoạn khởi tạo)"
}
ORDER_ITEM {
string id PK
string order_seller_id FK
string product_variant_id FK
int quantity
decimal unit_price "VND, snapshot tại thời điểm đặt hàng"
}
PAYMENT {
string id PK
string order_id FK
enum method "vnpay/momo/cod — BR-CART-04"
decimal amount "VND"
enum status "pending/success/failed — xem BR §3"
}
```
*Ký hiệu lực lượng: `||--o{` một-nhiều · `||--o|` một-không hoặc một · `}o--||` nhiều-một.*
### 4.1 Bảng thực thể
| Thực thể | Tên nghiệp vụ | Khoá nghiệp vụ | Số bản ghi hiện có | Ai tạo | Vòng đời | BR |
|---|---|---|---|---|---|---|
| `CART` | Giỏ hàng | *(id kỹ thuật — chưa có khoá nghiệp vụ do khách hàng nhận biết; `customer_id`/`session_id` là khoá truy vấn, không phải khoá nghiệp vụ theo nghĩa người dùng gõ ra)* | 0 — greenfield | Customer/Guest (US-001) | §3 `CART` | BR-CART-01, BR-CART-02 |
| `CART_ITEM` | Dòng sản phẩm trong giỏ | `(cart_id, product_variant_id)` | 0 | Customer/Guest | Theo `CART` cha | — |
| `ORDER` | Đơn hàng (cha) | `order_number` | 0 | Hệ thống, khi checkout (US-004) | Dẫn xuất từ `ORDER_SELLER` con | BR-CART-01 |
| `ORDER_SELLER` | Đơn hàng con theo seller | `sub_order_number` | 0 | Hệ thống, khi checkout (US-004) | §3 `ORDER_SELLER` (đoạn khởi tạo) | BR-CART-01, BR-CART-02 |
| `ORDER_ITEM` | Dòng sản phẩm trong đơn con | *(id kỹ thuật, không có khoá nghiệp vụ riêng — thuộc về `ORDER_SELLER`)* | 0 | Hệ thống, khi checkout | Theo `ORDER_SELLER` cha | — |
| `PAYMENT` | Giao dịch thanh toán | `gateway_transaction_ref` *(chỉ có với VNPay/Momo — COD chưa rõ khoá nghiệp vụ tương đương, xem `OQ-013`)* | 0 | Hệ thống, khi US-007/US-008 | §3 `PAYMENT` | BR-CART-03…06 |
**Khoá nghiệp vụ** là thứ người dùng dùng để nhận biết — `order_number`/`sub_order_number` là
mã đơn hàng khách/seller nhìn thấy và trao đổi (VD tra cứu, khiếu nại), khác với `id` kỹ thuật.
### 4.2 Quan hệ cần làm rõ
| Quan hệ | Xoá bên "một" thì bên "nhiều" ra sao | Bắt buộc có quan hệ? | Đổi được sang bên khác? | BR |
|---|---|---|---|---|
| `CART` → `CART_ITEM` | Không áp dụng "xoá" `CART` — chỉ chuyển trạng thái (§3); xoá `CART_ITEM` riêng lẻ là hành vi hợp lệ (US-003) | ✅ mỗi `CART_ITEM` luôn thuộc đúng 1 `CART` | ❌ | — |
| `ORDER` → `ORDER_SELLER` | Không áp dụng "xoá" `ORDER` (bắt buộc giữ dấu vết tài chính) | ✅ mỗi `ORDER_SELLER` luôn thuộc đúng 1 `ORDER` cha | ❌ | BR-CART-01 |
| `ORDER_SELLER` → `ORDER_ITEM` | Không áp dụng "xoá" | ✅ | ❌ | BR-CART-01 |
| `ORDER` → `PAYMENT` | Không áp dụng "xoá" | 🔶 một `ORDER` có 0 hoặc 1 `PAYMENT` tại một thời điểm — **trường hợp đổi phương thức thanh toán giữa chừng (huỷ Payment cũ, tạo Payment mới) chưa được chốt, xem `OQ` mới nếu phát sinh ở GĐ3** | 🔶 xem trên | BR-CART-04 |
### 4.3 Thực thể ngoài phạm vi
*Thực thể có nhắc tới nhưng do module/service khác sở hữu — nêu rõ để không ai định tạo bảng
cho nó trong phạm vi module Giỏ hàng & Checkout.*
| Thực thể | Ai sở hữu | Lấy về bằng cách nào | Cache không |
|---|---|---|---|
| `CUSTOMER` | Module Tài khoản (FR-01/FR-03, Identity & Access) | Tham chiếu qua `customer_id` (FK logic) | Không cache PII ngoài những trường cần thiết cho hiển thị checkout (địa chỉ, tên người nhận) — chi tiết mã hoá/cache thuộc Tech Lead/GĐ3 |
| `SELLER` | Module Quản trị Seller (FR-17/FR-23) | Tham chiếu qua `seller_id` (FK logic) | Cache tên hiển thị seller cho màn hình giỏ hàng — không cache dữ liệu KYC/tài chính của seller |
| `PRODUCT_VARIANT` | Module Catalog & Tìm kiếm (FR-04/FR-18) | Tham chiếu qua `product_variant_id`; giá được snapshot vào `CART_ITEM`/`ORDER_ITEM` tại thời điểm thêm giỏ/đặt hàng (xem `ASM-06`, `OQ-009`) | Có — snapshot giá tại thời điểm thêm giỏ, cần đối chiếu lại khi checkout (US-004) |
## 5. Công thức tính toán
| ID | Đại lượng | Công thức | Đơn vị | Làm tròn | Nguồn dữ liệu | Ví dụ |
|---|---|---|---|---|---|---|
| BR-CART-08 | Tổng tiền một `OrderSeller` | Σ (`ORDER_ITEM.quantity × ORDER_ITEM.unit_price`) — **chưa chốt có gồm phí vận chuyển ước tính (US-005) hay không** | VND | Chưa chốt — **cần OQ mới ở GĐ3 nếu phát sinh** | `ORDER_ITEM` | *(chưa có ví dụ số cụ thể — chờ chốt có gồm phí ship không)* |
| BR-CART-09 | Tổng tiền `Order` (cha) | Σ (`ORDER_SELLER.subtotal_amount`) | VND | Không làm tròn thêm (đã làm tròn ở từng `OrderSeller`) | `ORDER_SELLER` | Đơn A: 250.000đ + Đơn B: 180.000đ = 430.000đ |
🔴 BR-CART-08 **chưa chốt được** vì phụ thuộc: (a) phí vận chuyển có tính vào `subtotal_amount`
hay tách riêng một trường phí ship, và (b) coupon/điểm thưởng (module khác, `OQ-004`/`DEC-03`)
áp giảm giá ở cấp `Order` hay từng `OrderSeller`. Đây là khoảng trống thật cần Tech Lead + PO
xác nhận trước khi viết `AC` ở GĐ3 — không tự chọn cách tính.
## 6. Kiểm tra mâu thuẫn giữa các rule
*Đối chiếu từng cặp rule cùng tác động lên một thực thể (`ORDER_SELLER`, `PAYMENT`).*
| # | Rule A | Rule B | Mâu thuẫn ở đâu | Trạng thái |
|---|---|---|---|---|
| 1 | BR-CART-02 (giữ tồn kho, chặn nếu thiếu) | BR-CART-01 (tách đơn theo seller) | Không mâu thuẫn trực tiếp — BR-CART-02 chạy **trước** BR-CART-01 trong luồng (xem `PROCESS` B1 sơ đồ: kiểm tra tồn kho ở D1 trước khi tách đơn ở B5) | ✅ Không mâu thuẫn — đã xác nhận thứ tự |
| 2 | BR-CART-03 (giới hạn COD, chưa chốt) | BR-CART-04 (mọi phương thức đều được chọn tự do) | Nếu PO chốt BR-CART-03 theo phương án (a) giới hạn giá trị, nó sẽ **thu hẹp** BR-CART-04 (không còn "tự do chọn mọi phương thức" cho đơn giá trị cao) — cần cập nhật BR-CART-04 khi BR-CART-03 chốt | 🔴 Chờ PO quyết — `OQ-006` |
| 3 | BR-CART-06 (chặn khi webhook không hợp lệ/quá hạn) | Nhu cầu trải nghiệm khách "biết ngay kết quả thanh toán" (`RISK-02`) | Nếu thời gian chờ webhook quá dài, khách không biết đơn có được xác nhận hay không — không phải mâu thuẫn giữa hai rule mà là **khoảng trống thiết kế** (cơ chế đối soát bù) chưa có rule nào lấp — xem `PROCESS` B9, ngoài phạm vi US module này | 🟠 Ghi nhận là khoảng trống, không phải mâu thuẫn rule-rule |
**Kết luận:** không phát hiện mâu thuẫn rule-rule nghiêm trọng trong phạm vi các rule **đã chốt
được nội dung**. Mâu thuẫn tiềm ẩn ở dòng #2 phụ thuộc hoàn toàn vào việc PO trả lời `OQ-006`.
## 7. Rule của hệ thống hiện tại bị thay đổi
*Không áp dụng — `LIFECYCLE = greenfield`, không có hệ thống/rule cũ nào bị thay đổi bởi module
này (xác nhận F7, `ELICITATION_CartCheckout_2026-09-08.md`).*
## 8. Open Questions
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì |
|---|---|---|---|---|
| OQ-006 | *(GĐ1, nhắc lại)* Giới hạn giá trị đơn COD là gì? | PO, Kế toán đối soát | 2026-09-08 | `BR-CART-03` |
| OQ-010 | Xác nhận khả thi `ASM-01` (webhook VNPay/Momo) | Tech Lead | 2026-09-08 | `BR-CART-06` |
| OQ-011 | Xác nhận `ASM-03` — giỏ N seller luôn tách đúng N đơn, không gộp | PO | 2026-09-08 | `BR-CART-01` |
| OQ-013 | `Payment.status` của COD ghi "success" ngay hay giữ "pending" tới khi thực thu? | Kế toán đối soát, PO | 2026-09-08 | `PAYMENT` §3 bảng chuyển #1 |
| *(mới)* OQ-014 | `Order.total_amount`/`OrderSeller.subtotal_amount` có gồm phí vận chuyển ước tính (US-005) không? Coupon/điểm thưởng áp giảm giá ở cấp `Order` hay từng `OrderSeller`? | PO, Tech Lead | 2026-09-08 | BR-CART-08/09, US-005, `AC` ở GĐ3 |
## 9. Ngoài phạm vi
- Thông điệp lỗi hiển thị nguyên văn (VD nội dung `E-CART-0001`) → GĐ3 `SRS` §bảng mã lỗi
- Ai được thực hiện hành động → `RBAC_CartCheckout_v1.0.md`
- Công thức tính hoa hồng, payout, điểm loyalty (BR-03…BR-08 ở SAD) → module Commission &
Payout / Promotion & Loyalty, ngoài phạm vi module này
- Cơ chế đối soát bù thanh toán chi tiết (reconciliation job) → thiết kế kỹ thuật GĐ3 của
module Thanh toán