# AC — Acceptance Criteria — US-003 Sửa số lượng / xoá sản phẩm trong giỏ hàng | | | |---|---| | **Version** | 1.0 | | **Date** | 2026-09-08 | | **Author** | BA (qua skill ba-3-specification) | | **Status** | 🟡 Draft | | **Approved by** | QA: — *(chưa có QA thật tham gia lần chạy này)* | | **Source** | `SRS_US002-003_v1.0.md` · `RBAC_CartCheckout_v1.0.md` §6 · `BR_CartCheckout_v1.0.md` §3 | | **Scope** | US-003 | ## Change Log | Version | Date | Người sửa | Thay đổi | CR | |---|---|---|---|---| | 1.0 | 2026-09-08 | BA (qua skill ba-3-specification) | Bản đầu — 13 AC, 4 nhóm (2 AC còn mở chờ `OQ-028`/`OQ-032`, ghi rõ thay vì bịa) | — | --- ## 1. Bốn nhóm bắt buộc | Nhóm | Nội dung | Tối thiểu | Số AC đã viết | |---|---|---|---| | 1. Luồng thành công | Tăng/giảm số lượng, xoá dòng, xoá nhóm, xoá giỏ, huỷ modal | 1/hành động | 6 | | 2. Validation | Số lượng không hợp lệ; số lượng về 0 | 1/rule | 2 (1 còn mở — `OQ-028`) | | 3. Lỗi hệ thống | 5xx cập nhật, timeout xoá, item bị xoá đồng thời | ≥1 | 3 | | 4. Phân quyền | Sửa/xoá CartItem không thuộc quyền sở hữu (Customer, Guest) | ≥1/vai trò | 2 (1 còn mở — `OQ-032`) | --- ## 2. Danh sách AC ### Nhóm 1 — Luồng thành công #### AC-US003-01 — Tăng số lượng CartItem thành công | | | |---|---| | **Liên quan** | SCR-04 · F01, C08, C09 | | **Vai trò** | ROLE-02 (tương tự ROLE-01) | ``` Given CartItem X có quantity=2, Cart.status=active When tôi bấm nút "+" (F01) để tăng số lượng lên 3 Then hệ thống gọi PATCH /v1/cart/items/{X} với quantity=3, nhận 200 OK And F01 hiển thị 3; tạm tính nhóm (C08) và tổng cộng (C09) cập nhật lại ngay theo giá trị mới ``` #### AC-US003-02 — Giảm số lượng CartItem thành công (còn ≥1) ``` Given CartItem X có quantity=3 When tôi bấm nút "-" (F01) để giảm còn 2 Then PATCH thành công, F01=2, C08/C09 cập nhật ``` #### AC-US003-03 — Xoá CartItem thành công (đã xác nhận modal) | | | |---|---| | **Liên quan** | SCR-04 · C07, C08, C09 | | **Vai trò** | ROLE-02 | ``` Given CartItem X tồn tại trong nhóm seller "Shop A" (nhóm đang có 2 CartItem) When tôi bấm "Xoá" (C07) trên CartItem X, modal xác nhận hiện ra (theo UICONV §5), tôi bấm nút xác nhận trong modal Then hệ thống gọi DELETE /v1/cart/items/{X}, nhận 200/204 And dòng CartItem X biến mất khỏi danh sách; tạm tính nhóm "Shop A" (C08) cập nhật (còn 1 CartItem); tổng cộng (C09) cập nhật ``` #### AC-US003-04 — Xoá CartItem cuối cùng của một nhóm seller ``` Given nhóm seller "Shop B" chỉ có 1 CartItem When tôi xoá CartItem đó (đã xác nhận modal) Then toàn bộ khối nhóm "Shop B" (C02 + dòng CartItem) biến mất khỏi màn hình — không hiển thị một nhóm rỗng không có dòng nào ``` #### AC-US003-05 — Xoá CartItem cuối cùng của toàn giỏ hàng ``` Given giỏ hàng chỉ còn duy nhất 1 CartItem (1 nhóm, 1 dòng) When tôi xoá CartItem đó (đã xác nhận modal) Then màn hình chuyển sang trạng thái "Giỏ hàng trống" (theo SRS §2.A.3.6); nút "Tiến hành Checkout" (C11) ẩn/disable And Cart.status vẫn là active (KHÔNG tự chuyển abandoned — theo BR §3, chỉ hết hạn phiên mới chuyển abandoned) ``` #### AC-US003-06 — Huỷ modal xác nhận xoá ``` Given modal xác nhận xoá CartItem X đang mở When tôi bấm nút huỷ hoặc đóng modal (không xác nhận) Then CartItem X vẫn còn nguyên trong danh sách; không có request DELETE nào được gửi ``` --- ### Nhóm 2 — Validation #### AC-US003-07 — Nhập số lượng không phải số nguyên dương hợp lệ | | | |---|---| | **Liên quan** | SCR-04 · F01 | | **Vai trò** | ROLE-02 | ``` Given CartItem X có quantity=2 When tôi nhập trực tiếp vào F01 giá trị không hợp lệ (VD "-1", "1.5", "abc", để trống) Then hệ thống hiện lỗi inline dưới F01: "Số lượng phải là số nguyên từ 1 trở lên." (E-CART-0002) And không gửi request PATCH; F01 giữ nguyên giá trị hợp lệ trước đó (không lưu giá trị lỗi) ``` #### AC-US003-08 — Giảm số lượng về 0 *(🔴 chưa viết được đầy đủ — chờ `OQ-028`)* ``` Given CartItem X có quantity=1 (đã ở mức tối thiểu) When tôi bấm nút "-" hoặc nhập trực tiếp "0" vào F01 Then 🔴 CHƯA XÁC ĐỊNH — phụ thuộc OQ-028 (PO chưa chốt: (a) chặn nút "-"/nhập 0, hiện thông báo giữ tối thiểu 1, hay (b) tự động mở modal xác nhận xoá dòng) ``` *QA không viết test case cho AC này cho tới khi `OQ-028` được trả lời — đây là chỗ SRS chưa viết xong, không phải QA bỏ sót.* --- ### Nhóm 3 — Lỗi hệ thống #### AC-US003-09 — Server lỗi 5xx khi cập nhật số lượng | | | |---|---| | **Liên quan** | SCR-04 · F01 | | **Vai trò** | ROLE-02 | ``` Given CartItem X có quantity=2 When tôi đổi thành 5 (bấm "+" 3 lần hoặc nhập tay) và PATCH /v1/cart/items/{X} trả 500 Then hệ thống hiện banner lỗi tại dòng CartItem: "Không thể cập nhật giỏ hàng, thử lại." (E-CART-0006) And 🔴 F01 trở về giá trị trước đó (2), KHÔNG giữ giá trị đã nhập lỗi (5); nút +/- mở lại được bấm ngay ``` #### AC-US003-10 — Timeout khi xoá CartItem ``` Given tôi bấm "Xoá" trên CartItem X (đã xác nhận modal) When request DELETE bị timeout theo ngưỡng NFR §1 (xem OQ-033) Then hệ thống hiện banner lỗi tại dòng: "Không thể cập nhật giỏ hàng, thử lại." (E-CART-0006) And CartItem X vẫn hiển thị trong danh sách (không xoá khỏi giao diện khi chưa có xác nhận từ server); nút "Xoá" bấm lại được ``` #### AC-US003-11 — CartItem đã bị xoá bởi thao tác khác (đồng thời, VD 2 tab) ``` Given CartItem X đang hiển thị trên màn hình của tôi, nhưng đã bị xoá khỏi giỏ hàng ở một tab/thiết bị khác trước đó When tôi bấm sửa số lượng (F01) hoặc bấm "Xoá" (C07) trên CartItem X Then PATCH/DELETE trả 404 ERR_NOT_FOUND hoặc 409 ERR_CONFLICT (xem API §4) And hệ thống hiện banner "Sản phẩm này đã được xoá khỏi giỏ hàng trước đó." (E-CART-0003), sau đó ẩn dòng CartItem X khỏi danh sách và cập nhật lại C08/C09 ``` Ba tình huống tối thiểu của nhóm này: | # | Tình huống | AC | |---|---|---| | 1 | Server trả 5xx | AC-US003-09 | | 2 | Timeout / mất mạng | AC-US003-10 | | 3 | Dữ liệu bị người khác sửa/xoá trong lúc mình đang mở | AC-US003-11 | --- ### Nhóm 4 — Phân quyền #### AC-US003-12 — Gọi thẳng API sửa/xoá CartItem không thuộc quyền sở hữu (Customer) | | | |---|---| | **Liên quan** | SCR-04 | | **Vai trò** | ROLE-02 | ``` Given tôi đăng nhập ROLE-02 với customerId = A; CartItem Y thuộc Cart của customerId = B When tôi gọi thẳng PATCH /v1/cart/items/{Y} với token của A Then hệ thống trả 403 ERR_FORBIDDEN_OWNERSHIP (E-CART-0005), không cập nhật CartItem Y And không có thông tin nào của CartItem Y bị lộ ra trong response lỗi ``` #### AC-US003-13 — Guest cố sửa/xoá CartItem không thuộc session của mình *(🔴 chưa viết được đầy đủ — chờ `OQ-032`)* ``` Given tương tự AC-US003-12 nhưng với ROLE-01 (Guest): X-Guest-Session-Id = S1 của tôi, CartItem Z thuộc Cart của session S2 When tôi gọi thẳng PATCH /v1/cart/items/{Z} với X-Guest-Session-Id: S1 Then 🔴 CHƯA XÁC ĐỊNH — đề xuất BA: trả 403 ERR_FORBIDDEN_OWNERSHIP (E-CART-0005) giống hệt AC-US003-12, cần Tech Lead xác nhận cơ chế đối chiếu session_id (OQ-032) trước khi coi AC này là chốt ``` 🔴 Chặn ở giao diện là trải nghiệm, **chặn ở backend mới là bảo mật**. Cả hai AC nhóm này đều kiểm tra gọi thẳng API, không chỉ kiểm tra ẩn nút trên giao diện. --- ## 3. Bảng dữ liệu biên | Field | Dưới ngưỡng | Ngưỡng dưới | Trong khoảng | Ngưỡng trên | Trên ngưỡng | Rỗng | Ký tự đặc biệt | Khoảng trắng đầu/cuối | |---|---|---|---|---|---|---|---|---| | F01 Số lượng (≥1, ngưỡng trên **chưa chốt** — `OQ-030`) | `0` → lỗi `E-CART-0002` (hành vi cụ thể — `OQ-028`) | `1` → OK | `5` → OK | 🔴 chưa có ngưỡng trên xác nhận — `OQ-030` | 🔴 chưa có ngưỡng trên — `OQ-030` | Xoá trắng ô nhập → lỗi bắt buộc (`E-CART-0002`) | `"abc"`, `"1.5"`, `"-1"` → lỗi `E-CART-0002` | N/A — F01 là input dạng số (`type=number`), không nhận khoảng trắng | --- ## 4. Kịch bản kết hợp | # | Kịch bản | Các bước | AC liên quan | |---|---|---|---| | S1 | Sửa số lượng rồi xoá hết một nhóm seller | SCR-04 (mở) → sửa số lượng CartItem của "Shop B" (tổng cập nhật) → xoá cả 2 CartItem còn lại của "Shop B" → nhóm "Shop B" biến mất, tổng cộng chỉ còn của "Shop A" | AC-US003-01, 03, 04 | --- ## 5. Truy vết | AC | US | BR | Field/Thành phần | Mã lỗi | Test case (QA điền) | Kết quả (QA điền) | |---|---|---|---|---|---|---| | AC-US003-01 | US-003 | BR §3 CART | F01, C08, C09 | — | | | | AC-US003-02 | US-003 | BR §3 CART | F01, C08, C09 | — | | | | AC-US003-03 | US-003 | BR §3 CART | C07, C08, C09 | — | | | | AC-US003-04 | US-003 | — | C02, C07 | — | | | | AC-US003-05 | US-003 | BR §3 CART | C07, C10, C11 | — | | | | AC-US003-06 | US-003 | — | C07 | — | | | | AC-US003-07 | US-003 | — | F01 | E-CART-0002 | | | | AC-US003-08 | US-003 | — | F01 | E-CART-0002 (dự kiến) | *(chờ OQ-028)* | | | AC-US003-09 | US-003 | — | F01 | E-CART-0006 | | | | AC-US003-10 | US-003 | — | C07 | E-CART-0006 | | | | AC-US003-11 | US-003 | — | F01, C07 | E-CART-0003 | | | | AC-US003-12 | US-003 | RBAC §6 | — | E-CART-0005 | | | | AC-US003-13 | US-003 | RBAC §6 | — | E-CART-0005 (dự kiến) | *(chờ OQ-032)* | | --- ## 6. Xác nhận của QA | | | |---|---| | **Người xác nhận** | *(chưa có — chưa có QA thật tham gia lần chạy này)* | | **Ngày** | — | | ☐ Mọi AC đều test được (2 AC còn mở, chờ OQ trước khi viết test case) | | | ☐ Đủ 4 nhóm | | | ☐ Bảng dữ liệu biên đủ dùng để viết test case | | | ☐ Không có AC nào mâu thuẫn với AC khác | | **AC bị QA từ chối:** | AC | Lý do từ chối | BA sửa thế nào | |---|---|---| | | | |