Appearance
Type Deep Dive — Order Commission And Invoice
1. Order Affiliate là lớp commission trung gian
order_affiliate được tạo từ order/referral runtime ở ecommerce-api chứ không được nhập tay trong module affiliate. FE order list chủ yếu:
- filter và summary,
- mở detail,
- approve / cancel approve / reject / unreject,
- chỉnh commission percent hoặc wallet type khi record còn pending hợp lệ.
2. Order Status Engine
OrderActivePopup vẫn gọi ChangeAffiliateUserStatus, nhưng với:
type = order,new_statusthuộcapprove,cancel,reject,unreject.
Rule chính
approvesetis_approved = true,approved_at = now.cancelchỉ hợp lệ khi chưa có bất kỳinvoice_affiliatenào approved.rejectchỉ hợp lệ khi order chưa approved.unrejectchỉ hợp lệ khi order đang rejected và chưa approved.
3. Invoice Affiliate là lớp materialization gate
invoice_affiliate là bước gần cuối trước khi commission vào ví. PaymentActivePopup gọi cùng action engine với:
type = invoice,new_statusthuộcapprove,reject,unreject.
Approve invoice làm gì?
handleTypeInvoice thực hiện:
- set
invoice_affiliate.is_approved = true, - set
approved_atvàcommission_paid_date, - gọi
AddAffiliateCommission, - ghi
commission_revoke_log, - ghi
affiliate_action_log.
Trong AddAffiliateCommission:
- load
transaction_requestquainvoice_affiliate.transaction_id, - update
transaction_request.status = success, - gửi notification / ZNS side effects,
- từ đây wallet layer mới nhìn thấy commission đã thành công.
Kết luận: invoice approval là business gate cuối trước wallet success, không chỉ là cờ UI.
4. Commission Percent Mutation
Action changeCustomerCommissionPercent cho phép sửa phần trăm commission ở 4 modes:
- order,
- invoice,
- order item within order,
- order item within invoice.
Semantics chính:
- chỉ update trên pending records,
- recalc
order_affiliate.temp_commission_amount, - recalc
invoice_affiliate.commission_amountvàcurrent_sale_percent, - sync luôn
transaction_request.amountvàtransaction_request_user.amount, - ghi
affiliate_action_logcho audit.
Nói cách khác, affiliate commission ở đây không phải read-only sau khi sinh ra; pending path còn cho phép rewrite upstream financial inputs.
5. Wallet Type Mutation
Action changeAffiliateWalletType cho phép đổi ví nhận commission ở cấp order:
- update
order.wallet_receive_commission, - recalc
order_affiliate.wallet_typevàtemp_commission_amount, - recalc toàn bộ
invoice_affiliate.commission_amountchưa approve.
Nhưng nếu có bất kỳ invoice approved nào thì action bị chặn.
6. Historical Visibility Rule ở FE
OrderList và PaymentList dùng filter đặc biệt:
- record approved của affiliate inactive vẫn được show,
- pending records thường gắn điều kiện active/current status chặt hơn.
Mục đích là giữ nhìn thấy lịch sử commission đã chốt dù CTV hiện đã bị revoke.
7. Findings kỹ thuật
| ID | Mức | Finding |
|---|---|---|
| O-01 | P0 | Approve invoice phụ thuộc pre-existing transaction_request; nếu upstream order/referral runtime không tạo đúng transaction_id, approval sẽ fail ở lớp wallet bridge. |
| O-02 | P0 | changeCustomerCommissionPercent sync cả invoice_affiliate lẫn transaction_request và transaction_request_user, nên đây là financial mutation thật, không phải chỉ sửa display percent. |
| O-03 | P1 | changeAffiliateWalletType recalc hàng loạt invoice pending theo level discount hiện tại; QA cần test lại cả amount lẫn wallet type sau khi đổi. |
| O-04 | P1 | Order cancel approval bị chặn nếu có invoice approved, cho thấy state machine thật đang coi invoice approval là irreversible boundary của order-level approval. |
| O-05 | P2 | FE gọi useRefreshSettings() ở order flows để kéo config mới, nghĩa là semantics commission phụ thuộc settings runtime hơn là constants local của affiliate module. |