Appearance
Type Deep Dive — Refund / Withdraw Request Family
1. Scope
File này chỉ nói về family đi qua wallet.transaction_request:
refund_orderrefund_order_cosmeticrefund_topuprefund_collaboratorrefund_commissionnhư child request
Không bao gồm negative payment. Boundary đó được tách riêng tại type-negative-payment-boundary.md.
2. Frontend Entry Points
2.1 Route families
| Route family | Đối tượng | Ghi chú |
|---|---|---|
ROUTE_WITHDRAW_REQUEST* | POS | moduleId = refund_request_management |
ROUTE_REQUEST_MANAGEMENT_WITHDRAW* | Admin / fund request management | moduleId = fund_request_management |
Tuy tên route là “withdraw”, page set này thực tế đang gánh toàn bộ refund family.
2.2 Page responsibilities
| Page | Vai trò |
|---|---|
WithdrawRequest.tsx | List + load approvers |
WithdrawRequestCreate.tsx | Tạo / sửa request |
WithdrawRequestDetail.tsx | Xem chi tiết + approve/reject/cancel + tạo refund commission child |
2.3 Query / mutation chính
| Operation | Dùng ở đâu | Vai trò |
|---|---|---|
GetTransactionRequestByPk | Detail | Đọc request |
GetTransactionRequestRefunds | Detail | Đọc child refund |
RefundRequestCreate | Create / edit | Upsert request |
ChangeStatusTransactionRefund | Detail | Approve / reject / cancel |
UploadFileRefund | Detail | Upload file chứng từ |
GetOrderCommissionRefund | Detail dialog | Nguồn tạo refund_commission |
3. FE Runtime Flow
text
User mở list refund/withdraw
-> query transaction_request theo family withdraw types
-> mở detail
-> FE tính canApprove từ approver chain
-> approve/reject/cancel qua changeStatusTransaction
-> reload detail + child refunds + logs
Nếu cần truy thu commission
-> mở CommissionRefundConfirmForm
-> query order_commission_refund
-> tạo child request refund_commission với parent_id4. Create / Update Rules
4.1 Upsert request
WithdrawRequestCreate.tsx đang upsert transaction_request với các default đáng chú ý:
type = "W"status = "R"- default
behavior_id = "refund_topup"nếu người dùng chưa chọn nhánh khác
Điểm này quan trọng vì:
- page create không chỉ dành cho topup,
- nhưng default hiện tại khiến người đọc code dễ hiểu nhầm scope create page.
4.2 List filter
List refund/withdraw đang lọc:
type = "W"activity is nullbehavior_id in WITHDRAW_REQUEST_TYPES
Nguồn: components/withdraw-request/WithdrawRequestTable.tsx
5. Approval Runtime Rules
FE hiện đang tự build approver chain từ useGetApproversQuery và map:
approver_step_1approver_step_2
Logic này đang lặp ở:
WithdrawRequest.tsxWithdrawRequestDetail.tsxWithdrawRequestSelectStatus.tsx
Rule quan trọng
approvechỉ khả dụng khi request ở trạng tháiR- FE đang xác định
canApprovebằngcreated_bycủa request kết hợp approver chain
Rủi ro
Đây là một dấu hiệu bug/risk rõ:
- actor được so bằng
created_bycủa request, - thay vì current user hiện tại.
Hệ quả:
- có thể bật/tắt sai nút approve,
- khó đồng bộ với backend permission thật.
6. Backend Action Path
Action trung tâm: wallet-api/action/change_status_transaction_refund.go
Dispatch theo behavior
| Behavior | Handler |
|---|---|
refund_order | handlerRefundOrder |
refund_order_cosmetic | handlerRefundOrderCosmetic |
refund_collaborator | handlerRefundCollaborator |
refund_topup | handlerRefundTopup |
Transition gate
- action đọc request hiện tại,
- check
validStatusTransactionRefund, - lấy reviewers current/next step,
- chỉ cho người tạo cancel, reviewer approve, reviewer chain reject.
Điểm cần ghi rõ
validateTransactionRequest() đang bị comment toàn bộ, nên gate cũ theo accounting/group hiện không còn hiệu lực.
7. Backend Event Path
Event quan trọng nhất: wallet-api/event/transaction_request_update.go
Đây là nơi nằm phần lớn side effects:
- upsert / sync refund log,
- update
customer_revenue, - wallet credit cho khách khi refund vào ví,
- refund point,
- notification approved,
- commission side effects.
Điều này có nghĩa:
- đọc riêng action approve là chưa đủ,
- mọi doc/test case phải mô hình hóa cả event path.
8. Variant Notes
8.1 refund_order
- Áp cho service order.
- Khi success có thể force complete hoặc cancel order tùy trạng thái order.
- Sau approve còn có logic cancel các request refund khác cùng order/branch.
8.2 refund_order_cosmetic
- Áp cho product order.
- Khi success có thể đổi order sang
canceledhoặcreturned. - Có dấu hiệu semantics chưa sạch ở phần commission side effect.
8.3 refund_topup
- Vẫn là wallet request family.
- Có thể dính split giữa
VNDvàVND_PROMOTIONở downstream logic.
8.4 refund_collaborator
- Dùng cho nhánh collaborator / payout.
- Có thêm approved notification riêng.
8.5 refund_commission
- Không có route riêng.
- Tạo từ dialog con
CommissionRefundConfirmForm. - Là child request gắn
parent_idvề request cha.
9. Data Touchpoints
| Object | Vai trò trong flow |
|---|---|
wallet.transaction_request | Request source of truth |
wallet.transaction_request_user | Wallet legs sender/receiver |
wallet.transaction_request_log | Log action |
wallet.transaction | Ledger when success |
wallet.order_commission_refund | Source để build child refund commission |
wallet.wallet_reference_file | File chứng từ |
ecommerce.transaction_refund_log | Audit/read model |
ecommerce.order | Refund flags / amount / refunded_at |
10. Rủi ro / Findings
| ID | Mức | Finding |
|---|---|---|
| RR-01 | P1 | FE page set tên là “withdraw” nhưng đang gánh nhiều refund behaviors, dễ gây naming drift. |
| RR-02 | P1 | canApprove FE có dấu hiệu check sai actor. |
| RR-03 | P1 | reference_id không canonical nên downstream join rất dễ sai. |
| RR-04 | P1 | is_refunded_order có thể bị set sớm hơn success thật. |
| RR-05 | P1 | Cosmetic refund có semantics commission không đồng nhất với service refund. |