# 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