Skip to content

Shared Rules — Wallet Transaction Request / Commission

1. Thuật ngữ chuẩn

Thuật ngữNghĩa trong code hiện tạiGhi chú
Transaction Requestwallet.transaction_requestRequest envelope trung tâm cho nạp/chuyển/rút/commission/refund
Transaction Request Userwallet.transaction_request_userSender/receiver legs của request
Transactionwallet.transactionLedger thực tế sau khi request thành công
Behaviorwallet_master_dataPhân loại nghiệp vụ: transaction_commission, refund_order, refund_commission...
Hold AmountTổng amount sender đang bị giữ theo rule của DB functionKhông đồng nghĩa mọi request chưa xong đều bị giữ
Available Balancewallet.amount - hold_amount - min_balance_capacityMức khả dụng thực tế để tạo request mới
CommissionRequest family cộng tiền vào ví COMMISSION hoặc VND_PROMOTIONThường tự sinh từ ecommerce-api
Commission Refund / ClawbackRequest family thu hồi commissionCó thể là child request hoặc request sender mới

2. Type Matrix

TypeÝ nghĩaFamily phổ biến
DDepositcommission, topup ví, cashback
TTransfercommission clawback, điều chuyển giữa ví/người dùng
WWithdrawrefund cho khách, payout, collaborator withdraw

3. Status Matrix

StatusÝ nghĩa
RRequesting
PProcessing
SSuccess
FFailure
CCanceled
RejectRejected

Điểm đáng chú ý:

  • Family refund/withdraw hiện chạy nhiều ở R -> S/C/Reject.
  • Business wording trong docs cũ hay nói “pending” chung, nhưng DB function hold_amount chỉ cộng P.
  • RejectC cùng tồn tại, nên test case phải phân biệt “bị từ chối” với “người tạo hủy”.

4. Behavior Matrix

BehaviorFamilyEngineMô tả ngắn
transaction_commissionCommissionwallet.transaction_requestCộng commission chuẩn khi invoice approved
refund_orderRefundwallet.transaction_requestHoàn order dịch vụ
refund_order_cosmeticRefundwallet.transaction_requestHoàn order mỹ phẩm
refund_topupRefundwallet.transaction_requestHoàn topup/prepaid liên quan
refund_collaboratorPayout / refundwallet.transaction_requestChi/hoàn tiền liên quan collaborator
refund_commissionCommission clawbackwallet.transaction_requestThu hồi commission đã trả
event_bonusBonuswallet.transaction_requestThưởng sự kiện / campaign nếu cấu hình

5. Invariants quan trọng

SR-001: transaction_request là source-of-truth workflow

  • Approver chain, status, behavior, order/reference đều nằm ở đây.
  • transaction chỉ là hệ quả sau khi request tới S.
  • Vì vậy mọi phân tích workflow phải bắt đầu từ transaction_request, không bắt đầu từ ledger.

SR-002: transaction_request_user.amount khác với transaction.amount

  • transaction_request_user.amount: requested amount theo leg sender/receiver.
  • transaction.amount: amount đã materialize vào ledger.

Hệ quả:

  • reporting hoặc reconciliation không được trộn hai lớp này như nhau,
  • update request user sau khi request đã được materialize có thể làm lệch ledger.

SR-003: reference_id không phải khóa canonical

Trong code hiện tại, reference_id có thể gắn với:

  • invoice,
  • order,
  • project task.

Ngoài ra nhiều flow còn có order_id riêng.

Hệ quả:

  • luôn ghi rõ join bằng reference_id hay order_id,
  • không được dùng reference_id như business key duy nhất.

SR-004: walletBalances không thuần query

Action này:

  • ép user_id về caller nếu không phải admin,
  • lọc wallet type theo flags,
  • tự tạo wallet missing rows.

Hệ quả:

  • test read-path phải chấp nhận side effect tạo row,
  • mọi mô tả “chỉ query balance” là chưa đúng.

SR-005: Hold amount là invariant ở DB function, không phải invariant toàn hệ thống

  • DB function hiện chỉ cộng sender legs của request T/W có status P.
  • Một số flow approval lại dùng R -> S/C/Reject.

Hệ quả:

  • business expectation “request đang chờ duyệt thì bị giữ tiền” không luôn đúng,
  • QA cần tách test theo status thật, không theo wording màn hình.

6. Boundary Checklist

Khi phân tích bug hoặc change request trong vùng này, luôn hỏi:

  1. Đây là request family nào: commission create, payout, refund, hay clawback?
  2. Nguồn tạo request nằm ở FE mutation trực tiếp hay ở ecommerce-api helper/util?
  3. Read path đang dùng wallet_balance, wallet_stats hay walletBalances?
  4. Status thực tế của case này có đi qua P không?
  5. Reporting đang dựa vào ledger thật hay read-model/view như order_commission_refund?

7. Rủi ro / Findings

IDFinding
SR-F01Vocabulary “wallet”, “transaction”, “request”, “commission” đang bị dùng lẫn giữa FE page, GraphQL và DB table.
SR-F02Hold semantics hiện khác wording trong business docs cũ, nên rất dễ viết acceptance criteria sai.
SR-F03Một số read model như order_commission_refund hoặc wallet_stats rất hữu ích, nhưng không phải source-of-truth workflow.