Payment — Case thường gặp
Method không hiện ở checkout
Kiểm tra master toggle, BU/provider setting, category availability, site scope và payment option rule. Nếu method bị ẩn đúng do config, đừng sửa flow checkout.
Ví dụ thực tế: Phụ huynh ở site A không thấy Direct Debit khi checkout. → Xác định ẩn do cấu hình hay do bug. → Provider chưa bật cho BU của site A → đó là ẩn đúng config, không sửa flow checkout.
PayNow thành công nhưng UI không cập nhật
Đọc provider result/webhook, batch/payment status và checkout success method resolution. Webhook có thể đến sau redirect; UI cần chịu được trạng thái pending ngắn hạn.
Ví dụ thực tế: Khách trả thẻ xong, bị quay về trang "đang xử lý" vài giây trước khi báo thành công. → UI không được kết luận thất bại quá sớm. → Webhook về sau redirect → giữ trạng thái pending ngắn rồi cập nhật khi webhook tới.
Direct Debit tạo customer sai BU
AccountPaymentCustomer phải unique/active theo (AccountId, BusinessUnitId, PaymentProvider). Nếu thiếu BU filter, đó là lỗi boundary/security chứ không chỉ là lỗi query.
Ví dụ thực tế: Một account hoạt động ở 2 BU, set Direct Debit ở BU2 lại trỏ về customer của BU1. → Tránh rò rỉ thanh toán giữa hai đơn vị. → Query thiếu BU filter → coi là lỗi boundary, thêm
BusinessUnitIdvào điều kiện unique.
Deposit bị double submit
Kiểm tra order lock, provider callback idempotency và trạng thái batch. Deposit không được tạo nhiều transaction slots cho cùng order nếu lock còn hiệu lực.
Ví dụ thực tế: Khách bấm nút trả deposit hai lần do mạng chậm. → Tránh thu deposit hai lần cho một order. → Order lock + callback idempotency chặn slot thứ hai khi lock còn hiệu lực.
Checkout success message sai method
Đối chiếu payment-success-message-by-method, checkout confirmation type guard và method resolution. Message nên phản ánh method thực tế chứ không đoán từ route.
Ví dụ thực tế: Khách trả Direct Debit nhưng màn hình success lại ghi nội dung của PayNow. → Thông báo phải đúng method để khách không hiểu nhầm. → Resolve message theo method thực tế của giao dịch, không đoán theo route checkout.
Zero-amount checkout không mở provider
Total = 0 → bỏ qua provider dù chọn method nào; Proceed confirm ngay, Submit giữ pending theo eligibility.
Ví dụ thực tế: Booking sau ưu đãi còn total = 0 đồng, khách chọn Pay Now. → Không redirect Windcave cho khoản 0 đồng. → Nút
Proceedhiện ra, bấm xong booking confirm ngay, về confirmed success surface.
Zero-amount Pay Later-only giữ pending
Khi total = 0 và Pay Later là method duy nhất → nút Submit, booking giữ Submitted/pending, hiện pending message; không redirect booking-confirmed.
Ví dụ thực tế: Category chỉ cho Pay Later và booking có total = 0. → Không thể confirm ngay vì chưa có thao tác thu tiền. → Nút
Submitgiữ booking Submitted; admin/staff Confirm sau.
Popup finalization nền sau khi trả tiền
total payable > 0, provider trả về thành công → popup báo hệ thống đang hoàn tất booking nền, không cần bấm OK, tự đóng khi xong.
Ví dụ thực tế: Khách trả deposit xong bị redirect về portal nhưng booking chưa confirm. → Tránh khách đóng tab làm dở finalization. → Popup "đang xử lý, đừng đóng trình duyệt" hiện ra rồi tự biến mất khi finalization xong.
PayLater display name theo BU
Admin đặt PayLaterDisplayName ở tab "Other" → checkout hiện label đó cho mọi category; null/empty → fallback "Pay Later"; category cấm Pay Later thì option không hiện dù label có.
Ví dụ thực tế: BU đặt "Pay by Invoice". → Khách checkout thấy "Pay by Invoice" thay vì "Pay Later". → Hiển thị đúng label; nhưng category để
Nonethì option vẫn không hiện.
Booking FT/PT/Casual hỗn hợp xét Pay Later
Precedence FULL_TIME > PART_TIME > CASUAL: có ≥1 FT session → Full Time; không FT nhưng có PT → Part Time; chỉ Casual → không thỏa FT/PT.
Ví dụ thực tế: Booking gồm 1 session FT + 2 session Casual, category để quy tắc FT. → Xác định booking có thỏa FT không. → Tính Full Time theo precedence → Pay Later khả dụng.
Master toggle bật nhưng category cấm
Provider bật ở BU ≠ booking eligibility ở category. Method chỉ hiện khi cả hai pass; đổi một tầng không ghi đè tầng kia.
Ví dụ thực tế: Pay Now bật Stripe ở BU nhưng category B để
Disabled. → Không lẫn lộn hai cấu hình. → Section Pay Now vẫn enabled trong settings, nhưng khách checkout category B không thấy Pay Now.
Đổi payment method trên billing
Booking Manager đổi PaymentOptionId của billing qua ChangeBillingPaymentMethodModal (Direct Debit = 4 / Other = 1); nút chỉ hiện khi BU có DD provider; lỗi backend → giữ modal + hiện message.
Ví dụ thực tế: Staff muốn chuyển billing từ "Other" sang Direct Debit cho một booking. → Tránh phải tạo billing mới. → Mở modal, chọn Direct Debit, save thành công; nếu BU chưa bật DD thì nút không hiện.
Success message theo method và fallback
Batch type 201 → payNowSuccessMessage; 204 → payNowDepositSuccessMessage, fallback sang payNowSuccessMessage nếu deposit message rỗng; DD/Pay Later confirmed → directDebitSuccessMessage/payLaterMessage; message rỗng → default, không hiện content cũ đã xoá.
Ví dụ thực tế: Khách trả deposit nhưng BU chưa soạn deposit message. → Không để trống trang success. → Hiện
payNowSuccessMessagehiện hành thay vì trống hoặc content cũ đã bị xoá.