Skip to content

Type Deep Dive — Payment Withdraw And Wallet Boundary

1. Hai khái niệm khác nhau cần tách ngay

Khái niệm UISource-of-truth thật
Affiliate paymentinvoice_affiliate trong domain ecommerce
Affiliate withdraw / payouttransaction_requesttransaction trong domain wallet

Rất nhiều nhầm lẫn xảy ra vì cả hai đều được gọi là "thanh toán".

2. Withdraw Form Runtime

WithdrawAffiliateForm nằm trong affiliate UI nhưng thực tế:

  • query wallet_balance với wallet_type_id = COMMISSION,
  • query affiliate_user theo account_id để render info CTV,
  • submit mutation refundRequestCreate,
  • tạo transaction_request với:
    • type = W,
    • status = R,
    • behavior_id = refund_collaborator,
    • payment_method_id = wallet | cash,
    • reference_amount = amount.

Kết luận: withdraw không mutate invoice_affiliate hay order_affiliate.

3. Withdraw History Queries

GetWithdrawHistory lọc:

  • customer_id = user_id,
  • payment_method_id in ["wallet", "cash"],
  • type = W,
  • behavior_id = refund_collaborator.

Cards summary lại đọc ba nguồn:

  1. transaction_aggregate với transaction_request.behavior_id = transaction_commission để tính tổng commission đã nhận,
  2. transaction_request_aggregate với refund_collaborator để tính tổng đã rút,
  3. wallet_stats để tính số dư còn lại.

Điều này xác nhận affiliate payout dashboard là một màn hình reconciliation xuyên domain, không phải query một bảng duy nhất.

4. Customer Workspace Embed

Trong customer detail:

  • OrderCustomerListPaymentCustomerList embed order/payment views,
  • action Withdraw mở route withdraw form,
  • affiliate user id được resolve lại qua account_id -> affiliate_user.

Vì vậy user module chỉ là shell host; runtime thật vẫn nằm ở affiliate + wallet.

5. Approval Boundary vs Payout Boundary

Sequence đúng nên hiểu là:

  1. affiliate_user active,
  2. order_affiliate approved,
  3. invoice_affiliate approved,
  4. transaction_request(transaction_commission) success,
  5. user tạo transaction_request(refund_collaborator) để rút,
  6. wallet flow xử lý payout thực.

Nếu bỏ qua bước 4 và 5, rất dễ lẫn "đã duyệt payment" với "đã trả tiền cho CTV".

6. Findings kỹ thuật

IDMứcFinding
W-01P0Withdraw flow nằm hoàn toàn ở wallet boundary; affiliate module chỉ là UI shell tạo request và hiển thị reconciliation cards.
W-02P0Số dư commission không suy trực tiếp từ invoice_affiliate; nó đến từ wallet projections (wallet_balance, wallet_stats, transaction).
W-03P1GetWithdrawHistoryCards dùng transaction_request.behavior_id = transaction_commission để tính tổng đã nhận, còn withdraw dùng refund_collaborator; đây là hai behavior families khác nhau nhưng cùng xuất hiện trong một màn hình.
W-04P1WithdrawAffiliateForm chỉ clamp amount theo wallet balance ở FE; validation/quy tắc cuối cùng vẫn cần dựa vào wallet layer.
W-05P2Chỉ walletcash đang được tính là withdraw methods trong history query, nên nếu thêm payment method mới mà không sửa filter này thì dashboard sẽ drift.