Skip to content

QA Test Plan — Báo cáo Đơn hàng Voucher/Quà tặng

Ref: PRD v1.0 | Date: 19/03/2026


D1) Test Scope

FRMô tảPriority
FR-001Tab mới hiển thị trong Revenue Report GroupMust
FR-002Summary Bar 4 metricsMust
FR-003Bảng dữ liệu 13 cột (STT + 12 data) + visual groupingMust
FR-004Filter 6 tiêu chí (cascading)Must
FR-005Export ExcelMust
FR-006Database indexes (performance)Must
FR-007Permission + Migration seedMust

D2) Test Cases

TC-FR-001: Tab hiển thị

TCMô tảInputExpectedPriority
TC-001-01Tab hiển thị khi có quyềnLogin Admin có quyền reportTab "Voucher/Quà tặng" hiển thị ở cuối Revenue Report GroupP0
TC-001-02Tab ẩn khi không có quyềnLogin Staff không có quyền reportTab không hiển thị (không có trong DOM)P0
TC-001-03Click tab → render đúng componentClick tab mớiVoucherGiftOrderReportFilter + VoucherGiftOrderReportTable renderP0
TC-001-04Các tab khác không bị ảnh hưởngClick qua lại giữa tab cũ và mớiData + filter reset đúng khi đổi tabP1

TC-FR-002: Summary Bar

TCMô tảInputExpectedPriority
TC-002-014 BoxInfo hiển thị đúngDate range có dữ liệu4 cards: lượt dùng (+ số đơn), giá trị giảm, thực thu, tỷ lệ giảmP0
TC-002-02Tỷ lệ giảm tính đúngGiảm=200.000đ, Thực thu=800.000đ200.000/(800.000+200.000)×100 = 20.0%P0
TC-002-03Mẫu số = 0Tất cả gift type "Lời chúc" (discount=0), paid=0Tỷ lệ giảm hiển thị "—"P1
TC-002-04Không tính đơn hủy (mặc định)10 đơn có voucher, 3 đã hủyTổng đơn = 7, không tính 3 đơn hủyP0
TC-002-05Loading stateTab vừa click4 BoxInfo hiện QSkeletonP1
TC-002-06Lượt dùng ≠ đơn hàng1 đơn có 3 items dùng voucher"3 lượt (1 đơn)"P0

TC-FR-003: Bảng dữ liệu

TCMô tảInputExpectedPriority
TC-003-0113 cột hiển thị đúngCó dữ liệu13 cột (STT + 12 cột data) với format đúngP0
TC-003-02Chỉ hiển thị items có voucher/giftorder_item không có gifted_id và voucher_discount_amount=0Không hiển thị item đóP0
TC-003-03Chỉ hiển thị đơn service/cosmetic/prepaidĐơn order_transfer có voucherKhông hiển thị (DEC-008)P0
TC-003-04Pagination 20 items/page50 order_items có voucherTrang 1: 20 items, trang 2: 20 items, trang 3: 10 itemsP0
TC-003-05Visual grouping: dim repeated cells1 đơn có 3 items voucherDòng 1: đầy đủ 13 cột. Dòng 2-3: STT vẫn hiện, cột order-level trống, chỉ hiện item-levelP0
TC-003-06Sort theo created_at DESCĐơn A: 15/03, Đơn B: 14/03Đơn A hiện trướcP1
TC-003-07Click mã đơnClick "DH-001"Mở trang chi tiết đơn hàng DH-001P1
TC-003-08Cột Voucher/Quà: 2 dòngTên dài + mã voucherDòng 1: tên (ellipsis nếu dài). Dòng 2: mã voucher (grey)P1
TC-003-09Cột Campaign render theo gifted_fromitem từ voucher campaignHiển thị tên campaign. Item từ "Bạn bè" → "Quà từ bạn bè"P0
TC-003-10Empty stateDate range không có dữ liệu"Không có đơn hàng voucher/quà tặng trong khoảng thời gian này"P1
TC-003-11Khách hàng từ order.addressesĐơn có addressesHiển thị name + primary_phone (không call remote customer)P1

TC-FR-004: Filter

TCMô tảInputExpectedPriority
TC-004-01Filter thời gianChọn 01/03 - 15/03/2026Chỉ hiện đơn trong range, summary cập nhậtP0
TC-004-02Filter chi nhánh (Admin)Chọn "CN Quận 1"Chỉ hiện đơn branch đóP0
TC-004-03Filter chi nhánh (Staff)Login Staff branch "CN Quận 7"Chỉ hiện đơn CN Quận 7, không thấy branch khácP0
TC-004-04Filter nguồn quàChọn "Lắc xì"Chỉ hiện items có gifted_from = "gifted_from_gamification"P0
TC-004-05Cascading: nguồn → chiến dịchChọn "Voucher"Dropdown chiến dịch enable + load danh sách voucher_campaignsP0
TC-004-06Cascading: chưa chọn nguồnKhông chọn nguồn quàDropdown chiến dịch disabled + "Chọn nguồn quà trước"P0
TC-004-07Cascading: đổi nguồn → reset campaignĐã chọn Voucher + campaign X → đổi sang "Lắc xì"Campaign dropdown reset, load danh sách gamificationP0
TC-004-08Filter loại giảmChọn "Giảm %"Chỉ hiện items có gift_type = "gift_type_discount_percent"P0
TC-004-09Filter trạng thái đơn = "Đã hủy"Chọn "Đã hủy"Hiện đơn đã hủy (canceled_at IS NOT NULL)P1
TC-004-10Filter trạng thái đơn mặc địnhLoad trangẨn đơn hủy (canceled_at IS NULL)P0
TC-004-11Nguồn "Bạn bè" + "Thủ công"Chọn cả 2Dropdown chiến dịch disabled + "Không áp dụng"P1
TC-004-12Filter thay đổi → reset page 1Đang ở page 3, đổi filterQuay về page 1P1

