Mở đầu — vì sao bài này quan trọng
Nếu bạn từng làm QA cho một sản phẩm e-commerce, hẳn bạn đã quen với cảnh: tới đợt sale, hệ thống voucher trở thành "ổ bug" lớn nhất. Đơn hàng âm tiền, voucher freeship cộng dồn với voucher giảm 50% khiến công ty lỗ nặng, hoặc khách hàng phát hiện cách "lách" để mua iPhone với giá 0 đồng rồi khoe lên mạng xã hội. Là QA, bạn từng là người tìm ra những lỗ hổng đó. Nhưng bạn có bao giờ tự hỏi: tại sao những lỗ hổng đó tồn tại ngay từ đầu?
Câu trả lời gần như luôn là: business rules về voucher được viết không đầy đủ, không rõ ràng, và không ai nghĩ hết các trường hợp khi đặc tả. Đây chính xác là công việc của một BA. Và đây cũng là lý do bài học này quan trọng đặc biệt với người chuyển từ QA sang BA: voucher stacking (cộng dồn nhiều voucher trên một đơn hàng) là một bài toán mà tư duy QA của bạn là lợi thế vàng. Bạn đã quen nghĩ về edge case, về việc "nếu khách làm thế này thì sao", về cách hệ thống vỡ khi gặp dữ liệu bất thường. Bài học này sẽ dạy bạn cách chuyển hóa tư duy đó thành tài liệu đặc tả business rules mà dev có thể build và QA có thể test.
Chúng ta sẽ lấy một case study cụ thể: Tiki muốn launch tính năng cho phép khách hàng áp dụng nhiều voucher trên cùng một đơn hàng. Bạn — với vai trò BA xuất thân QA — sẽ là người đặc tả toàn bộ quy tắc này. Hết bài, bạn sẽ có một bộ khung tư duy và một mẫu tài liệu thực sự dùng được trong công việc.
Khái niệm cốt lõi
Voucher stacking là gì?
Voucher stacking là khả năng áp dụng đồng thời nhiều mã giảm giá trên một đơn hàng. Ví dụ: một đơn 500.000đ có thể được áp dụng cùng lúc voucher freeship (miễn phí vận chuyển), voucher giảm 10% từ shop, và voucher giảm 30.000đ từ sàn. Nghe có vẻ đơn giản, nhưng đây là một trong những vùng nghiệp vụ phức tạp nhất của bất kỳ nền tảng thương mại điện tử nào.
Tại sao phức tạp? Vì nó liên quan đến tiền thật, đến nhiều bên (sàn, shop, đơn vị vận chuyển), và đến hành vi cố tình khai thác lỗ hổng của người dùng. Một quy tắc viết thiếu một dòng có thể khiến công ty mất hàng tỷ đồng trong một đợt sale.
Ba khái niệm BA bắt buộc phải làm rõ
Khi đặc tả voucher stacking, có ba trục quyết định mà BA phải định nghĩa minh bạch:
1. Tính kết hợp (Combinability) — voucher nào được phép đi cùng voucher nào?
Không phải mọi voucher đều stack được với nhau. Thông thường người ta phân loại voucher theo category: voucher vận chuyển (shipping), voucher sàn (platform), voucher shop (seller), voucher thanh toán (ngân hàng/ví). Quy tắc phổ biến: trong cùng một category chỉ được chọn một voucher, nhưng khác category thì được cộng dồn. BA phải vẽ ra ma trận combinability — một bảng cho biết cặp loại voucher nào tương thích.
2. Thứ tự áp dụng (Order of application) — áp voucher nào trước, voucher nào sau?
Đây là phần mà nhiều BA mới bỏ qua và là nguồn bug kinh điển. Nếu đơn 500.000đ áp voucher giảm 10% rồi mới áp voucher giảm 50.000đ, kết quả khác với việc áp 50.000đ trước rồi mới giảm 10%. Voucher phần trăm tính trên giá nào — giá gốc hay giá sau khi đã trừ các voucher trước? BA phải định nghĩa calculation order rõ ràng đến từng bước.
3. Giới hạn và bảo vệ (Caps & guardrails) — đâu là điểm dừng?
Hệ thống phải có lằn ranh để không bao giờ rơi vào trạng thái nguy hiểm: tổng giảm giá không vượt quá giá trị đơn hàng (không cho ra đơn âm tiền), số voucher tối đa trên một đơn, ngân sách (budget) của chiến dịch voucher đã cạn chưa, và các điều kiện tối thiểu (minimum order value) của từng voucher có còn thỏa mãn sau khi voucher khác đã trừ tiền hay không.
Vì sao đây là "sân nhà" của người từ QA
Tư duy edge case — thứ bạn đã rèn hằng ngày khi làm QA — chính là kỹ năng quý nhất ở đây. BA giỏi về voucher không phải người nghĩ ra "happy path" (luồng thuận lợi), mà là người liệt kê được hết các trường hợp gãy: voucher hết hạn giữa lúc thanh toán, khách hủy một sản phẩm khiến đơn không còn đủ điều kiện minimum order, hai voucher cùng trừ tiền khiến đơn rơi xuống dưới ngưỡng của voucher thứ ba. Bạn đã quen viết test case kiểu này. Giờ bạn chỉ cần viết nó trước khi code được viết, dưới dạng business rules.
Tình huống thực tế
Tình huống 1 — Tiki và đơn hàng âm tiền trong đợt sale 11.11
Giả định Tiki (bối cảnh hợp lý dựa trên thực tế ngành) chuẩn bị cho sale 11.11. Đội product quyết định cho phép stack tối đa 3 voucher: 1 freeship + 1 voucher sàn + 1 voucher shop. PO viết yêu cầu ngắn gọn: "Cho phép khách áp dụng đồng thời 3 loại voucher."
Một BA thiếu kinh nghiệm sẽ chuyển thẳng yêu cầu này cho dev. Kết quả: một khách hàng tinh ý đặt đơn 120.000đ, áp voucher sàn "giảm 50%" (giảm 60.000đ), voucher shop "giảm 70.000đ", và freeship "giảm 25.000đ phí ship". Tổng giảm: 155.000đ trên đơn 120.000đ — đơn âm 35.000đ. Hệ thống ghi nhận và Tiki phải hoàn tiền ngược cho khách.
Một BA xuất thân QA sẽ ngay lập tức hỏi: "Điều gì xảy ra khi tổng voucher lớn hơn giá trị đơn?" Họ đặc tả guardrail: tổng giá trị giảm giá (không tính phần freeship) không bao giờ được vượt quá subtotal của đơn hàng; nếu vượt, voucher cuối cùng được áp chỉ giảm tới mức làm đơn về 0đ. Họ cũng tách bạch: freeship chỉ trừ vào phí vận chuyển, không bao giờ trừ vào tiền hàng.
Bài học: Một dòng yêu cầu "cho phép stack 3 voucher" cần được nở ra thành hàng chục quy tắc con. Khoảng cách giữa yêu cầu của PO và đặc tả của BA chính là giá trị bạn tạo ra.
Tình huống 2 — Shopee và bẫy "thứ tự áp dụng" trong giảm phần trăm
Trên Shopee (bối cảnh giả định hợp lý), một khách đặt đơn 1.000.000đ. Có hai voucher: voucher A "giảm 20%" và voucher B "giảm 200.000đ". Câu hỏi tưởng nhỏ nhưng có thể chênh lệch hàng tỷ đồng khi nhân lên hàng triệu đơn: áp cái nào trước?
- Cách 1: Áp A trước: 1.000.000 × 80% = 800.000đ, rồi trừ B: 800.000 − 200.000 = 600.000đ.
- Cách 2: Áp B trước: 1.000.000 − 200.000 = 800.000đ, rồi giảm 20%: 800.000 × 80% = 640.000đ.
BA xuất thân QA sẽ đặc tả calculation order rõ ràng, ví dụ: "Áp dụng theo thứ tự: (1) voucher giảm số tiền cố định trừ trên subtotal gốc; (2) voucher giảm phần trăm tính trên subtotal đã trừ ở bước 1; (3) voucher freeship trừ trên phí vận chuyển." Đồng thời nêu rõ con số mẫu để QA verify.
Bài học: Với business rules liên quan đến tính toán, con số ví dụ trong tài liệu quan trọng ngang với câu chữ. Đây đúng là thói quen QA của bạn — luôn kèm expected result.
Tình huống 3 — Lazada và voucher "rơi điều kiện" khi khách bớt sản phẩm
Trên Lazada (bối cảnh giả định), khách có đơn 3 sản phẩm trị giá 350.000đ và áp được voucher "giảm 50.000đ cho đơn từ 300.000đ" cộng với voucher freeship "cho đơn từ 250.000đ". Mọi thứ ổn ở màn giỏ hàng. Nhưng đến bước thanh toán, khách bỏ một sản phẩm 80.000đ, đơn còn 270.000đ.
Lúc này: voucher freeship vẫn hợp lệ (270.000 > 250.000), nhưng voucher giảm 50.000đ đã mất điều kiện (270.000 < 300.000). Nếu hệ thống không re-validate (xác thực lại) khi giỏ hàng thay đổi, khách vẫn được giảm 50.000đ trên đơn không đủ điều kiện.
BA xuất thân QA sẽ định nghĩa rõ trigger re-validation: "Mỗi khi giỏ hàng thay đổi (thêm/bớt/đổi số lượng sản phẩm) hoặc trước khi xác nhận thanh toán, hệ thống phải kiểm tra lại toàn bộ điều kiện của từng voucher đang áp dụng; voucher nào không còn thỏa điều kiện sẽ bị gỡ và thông báo cho khách."
Bài học: Voucher không phải trạng thái tĩnh "áp một lần là xong". Nó là trạng thái động phải được kiểm tra lại theo vòng đời đơn hàng. Tư duy "state thay đổi thì điều gì gãy" là bản năng QA — hãy đưa nó vào spec.
Hướng dẫn từng bước
Đây là quy trình BA mà bạn có thể áp dụng để đặc tả voucher stacking (hoặc bất kỳ business rule phức tạp nào).
Bước 1 — Phân loại voucher (Categorize). Liệt kê tất cả loại voucher hiện có và sẽ có: freeship, voucher sàn, voucher shop, voucher thanh toán, voucher hoàn xu. Mỗi loại ghi rõ nguồn ngân sách (ai trả tiền giảm giá này — sàn hay shop?).
Bước 2 — Lập ma trận Combinability. Vẽ bảng N×N giữa các loại voucher, mỗi ô đánh dấu "được stack" hoặc "loại trừ". Ví dụ:
| Freeship | Voucher sàn | Voucher shop | Voucher thanh toán | |
|---|---|---|---|---|
| Freeship | — | Có | Có | Có |
| Voucher sàn | Có | Không (chọn 1) | Có | Có |
| Voucher shop | Có | Có | Không (chọn 1) | Có |
Bước 4 — Xác định Guardrails. Liệt kê các lằn ranh không được phép vượt: không đơn âm tiền, số voucher tối đa/đơn, kiểm tra budget chiến dịch, minimum order value tính trước hay sau khi stack.
Bước 5 — Đặc tả Re-validation triggers. Liệt kê mọi sự kiện khiến voucher cần được kiểm tra lại: thay đổi giỏ hàng, voucher hết hạn, hết lượt dùng, đổi phương thức thanh toán, trước khi confirm đơn.
Bước 6 — Viết Acceptance Criteria dạng Gherkin. Chuyển mỗi quy tắc thành kịch bản Given–When–Then mà dev build được và QA test được. Ví dụ:
> Given đơn hàng có subtotal 120.000đ > And khách áp voucher sàn giảm 60.000đ và voucher shop giảm 70.000đ > When hệ thống tính tổng giảm giá > Then tổng giảm trên tiền hàng không vượt quá 120.000đ > And đơn hàng cuối cùng có giá trị tối thiểu là 0đ, không âm.
Bước 7 — Rà soát edge case cùng QA. Đây là bước bạn tỏa sáng. Ngồi cùng đội QA, brainstorm các trường hợp gãy, bổ sung vào spec trước khi dev bắt đầu code.
Lỗi thường gặp & mẹo
Lỗi 1 — Chỉ viết happy path. BA mới thường chỉ đặc tả "khách áp 3 voucher hợp lệ thì được giảm tổng". Họ quên trường hợp voucher xung đột, đơn âm, voucher rơi điều kiện. Mẹo: Với mỗi quy tắc thuận, tự hỏi "điều ngược lại thì sao?" — đúng phản xạ QA của bạn.
Lỗi 2 — Không định nghĩa thứ tự tính toán. Để mặc định "dev tự quyết" là công thức cho bug không thể test. Mẹo: Luôn kèm bảng tính bằng số cụ thể trong tài liệu.
Lỗi 3 — Bỏ quên góc nhìn tài chính. Voucher do shop trả khác voucher do sàn trả. Nếu spec không phân biệt nguồn ngân sách, đội tài chính không thể đối soát. Mẹo: Mỗi voucher trong spec phải có trường "ai chịu chi phí".
Lỗi 4 — Coi voucher là trạng thái tĩnh. Quên re-validation là nguyên nhân của phần lớn lỗ hổng thực tế. Mẹo: Vẽ vòng đời đơn hàng và đánh dấu mọi điểm voucher cần được kiểm tra lại.
Lỗi 5 — Không nghĩ tới hành vi khai thác. Người dùng thật sẽ chủ động tìm cách lách. Mẹo: Dành riêng một mục "Abuse scenarios" trong spec, liệt kê các cách khách có thể lợi dụng — đây là tư duy security testing bạn đã có.
Mẹo chuyển đổi mindset: Khi còn là QA, bạn tìm bug sau khi hệ thống được build. Là BA, bạn tìm bug trong tài liệu trước khi có một dòng code. Cùng một bộ não, chỉ khác thời điểm áp dụng — và áp dụng sớm thì rẻ hơn rất nhiều.
Bài tập thực hành
Đề bài: Một sàn TMĐT Việt Nam muốn cho phép khách stack tối đa 2 voucher trên một đơn: 1 voucher sàn + 1 voucher shop. Voucher sàn hiện có hai loại — giảm phần trăm và giảm số tiền cố định. Voucher shop chỉ có loại giảm số tiền cố định. Đơn mẫu: subtotal 800.000đ, phí ship 30.000đ.
Hãy hoàn thành các phần sau như một BA thực thụ:
- Ma trận combinability: Vẽ bảng cho biết voucher sàn loại phần trăm và voucher sàn loại tiền cố định có stack được với nhau không, và vì sao.
- Calculation order: Định nghĩa thứ tự áp dụng và tính kết quả cuối cùng cho hai voucher cụ thể: voucher sàn "giảm 15%" + voucher shop "giảm 100.000đ".
- Guardrail: Viết một quy tắc bảo vệ chống đơn âm tiền và một quy tắc về minimum order value khi stack.
- Re-validation: Liệt kê ít nhất 3 sự kiện khiến hệ thống phải kiểm tra lại voucher.
- Acceptance Criteria: Viết 2 kịch bản Given–When–Then — một happy path và một edge case (ví dụ: khách bớt sản phẩm làm đơn rơi xuống dưới minimum order value).
- Abuse scenario (nâng cao): Mô tả một cách khách hàng có thể lợi dụng lỗ hổng nếu spec viết thiếu, và đề xuất quy tắc chặn.
Tóm tắt
Voucher stacking là một case study hoàn hảo để bạn thấy rõ giá trị của việc chuyển từ QA sang BA. Bản chất công việc là biến một câu yêu cầu mơ hồ thành bộ business rules đầy đủ, không mâu thuẫn và testable. Ba trục quyết định bạn phải luôn làm rõ là: tính kết hợp (combinability), thứ tự áp dụng (calculation order), và giới hạn bảo vệ (guardrails). Cùng với đó là re-validation — coi voucher như trạng thái động chứ không tĩnh.
Điều quan trọng nhất: tư duy edge case mà bạn rèn được khi làm QA chính là siêu năng lực của một BA giỏi trong domain này. Người khác viết happy path; bạn viết cả những con đường gãy. Người khác đặc tả "cho phép stack"; bạn đặc tả điều gì xảy ra khi đơn âm tiền, khi voucher rơi điều kiện, khi khách cố tình lách. Đó chính là khoảng cách giữa một spec gây ra bug tỷ đồng và một spec bảo vệ doanh nghiệp. Hãy mang theo bản năng "nếu thế này thì sao" của bạn vào mọi tài liệu BA — đó là tài sản nghề nghiệp quý nhất bạn mang từ QA sang.