Bẫy logic mã giảm giá: quy tắc chồng mà không làm hỏng giỏ hàng
Lỗi logic mã giảm giá có thể làm sai tổng thanh toán. Tìm hiểu quy tắc chồng, loại trừ và mẫu có thể kiểm thử để tránh giảm hai lần và tổng âm.

Tại sao logic khuyến mãi hay bị hỏng
Khuyến mãi trông đơn giản cho tới khi bạn đưa chúng vào một quy trình thanh toán thực. Giỏ hàng thay đổi liên tục, nhưng các khoản giảm giá thường được viết như những quy tắc đơn lẻ. Chính khe hở đó là nơi hầu hết các lỗi logic mã giảm giá xuất hiện.
Khó khăn là một quy tắc mới có thể thay đổi tổng tiền ở khắp nơi. Thêm “giảm 10%, nhưng không áp dụng cho hàng giảm giá” và bạn phải quyết định “hàng giảm giá” nghĩa là gì, khi nào kiểm tra, và 10% áp dụng trên khoản nào. Nếu còn khuyến mãi khác cũng chạm tới cùng món hàng, thứ tự áp dụng quan trọng, và thứ tự thay đổi giá.
Nhiều đội cũng trộn toán học với quy tắc nghiệp vụ. Một sửa nhanh như “giới hạn giảm giá bằng tổng phụ” bị sao chép ra ba nơi, rồi bạn có đáp án khác nhau tùy nơi tính tổng (trang giỏ, checkout, hóa đơn, email).
Những thời điểm rủi ro cao là khi hệ thống của bạn tính lại giá:
- Cập nhật giỏ hàng: thay đổi số lượng, xóa mặt hàng, đổi phương thức vận chuyển
- Chỉnh sửa sau khi thanh toán: thay đổi địa chỉ, hủy một phần, thay thế mặt hàng
- Hoàn trả và trả hàng: phân bổ lại theo tỷ lệ giữa các mặt hàng, điều chỉnh thuế, tín dụng cửa hàng
- Thay đổi chế độ tiền tệ hoặc thuế: giá net vs gross, tổng đã bao gồm thuế
Một ví dụ nhỏ: khách thêm một bundle, áp mã “$20 off $100”, rồi xóa một món. Nếu mã vẫn “nhớ” tổng phụ cũ, bạn có thể cho $20 khi giỏ chỉ còn $85, hoặc thậm chí làm một dòng hàng âm.
Cuối bài này, bạn sẽ biết cách ngăn hầu hết lỗi khuyến mãi phổ biến: giảm giá hai lần, tổng khác nhau giữa các màn hình, tổng âm, giảm áp dụng cho hàng bị loại trừ, và hoàn tiền không khớp với những gì khách đã thanh toán.
Bắt đầu bằng quy tắc chồng và thứ tự ưu tiên rõ ràng
Hầu hết lỗi logic mã giảm giá bắt nguồn từ một câu bị thiếu: những giảm giá nào được phép áp dụng cùng nhau, và theo thứ tự nào. Nếu bạn không thể giải thích quy tắc chồng bằng ngôn ngữ đơn giản, giỏ hàng cuối cùng sẽ làm điều gì đó gây bất ngờ.
Định nghĩa chồng bằng các câu trả lời có/không. Ví dụ: “Một coupon thủ công mỗi đơn hàng. Khuyến mãi tự động vẫn có thể áp dụng trừ khi coupon nói nó chặn chúng.” Một dòng như vậy ngăn các kết hợp ngẫu nhiên dẫn đến giảm hai lần.
Tách giảm theo mặt hàng và giảm theo đơn sớm. Quy tắc theo mặt hàng thay đổi giá sản phẩm cụ thể (ví dụ giảm 20% giày). Quy tắc theo đơn thay đổi tổng (ví dụ $10 off toàn giỏ). Trộn chúng mà không có cấu trúc là cách làm tổng chệch giữa trang sản phẩm, giỏ và checkout.
Quyết định “ưu đãi tốt nhất” nghĩa là gì trước khi bạn code. Nhiều đội chọn “tiết kiệm tối đa”, nhưng điều đó có thể phá vỡ ngưỡng giá sàn. Bạn có thể cần quy tắc như “không bao giờ giảm dưới giá vốn” hoặc “không bao giờ làm phí vận chuyển âm.” Chọn một quy tắc rõ ràng để bộ máy không phải tự suy đoán.
Một thứ tự ưu tiên đơn giản giữ xung đột có thể dự đoán được:
- Khuyến mãi tự động trước (danh mục hoặc theo mùa)
- Coupon thủ công tiếp theo (khách nhập vào)
- Tín dụng cửa hàng hoặc thẻ quà tặng cuối cùng (hình thức thanh toán, không phải giảm giá)
- Thuế và vận chuyển tính lại sau khi áp giảm giá
Ví dụ: giỏ có khuyến mãi tự động 10% tất cả mặt hàng, thêm coupon nhập $15 off cho đơn trên $100. Nếu ưu tiên nói tự động trước, bạn có thể rõ ràng trả lời: ngưỡng $100 dùng tổng trước giảm hay sau giảm? Ghi lại, rồi giữ nhất quán khắp nơi.
Khi những lựa chọn này được viết ra, quy tắc chồng coupon của bạn trở thành quy tắc có thể kiểm thử, không phải hành vi ẩn. Đây là cách nhanh nhất tránh lỗi sau này.
Mô hình hóa giảm giá như dữ liệu đơn giản, rõ ràng
Nhiều lỗi bắt đầu khi giảm giá tản mát dưới dạng if-else khắp mã checkout. Cách an toàn hơn là coi mỗi khuyến mãi như dữ liệu với loại, phạm vi và giới hạn rõ ràng. Khi đó toán học giỏ hàng chỉ là bộ đánh giá nhỏ, có thể dự đoán.
Bắt đầu bằng cách đặt tên loại giảm giá, không phải ý tưởng marketing. Hầu hết khuyến mãi phù hợp vài dạng: phần trăm, số tiền cố định, tặng hàng (mua X tặng Y), và miễn phí vận chuyển. Khi bạn thể hiện khuyến mãi bằng một trong các loại này, bạn tránh được các trường hợp đặc biệt khó test.
Tiếp theo, làm rõ phạm vi. Cùng một % hoạt động rất khác tùy vào mục tiêu. Định nghĩa xem nó áp dụng cho toàn đơn, một danh mục, một sản phẩm, một dòng hàng hay vận chuyển. Nếu phạm vi mơ hồ, bạn sẽ vô tình giảm nhầm tổng phụ hoặc giảm hai lần.
Ghi ràng buộc thành trường dữ liệu, không phải comment trong code. Các ràng buộc phổ biến: chi tiêu tối thiểu, chỉ đơn hàng đầu tiên, và khoảng ngày. Cũng ghi rõ cách xử lý với giá sale: chồng lên sale, áp vào giá gốc, hay loại trừ hàng giảm giá.
Một schema gọn có thể gồm:
- type (percent, fixed, free_item, free_shipping)
- scope (order, category, product, item, shipping)
- constraints (min_spend, first_order, start_at, end_at)
- floors (min_total = 0, min_item_price, optional min_margin)
- rounding policy (per item vs per order)
Cuối cùng, thêm giá sàn mà engine luôn tôn trọng: tổng không bao giờ thấp hơn 0, và nếu doanh nghiệp cần, hàng không bao giờ thấp hơn giá vốn (hoặc mức giá tối thiểu đã định). Xây dựng điều này sẽ ngăn tổng âm và trường hợp “chúng ta trả tiền cho khách” khó chịu.
Nếu bạn prototype engine giảm giá trong Koder.ai, giữ các trường này hiển thị trong chế độ planning để bộ đánh giá luôn đơn giản và có thể test khi thêm nhiều khuyến mãi.
Bước từng bước: cách an toàn để đánh giá khuyến mãi
Nhiều lỗi bắt nguồn khi kiểm tra điều kiện đủ điều kiện và phép toán bị trộn lẫn. Mô hình an toàn hơn là hai pha: trước tiên quyết định những gì có thể áp dụng, rồi tính toán số tiền. Tách biệt này giữ quy tắc dễ đọc và giúp ngăn trạng thái xấu (như tổng âm).
Trật tự đánh giá xác định
Dùng cùng một thứ tự mỗi lần, ngay cả khi khuyến mãi đến từ UI hay API khác nhau. Tính xác định quan trọng vì nó biến “tại sao giỏ thay đổi?” thành một câu hỏi bạn có thể giải thích.
Một luồng đơn giản hoạt động tốt:
- Validate đầu vào: định dạng mã, cửa sổ ngày, phạm vi khách hàng, tiền tệ, và giá không âm.
- Select eligible promos: chạy kiểm tra điều kiện (chưa tính tiền). Xây dựng danh sách ứng viên.
- Resolve stacking and priority: áp dụng quy tắc chồng (ví dụ: “tối đa một khuyến mãi theo đơn”) và tiêu chí quyết định (ưu tiên, rồi giá trị tốt nhất, rồi ID ổn định).
- Apply calculations: tính giảm sử dụng cơ sở nhất quán (trước thuế hay sau thuế, có tính shipping hay không) và chính sách làm tròn.
- Summarize totals: tính lại tổng đơn từ tổng các dòng, rồi giới hạn ở 0 và thi hành giới hạn giảm tối đa.
Ghi lại phân tích và dấu vết kiểm toán
Khi áp khuyến mãi, đừng chỉ lưu một “tổng giảm”. Giữ phân tích theo từng dòng và theo đơn để bạn có thể đối chiếu tổng và giải thích.
Tối thiểu, ghi lại:
- Quy tắc hoặc khuyến mãi nào đã áp (ID và phiên bản), và độ ưu tiên
- Lý do nó được áp (các điều kiện như “category=shoes”, “cart subtotal >= 50”)
- Nó thay đổi gì (ID dòng bị ảnh hưởng, cơ sở, số tiền giảm, làm tròn)
- Những gì nó ngăn chặn (ví dụ: “bị chặn do loại trừ: đã có giảm theo mặt hàng”)
Ví dụ: giỏ có hai món, một đang sale. Pha 1 đánh dấu mã đủ điều kiện chỉ cho món giá gốc. Pha 2 áp 10% cho dòng đó, để nguyên dòng sale, rồi tính lại tổng đơn từ phân tích dòng để không giảm hai lần vô ý.
Mã hóa loại trừ mà không tạo logic rối rắm
Nhiều lỗi bắt đầu khi loại trừ ẩn trong các nhánh đặc biệt kiểu “nếu mã là X thì bỏ qua Y.” Nó hoạt động cho một khuyến mãi, rồi vỡ khi khuyến mãi tiếp theo xuất hiện.
Cách an toàn hơn: giữ một luồng đánh giá duy nhất, và làm cho loại trừ trở thành một tập kiểm tra có thể từ chối một tổ hợp khuyến mãi trước khi bạn tính tiền. Bằng cách đó, giảm không bao giờ áp dụng một nửa.
Xử lý loại trừ như dữ liệu, không phải nhánh code
Thay vì hardcode hành vi, cho mỗi khuyến mãi một “hồ sơ khả năng tương thích” nhỏ, rõ ràng. Ví dụ: loại promo (coupon vs sale tự động), phạm vi (hàng, vận chuyển, đơn), và quy tắc kết hợp.
Hỗ trợ cả hai:
- Danh sách “không thể kết hợp với” (denylist): promo A chặn promo B.
- Danh sách “chỉ kết hợp với” (allowlist): promo A chỉ chồng với tập được đặt tên.
- Các cờ quy tắc như “chặn sale tự động” hoặc “yêu cầu không có coupon khác.”
Điểm mấu chốt là engine của bạn hỏi cùng những câu cho mọi promo, rồi quyết định tập hợp có hợp lệ hay không.
Làm cho xung đột rõ ràng, kể cả sale tự động
Sale tự động thường được áp trước, rồi một coupon đến và lặng lẽ ghi đè. Quyết định trước điều gì nên xảy ra:
- Coupon chồng lên sale
- Coupon chỉ áp cho hàng không sale
- Coupon bị từ chối nếu có sale
Chọn một cách cho mỗi promo và mã hóa nó như một kiểm tra, không phải một đường tính toán thay thế.
Một cách thực tiễn để tránh bất ngờ là kiểm tra tính đối xứng. Nếu “WELCOME10 không kết hợp với FREESHIP” là ý định hai chiều, mã hóa để cả hai chiều đều chặn. Nếu không đối xứng, làm rõ và hiển thị trong dữ liệu.
Ví dụ: sale toàn site 15% đang chạy. Khách nhập coupon 20% dành cho hàng giá gốc. Các kiểm tra nên loại trừ hàng đang sale cho coupon trước khi tính tổng, hơn là giảm chúng rồi cố sửa số về sau.
Nếu bạn xây quy tắc trong nền tảng như Koder.ai, giữ các kiểm tra này như một lớp riêng, có thể test, để thay đổi quy tắc mà không viết lại phần toán học.
Các trường hợp méo mó gây tổng lệch
Hầu hết tranh chấp khuyến mãi không phải vì con số headline. Chúng xảy ra khi cùng giỏ được tính theo hai cách hơi khác nhau, rồi khách thấy một số ở giỏ và một số khác ở checkout.
Bắt đầu bằng khoá trình tự thao tác. Quyết định, và văn bản hoá, xem giảm theo dòng có xảy ra trước giảm theo đơn không, và vận chuyển nằm đâu. Quy tắc phổ biến: giảm theo mặt hàng trước, rồi giảm theo đơn trên tổng còn lại, rồi giảm vận chuyển cuối cùng. Dù chọn gì, dùng cùng một trình tự ở mọi nơi hiển thị tổng.
Thuế là cái bẫy tiếp theo. Nếu giá đã bao gồm thuế, giảm giá làm giảm phần thuế nữa. Nếu giá chưa bao gồm thuế, thuế tính sau khi giảm. Trộn hai mô hình này ở các phần khác nhau của luồng là một trong những lỗi kinh điển vì hai phép tính đúng vẫn có thể cho kết quả khác nhau nếu giả định cơ sở thuế khác nhau.
Vấn đề làm tròn có vẻ nhỏ nhưng tạo nhiều ticket hỗ trợ. Quyết định làm tròn theo dòng hay theo đơn, và giữ đúng độ chính xác cho tiền tệ. Với coupon phần trăm, làm tròn theo dòng có thể chênh vài xu so với làm tròn theo đơn, đặc biệt với nhiều món giá thấp.
Những trường hợp méo mó đáng xử lý:
- Hoàn trả và hoàn tiền một phần: phân bổ giảm theo tỷ lệ để hoàn tiền không vượt quá số đã trả.
- Chỉnh giỏ sau khi áp coupon: đánh giá lại tính đủ điều kiện và giới hạn khi thêm/xóa mặt hàng.
- Thay đổi vận chuyển: đổi địa chỉ hay phương thức làm thay đổi phần thuế và điều kiện giảm vận chuyển.
- Thay đổi số lượng: cùng món lặp lại có thể vượt ngưỡng (ví dụ min_spend hoặc mua-X-tặng-Y).
- Món chịu thuế hỗn hợp: một số mặt hàng không chịu thuế nhưng vẫn đủ điều kiện nhận coupon.
Ví dụ cụ thể: coupon giảm 10% theo đơn cộng miễn phí vận chuyển cho đơn trên $50. Nếu coupon áp trước khi kiểm tra ngưỡng, tổng sau giảm có thể < $50 và vận chuyển mất miễn phí. Chọn một cách diễn giải, mã hóa nó, và giữ nhất quán ở giỏ, checkout và trong hoàn tiền.
Lỗi khuyến mãi phổ biến và cách chúng xảy ra
Hầu hết lỗi xuất hiện khi giỏ được đánh giá qua hơn một đường. Một khuyến mãi có thể áp ở mức dòng hàng ở chỗ này và sau đó lại áp ở mức đơn ở chỗ khác, và cả hai nhìn có vẻ “đúng” cô lập.
Các lỗi thường gặp và nguyên nhân:
- Giảm hai lần cùng một món: cùng khuyến mãi được áp một lần ở giá từng dòng và một lần nữa khi tính tổng đơn, thường vì hai dịch vụ đều cố áp giảm.
- Tổng âm hoặc dòng hàng âm: giảm theo số tiền cố định vượt quá khoản đủ điều kiện (ví dụ $20 off áp cho tổng đủ điều kiện $12) mà không có sàn 0.
- Áp % lên giá đã giảm vô tình: engine áp 10% lên giá đã giảm trong khi ý định là “10% trên giá niêm yết”, vì code dùng giá hiện tại thay vì giá gốc.
- Kiểm tra chi tiêu tối thiểu dựa trên tổng sai: quy tắc kiểm tra tổng trước giảm nhưng nghiệp vụ mong muốn sau giảm (hoặc ngược lại), dẫn đến áp hoặc không áp bất ngờ.
- Mặt hàng bị loại trừ vẫn nhận coupon: điều kiện dựa vào tag sản phẩm, nhưng tag thiếu hoặc không đồng nhất (hoặc đường thoát fallback) khiến mặt hàng không nhận biết được là bị loại trừ.
Ví dụ: giỏ có hai món, một đủ điều kiện và một bị loại trừ. Nếu engine tính “tổng đủ điều kiện” đúng cho promo phần trăm, nhưng sau đó trừ một khoản cố định từ tổng đơn đầy đủ, món bị loại trừ thực chất vẫn bị giảm.
Mẫu an toàn nhất là tính mỗi promo trên một “khoản đủ điều kiện” rõ ràng và trả về điều chỉnh có giới hạn (không bao giờ dưới 0), cùng với dấu vết rõ ràng những gì nó chạm tới. Nếu bạn sinh engine giảm giá bằng công cụ như Koder.ai, hãy xuất dấu vết dưới dạng dữ liệu để test có thể so sánh chính xác dòng nào đủ điều kiện và tổng phụ nào được dùng.
Làm cho quy tắc có thể kiểm thử với bộ test phù hợp
Nhiều lỗi xuất hiện vì test chỉ kiểm tra tổng cuối cùng. Một bộ test tốt kiểm tra cả tính đủ điều kiện (promo có nên áp không?) và toán học (nó bớt bao nhiêu?), với phân tích đọc được để so sánh theo thời gian.
Xây test từ nhỏ đến thực tế
Bắt đầu với unit test cô lập một quy tắc. Giữ input nhỏ, rồi mở rộng tới kịch bản giỏ đầy đủ.
- Unit test điều kiện: promo có áp được không dựa trên loại khách, ngày, tag sản phẩm, và chi tiêu tối thiểu?
- Unit test toán học: với tổng đủ điều kiện cố định, phép tính có đúng làm tròn và quy tắc tiền tệ không?
- Scenario test: items hỗn hợp, số lượng, vận chuyển, thuế, và vài promo cạnh tranh.
- “Giỏ thay đổi” test: giá cập nhật, xóa mặt hàng, hoặc thay đổi số lượng giữa lúc đánh giá và checkout.
- Snapshot phân tích: lưu phân bổ giảm theo dòng, không chỉ tổng cuối.
Sau khi có độ phủ, thêm vài kiểm tra “luôn đúng” bắt lỗi lạ bạn không nghĩ tới:
- Tổng không bao giờ xuống dưới 0.00.
- Một giảm không bao giờ làm tăng tổng.
- Giảm áp dụng không vượt quá cơ sở đủ điều kiện.
- Xóa mặt hàng không đủ điều kiện không được làm cho giảm lớn hơn.
Ví dụ giỏ nhỏ
Giả sử giỏ có 2 mặt hàng: áo $40 (đủ điều kiện) và thẻ quà $30 (bị loại trừ). Vận chuyển $7. Promo 1: “20% off apparel, max $15”, và promo 2: “$10 off orders over $50” không chồng với giảm phần trăm.
Test kịch bản nên khẳng định promo nào thắng (ưu tiên), xác nhận thẻ quà bị loại trừ, và kiểm tra phân bổ chính xác: 20% của $40 là $8, vận chuyển không đổi, tổng cuối đúng. Lưu phân tích đó làm snapshot vàng để refactor sau này không âm thầm đổi promo áp dụng hay bắt đầu giảm các dòng bị loại trừ.
Danh sách kiểm tra nhanh trước khi ra mắt
Trước khi phát hành promo mới, chạy qua checklist cuối cùng để bắt những lỗi khách thấy ngay: tổng lạ, thông điệp mơ hồ, và hoàn tiền không khớp. Những kiểm tra này cũng giúp ngăn hầu hết lỗi vì buộc quy tắc phải hành xử giống nhau ở mọi giỏ.
Chạy các kiểm tra này với vài giỏ “khó” đã biết (một mặt hàng, nhiều mặt hàng, thuế hỗn hợp, vận chuyển, và một dòng số lượng lớn). Lưu giỏ để chạy lại khi bạn thay đổi mã định giá.
Năm kiểm tra bắt lỗi chủ yếu
- Hàng rào an toàn cho tổng: Tổng đơn và giá ròng mỗi dòng không bao giờ thấp hơn 0. Nếu giảm vượt quá khoản có thể áp dụng, cắt gọn và ghi lại phần bị cắt.
- Toán học giải thích được: Phân tích giảm hiển thị cho khách (theo promo, theo dòng, theo vận chuyển) phải cộng đúng với số cuối cùng. Nếu không giải thích được trong một câu, quy tắc quá mơ hồ.
- Một chính sách chồng, không bất ngờ: Quyết định và xác minh những gì có thể chồng (coupon với auto promo, phần trăm với cố định, giảm vận chuyển với giảm hàng). Làm rõ thứ tự ưu tiên và xác nhận khớp với những gì đội hỗ trợ sẽ nói.
- Làm tròn nhất quán: Chọn quy tắc làm tròn (theo dòng vs theo đơn, half-up vs bankers, số thập phân theo tiền tệ). Văn bản hoá và test với giá như $0.99, số lượng 3, và các % trộn lẫn.
- Hoàn trả và refund đúng: Trả lại một phần phải hoàn đúng phần giảm, thuế và vận chuyển. Test “trả 1 trong 3 mặt hàng”, “trả mặt hàng đã giảm trước”, và “hoàn tiền sau khi promo hết hạn”.
Nếu bạn xây quy tắc trong trình tạo như Koder.ai, thêm các trường hợp này làm test tự động cạnh định nghĩa quy tắc. Mục tiêu: promo mới nên fail nhanh trong test chứ không phải fail trong giỏ khách.
Một kịch bản chồng thực tế để xác nhận quy tắc
Đây là giỏ nhỏ phơi bày hầu hết lỗi mà không quá phức tạp.
Giả sử các quy tắc (ghi chính xác như sau vào hệ thống):
- Khuyến mãi tự động áp trước, theo mặt hàng, chỉ cho mặt hàng full-price đủ điều kiện
- Coupon theo đơn, $15 off, yêu cầu ít nhất $100 hàng đủ điều kiện
- “Hàng đủ điều kiện” loại trừ hàng sale, vận chuyển và thuế
- Coupon không được vượt quá tổng đủ điều kiện sau các promo trước
- Thuế tính sau khi giảm (trên hàng đã giảm + vận chuyển)
Giỏ và promo
Giỏ:
| Line | Price | Notes |
|---|---|---|
| Item A | $60 | full-price, eligible |
| Item B | $40 | full-price, eligible |
| Item C | $30 | sale item, excluded |
| Shipping | $8 | fee |
Promos:
- Promo 1: automatic 10% weekend sale on eligible items
- Promo 2: coupon $15 off, min $100 eligible spend, excludes sale items
Các bước và phân tích cuối
-
Kiểm tra ngưỡng coupon: hàng đủ điều kiện trước giảm là $60 + $40 = $100, nên coupon có thể áp.
-
Áp Promo 1 (10% cho hàng đủ điều kiện): $100 x 10% = $10 off. Tổng đủ điều kiện còn $90.
-
Áp Promo 2 ($15 off): giới hạn là $90, nên áp đủ $15. Tổng đủ điều kiện mới: $75.
Tổng:
- Hàng: đủ điều kiện $75 + hàng sale $30 = $105
- Vận chuyển: $8
- Thuế (8%): (105 + 8) x 0.08 = $9.04
- Tổng cuối: $105 + $8 + $9.04 = $122.04
Bây giờ đổi một thứ: khách xóa Item B ($40). Hàng đủ điều kiện còn $60, nên coupon không đạt ngưỡng. Chỉ có promo 10% tự động: Item A còn $54, hàng là $54 + $30 = $84, và tổng cuối trở thành $99.36. Đây là kiểu “chỉnh sửa nhỏ” thường làm hỏng giỏ nếu điều kiện và thứ tự không rõ ràng.
Bước tiếp theo: ra mắt promo an toàn và duy trì chúng
Cách nhanh nhất tránh lỗi là coi promo như quy tắc sản phẩm, không phải “một chút toán trong checkout.” Trước khi phát hành, viết spec ngắn ai cũng đọc và đồng ý.
Bao gồm bốn điều, bằng ngôn ngữ đơn giản:
- Quy tắc chồng (cái gì kết hợp được, và cái gì không)
- Thứ tự ưu tiên (giảm nào thắng khi hai cái cùng trúng một món)
- Loại trừ (danh mục, thương hiệu, hàng sale, đăng ký, thẻ quà)
- Sàn và giới hạn (min subtotal, max discount, và “không bao giờ dưới $0”)
Sau khi phát hành, theo dõi các tổng như theo dõi lỗi. Lỗi giảm giá thường trông như đơn hợp lệ cho đến khi tài chính thấy nó.
Thiết lập giám sát cảnh báo đơn hàng có mẫu bất thường, như tổng gần bằng không, tổng âm, giảm lớn hơn tổng phụ, hoặc bùng phát giỏ “miễn phí 100%”. Chuyển cảnh báo đến cùng nơi bạn gửi lỗi checkout, và giữ playbook ngắn cách vô hiệu hóa promo an toàn.
Để thêm promo mới mà không gây regressions, dùng workflow lặp lại: cập nhật spec trước, mã hóa quy tắc như dữ liệu (không phải nhánh code), thêm test cho vài giỏ “bình thường” và một hai trường hợp khó, rồi chạy toàn bộ bộ test giảm giá trước khi merge.
Nếu muốn triển khai và lặp nhanh hơn, bạn có thể prototype luồng engine promo trong Koder.ai bằng chế độ planning, rồi dùng snapshot và rollback khi tinh chỉnh test. Điều này giúp thử thay đổi quy tắc nhanh mà không mất phiên bản đã biết là an toàn.
Câu hỏi thường gặp
Quy tắc kết hợp mã giảm giá là gì?
Hãy viết một chính sách kết hợp khuyến mãi trước khi lập trình. Nêu rõ những ưu đãi tự động, mã giảm giá, ưu đãi vận chuyển và tín dụng cửa hàng nào có thể kết hợp, rồi xác định thứ tự giỏ hàng đánh giá chúng.
Làm thế nào để mã giảm giá không tạo ra tổng tiền âm?
Chỉ áp dụng khoản giảm cố định cho phần giá trị đủ điều kiện và giới hạn kết quả ở mức 0. Hãy tính lại giới hạn này mỗi khi giỏ hàng thay đổi, thay vì dùng lại tổng tiền tạm tính trước đó.
Mã giảm giá có thể loại trừ các mặt hàng đang giảm giá như thế nào?
Giữ các mặt hàng giảm giá trong giỏ, nhưng loại chúng khỏi tổng tiền đủ điều kiện của mã giảm giá trước khi tính mức giảm. Lưu ngoại lệ này trong quy tắc khuyến mãi để mọi màn hình đều cho ra cùng một kết quả.
Khuyến mãi tự động có nên áp dụng trước mã giảm giá không?
Hãy dùng một trình tự đánh giá cố định. Ví dụ, áp dụng khuyến mãi cho từng mặt hàng trước, sau đó đến mã giảm giá cho đơn hàng, rồi đến ưu đãi vận chuyển và tính thuế sau cùng nếu chính sách thuế của bạn yêu cầu.
Quy tắc giảm giá nên bao gồm những dữ liệu nào?
Mỗi khuyến mãi nên có loại, phạm vi, điều kiện ràng buộc, ngoại lệ, mức sàn và chính sách làm tròn. Khi đó, bộ đánh giá có thể dùng cùng một cấu trúc dữ liệu thay vì các trường hợp đặc biệt rải rác.
Vì sao tôi cần nhật ký kiểm toán khuyến mãi?
Ghi lại mã và phiên bản khuyến mãi đã áp dụng, các dòng hàng bị ảnh hưởng, số tiền cơ sở đủ điều kiện, số tiền giảm, kết quả làm tròn và mọi khuyến mãi bị chặn. Nhờ vậy, bộ phận hỗ trợ và tài chính có thể giải thích giá cuối cùng mà không cần dựng lại đơn hàng thủ công.
Khi nào thanh toán nên tính lại mức giảm giá?
Đánh giá lại mọi khuyến mãi khi số lượng, mặt hàng, địa chỉ, phương thức vận chuyển, tiền tệ hoặc cài đặt thuế thay đổi. Một mã hợp lệ có thể trở nên không hợp lệ sau khi khách bỏ một mặt hàng hoặc không còn đạt ngưỡng chi tiêu.
Làm thế nào để tổng tiền trong giỏ hàng và khi thanh toán không bị lệch nhau?
Chọn một phương pháp làm tròn, chẳng hạn làm tròn từng dòng hàng hoặc chỉ làm tròn tổng đơn hàng, rồi dùng nhất quán ở mọi nơi. Chênh lệch nhỏ sẽ dễ thấy khi mức giảm theo phần trăm áp dụng cho nhiều mặt hàng giá thấp.
Hoàn tiền một phần nên xử lý giảm giá như thế nào?
Phân bổ mức giảm giá ban đầu cho các mặt hàng đã mua và chỉ hoàn lại phần tiền đã trả của mặt hàng đó, bao gồm cả điều chỉnh thuế liên quan. Đừng tính khoản hoàn tiền theo các quy tắc khuyến mãi hiện tại, vì khuyến mãi có thể đã hết hạn hoặc giỏ hàng đã thay đổi.
Những kiểm thử nào phát hiện nhiều lỗi khuyến mãi nhất?
Hãy kiểm tra điều kiện đủ, phép tính, ngoại lệ, xung đột khi kết hợp khuyến mãi, chỉnh sửa giỏ hàng, làm tròn, thuế và hoàn trả một phần. Cũng cần xác nhận rằng không có khoản giảm giá nào vượt quá giá trị cơ sở đủ điều kiện và tổng tiền không bao giờ thấp hơn 0.