TC-FR-005: Export Excel

TCMô tảInputExpectedPriority
TC-005-01Export thành côngFilter có 100 dòng, click exportFile don-hang-voucher-qua-tang_19-03-2026.xlsx downloadP0
TC-005-02Export đúng dữ liệu sau filterFilter nguồn = "Lắc xì"Excel chỉ chứa items từ Lắc xìP0
TC-005-03Export > 10,000 dòngFilter trả về 15,000 dòngHiển thị confirmation dialog "có hơn 10,000 dòng, có thể mất vài phút". Chọn "Tiếp tục" → export thành công. Chọn "Hủy" → abortP1
TC-005-04Cột Excel đúng formatExport fileHeaders đúng, số tiền format #,##0, ngày format DD/MM/YYYY HH:MMP1

TC-FR-006: Performance (indexes)

TCMô tảInputExpectedPriority
TC-006-01List query < 500msEXPLAIN ANALYZE trên staging, date range 3 thángExecution time < 500msP0
TC-006-02Aggregate query < 3sEXPLAIN ANALYZE trên staging, all branches, 3 thángExecution time < 3sP0
TC-006-03Index sử dụng đúngEXPLAIN ANALYZEPlan show Index Scan (không Seq Scan) trên order_itemP0

TC-FR-007: Permission

TCMô tảInputExpectedPriority
TC-007-01Report role seed đúngQuery report_role tableRecord "revenue_voucher_gift_order_report" tồn tạiP0
TC-007-02REPORT_TREE cập nhậtCheck types.tsREVENUE_VOUCHER_GIFT_ORDER_REPORT có trong REPORT_TREEP0

D3) Seed Data

Dataset: DS-001 — Đơn hàng với nhiều loại voucher/gift

Cách tạo: SQL Script

sql
-- Tạo 10 đơn hàng với các scenario:
-- 1. Đơn service có 1 voucher (gifted_from_voucher)
-- 2. Đơn service có 2 voucher từ lắc xì (gifted_from_gamification)
-- 3. Đơn cosmetic có 1 gift từ bạn bè (gifted_from_friend)
-- 4. Đơn service có voucher vòng quay (gifted_from_wheel_of_fortune)
-- 5. Đơn service có gift thủ công (gifted_from_manual)
-- 6. Đơn service KHÔNG có voucher (để verify filter)
-- 7. Đơn đã hủy có voucher (canceled_at IS NOT NULL)
-- 8. Đơn chưa xác nhận (customer_confirmed_at IS NULL)
-- 9. Đơn order_transfer có voucher (để verify order_kind filter)
-- 10. Đơn có gift type "Lời chúc" (voucher_discount_amount = 0)

-- Verify: SELECT COUNT(*) FROM order_item WHERE gifted_id IS NOT NULL;
-- Expected: 12 items có voucher/gift
-- Verify: SELECT COUNT(DISTINCT oi.order_id) FROM order_item oi JOIN "order" o ON oi.order_id = o.id WHERE oi.gifted_id IS NOT NULL AND o.customer_confirmed_at IS NOT NULL AND o.order_kind IN ('service', 'cosmetic', 'prepaid');
-- Expected: 7 đơn (trừ đơn 6 không voucher, đơn 8 chưa xác nhận, đơn 9 order_transfer bị loại bởi order_kind filter)

D4) Traceability

FRTC-IDCoverageStatus
FR-001TC-001-*4 test cases
FR-002TC-002-*6 test cases
FR-003TC-003-*11 test cases
FR-004TC-004-*12 test cases
FR-005TC-005-*4 test cases
FR-006TC-006-*3 test cases
FR-007TC-007-*2 test cases
Total42 test cases

D5) Entry / Exit Criteria

Entry (bắt đầu test)

  • [ ] BE deploy xong: 4 indexes + seed report_role trên staging
  • [ ] FE deploy xong trên staging
  • [ ] Seed data DS-001 có sẵn trên staging
  • [ ] Test accounts: 1 Admin, 1 Manager (branch cụ thể), 1 Staff (branch cụ thể), 1 Staff không có quyền report

Exit (kết thúc test)

  • [ ] Tất cả P0 test cases (22 cases) PASS
  • [ ] Tất cả P1 test cases (20 cases) PASS hoặc có waiver từ PO
  • [ ] Performance verify: list query < 500ms, aggregate < 3s (EXPLAIN ANALYZE)
  • [ ] No critical/major bugs open
  • [ ] Export Excel verify: file mở được, data đúng, format đúng