Skip to content

Shared Rules — Affiliate Approval And Payout

1. Thuật ngữ chuẩn

Thuật ngữNghĩa trong hệ thống
Affiliate userHồ sơ CTV ở bảng affiliate_user; có thể pending hoặc active
Approval queueCác affiliate_useris_active = false đang chờ duyệt hoặc đang bị revoke
Order affiliateCommission record gắn với order; chưa phải payout cuối
Invoice affiliateCommission record gắn với invoice/payment; là bước ngay trước materialization vào wallet
Withdraw requestYêu cầu rút commission từ ví, lưu ở transaction_request với behavior_id = refund_collaborator

2. State Matrix

2.1 affiliate_user

StateDấu hiệu DBÝ nghĩa
Pending / inactiveis_active = false, approved_at = nullChưa có quyền CTV hoặc đã bị thu hồi
Activeis_active = true, approved_at != nullĐã được duyệt và có thể tích lũy commission

2.2 order_affiliate

StateDấu hiệu DBÝ nghĩa
Pendingis_approved = false, rejected = falseChờ duyệt hoa hồng cấp order
Approvedis_approved = true, rejected = falseĐã duyệt order commission
Rejectedrejected = trueBị từ chối ở cấp order
Cancelled approvalis_approved = false, approved_at = nullHoàn tác duyệt order, chỉ hợp lệ khi chưa có invoice approved

2.3 invoice_affiliate

StateDấu hiệu DBÝ nghĩa
Pendingis_approved = false, rejected = falseChờ duyệt payout cấp invoice
Approvedis_approved = true, approved_at != nullCommission đã được materialize sang wallet
Rejectedrejected = trueBị từ chối ở cấp invoice

3. Action Matrix

Reference typeActionKết quả chính
userapproveActive affiliate, bind/create account, set tag, ghi log
userrevokeDeactivate affiliate, clear approved_at, ghi log
orderapproveSet is_approved = true, approved_at = now
ordercancelHoàn tác approve order nếu chưa có invoice approved
orderreject / unrejectToggle rejected
invoiceapproveSet approved fields, update transaction request sang success, add commission
invoicereject / unrejectToggle rejected

4. Invariants

  1. Không thể approve user nếu thiếu tag_id.
  2. Không thể cancel order_affiliate nếu có bất kỳ invoice_affiliate nào đã approved.
  3. Không có nhánh cancel approved invoice trong action engine; invoice chỉ approve/reject/unreject.
  4. Không thể đổi wallet type nhận commission nếu đã có invoice approved trong order đó.
  5. Không thể sửa commission percent của invoice/order nếu invoice target đã approved; action chỉ update pending path.

5. Cross-Module Boundary Rules

BoundaryRule
affiliate -> userApprove CTV có thể create customer account mới và cập nhật account tag
affiliate -> walletInvoice approval credit commission; withdraw tạo transaction_request riêng
affiliate -> reportReport đọc aggregate/view/function từ cùng family data nhưng không phải source-of-truth để mutate
affiliate -> settingsuseRefreshSettings được gọi ở order pages để lấy config commission/wallet validity mới nhất

6. Những điều dễ hiểu nhầm

6.1 "Payment" trong affiliate không phải luôn là tiền đã rút

PaymentList trong affiliate đang hiển thị invoice_affiliate. Đây là trạng thái commission cấp invoice, không phải lịch sử tiền đã rút khỏi ví.

6.2 Approve affiliate không luôn đi qua approval queue

Staff có thể tạo CTV mới bằng ListCreate và path đó gọi affiliateUserRegistration theo role user, dẫn tới record active ngay sau create nếu tag hợp lệ.

6.3 Wallet balance không suy ra trực tiếp từ invoice_affiliate

Balance đang đọc wallet_balance / wallet_stats; invoice_affiliate chỉ là upstream business record. Nguồn số dư thật nằm ở wallet layer sau khi transaction request thành công.

7. Checklist QA ngắn

  1. Tách test affiliate payment approval khỏi test withdraw request.
  2. Test cả 2 nhánh registration: customer self-register và staff create affiliate.
  3. Test historical visibility cho affiliate inactive nhưng đã có order/payment approved.
  4. Test fail path khi invoice approve gặp thiếu transaction_id.
  5. Test action logs cho approve/revoke/reject/update percent ở cả order và invoice.