Skip to content

Type Deep Dive — Commission Lifecycle

1. Commission có phải subsystem riêng không?

Không. Trong code hiện tại, commission là một family request chạy trên cùng wallet request engine.

Điểm khác biệt chỉ là:

  • behavior_id,
  • wallet đích hoặc wallet nguồn,
  • upstream creator,
  • rule idempotency,
  • refund/clawback path.

2. Commission create path chuẩn

2.1 Trigger nghiệp vụ

Các nguồn tạo commission phổ biến:

  • invoice approved,
  • membership / prepaid flow,
  • referral / affiliate flow,
  • event bonus.

Nguồn backend quan trọng nhất:

  • ecommerce-api/event/invoice_insert_update.go
  • pkg/commission_util/add_commission.go

2.2 AddCommission(...)

Utility này thường:

  1. build checksum,
  2. tạo transaction_request,
  3. set behavior_id = transaction_commission,
  4. set type = D,
  5. chọn wallet đích COMMISSION hoặc VND_PROMOTION,
  6. tạo request ở trạng thái S,
  7. để DB trigger materialize transaction.

Kết quả:

  • commission chuẩn là “auto-success request”,
  • không cần đi qua màn hình duyệt như family refund/withdraw.

3. Customer / affiliate commission variants

3.1 AddCommissionCustomer(...)

Variant này dùng cho customer/affiliate-oriented flows nhưng vẫn giữ pattern:

  • create request,
  • create receiver leg,
  • materialize ledger,
  • đồng bộ read models/reporting.

3.2 Temp commission rồi mới approve

Một số flow affiliate dùng mô hình:

  1. AddTempCustomerCommission(...) tạo request status R,
  2. affiliate/status change approval xảy ra,
  3. AddAffiliateCommission(...) chuyển request sang S.

Đây là khác biệt quan trọng so với commission chuẩn từ invoice:

  • commission không phải lúc nào cũng auto-success,
  • cùng family commission nhưng state machine có thể khác nhau theo upstream business flow.

4. Commission refund / clawback

4.1 Refund order sinh child refund_commission

Khi refund order:

  1. FE đọc order_commission_refund,
  2. approver chọn amount truy thu theo user,
  3. FE hoặc backend tạo child transaction_request,
  4. child request có behavior_id = refund_commission,
  5. sender thường là ví COMMISSION của user bị truy thu.

4.2 Commission percent / affiliate config change

Một số thay đổi affiliate không tạo child request từ refund cha mà:

  • update request hiện hữu, hoặc
  • insert sender request mới để clawback phần commission không còn hợp lệ.

Điều này làm commission clawback có ít nhất 2 hình thái:

  • child refund request gắn vào refund cha,
  • standalone sender request do change config/business state.

5. Read models liên quan

ObjectVai trò
order_commission_refundAggregate commission/refund theo order + user
ecommerce_transactionTheo dõi side effect transaction phía ecommerce
CommissionReport*Báo cáo read-only phía report
EmployeeProfileCommissionLịch sử commission phía user module

Điểm cần nhớ:

  • đây là read models hoặc reporting surfaces,
  • source-of-truth của lifecycle vẫn là transaction_request + transaction.

6. Idempotency và duplicate risk

Checksum hiện tại là lớp anti-duplicate chính cho commission create.

Vấn đề:

  • checksum mang tính time-window,
  • chưa phản ánh đầy đủ business key bền vững như invoice/order/user/behavior/source,
  • retry sau window có thể tạo duplicate hợp lệ về mặt kỹ thuật nhưng sai về business,
  • hai thao tác hợp lệ quá gần nhau có thể bị chặn nhầm.

Kết luận:

  • commission idempotency hiện là “best effort”,
  • chưa phải contract mạnh để QA hoặc integration dựa vào hoàn toàn.

7. Rủi ro / Findings kỹ thuật

IDMứcFinding
CL-F01P1Commission chuẩn và temp commission dùng hai state model khác nhau nhưng cùng family, dễ làm docs/QA nhầm là một flow duy nhất.
CL-F02P1refund_commission có thể được tạo theo child request hoặc sender request standalone, nên reconciliation phải phân biệt nguồn gốc.
CL-F03P1Idempotency checksum hiện dựa trên time-window, không đủ mạnh như business key.
CL-F04P2Reporting surfaces commission không luôn đọc ledger trực tiếp, nên số liệu có thể lệch khi read-model sync trễ hoặc source field bị overload.