退款接入
退款接入用于把业务退款申请、Pay 退款单、第三方渠道退款和业务单退款状态串起来。RuoYi Office 当前示例订单提供了最小退款闭环:已支付的示例订单可以发起退款,Pay 模块创建退款单,渠道退款成功后回调示例订单更新退款时间。
本页基于 PayDemoOrderServiceImpl、PayRefundController 和管理端退款页面整理。
当前实现边界
| 层 | 路径 / 接口 |
|---|---|
| 示例订单服务 | service/demo/PayDemoOrderServiceImpl.java |
| 示例订单控制器 | controller/admin/demo/PayDemoOrderController.java |
| 退款订单控制器 | controller/admin/refund/PayRefundController.java |
| 管理端示例订单页 | apps/web-antd/src/views/pay/demo/order |
| 管理端退款订单页 | apps/web-antd/src/views/pay/refund |
| 示例退款接口 | PUT /pay/demo-order/refund?id={id} |
| 退款回调接口 | POST /pay/demo-order/update-refunded |
| 退款订单接口 | /pay/refund/page、/pay/refund/get、/pay/refund/export-excel |
退款链路
在真实业务中,merchantRefundId 通常来自售后单、退款申请单或财务退款单。示例订单为了简化,用 {订单ID}-refund 作为退款单号。
发起退款前校验
refundDemoOrder 会先调用 validateDemoOrderCanRefund,确保:
- 示例订单存在。
- 订单已经支付。
- 订单尚未发起过退款。
只有通过校验后才会调用:
java
payRefundApi.createRefund(new PayRefundCreateReqDTO()
.setAppKey(PAY_APP_KEY)
.setMerchantOrderId(String.valueOf(order.getId()))
.setMerchantRefundId(refundId)
.setReason("想退钱")
.setPrice(order.getPrice()))生产业务不要绕过这一步。尤其是部分退款、多次退款、售后拒绝后重新申请等场景,需要用独立退款申请表控制状态和金额。
退款订单管理
管理端「支付退款」页面提供列表、详情和导出能力:
| 功能 | 接口 | 权限 |
|---|---|---|
| 退款分页 | GET /pay/refund/page | pay:refund:query |
| 退款详情 | GET /pay/refund/get | pay:refund:query |
| 导出退款 | GET /pay/refund/export-excel | pay:refund:export |
列表会同时展示商户订单号、商户退款号、渠道退款号,排查时建议先用业务退款单号定位,再看 Pay 退款单和渠道退款单。
回调校验
退款成功后,Pay 模块通过:
text
POST /pay/demo-order/update-refunded通知业务单。updateDemoOrderRefunded 会校验:
- 示例订单是否存在。
- 示例订单记录的
payRefundId是否和回调一致。 - Pay 退款单是否存在且状态成功。
- 退款金额是否等于示例订单金额。
- Pay 退款单的
merchantRefundId是否等于{订单ID}-refund。
这些校验是生产接入必须保留的底线,不能只凭渠道通知就直接修改业务单状态。
和售后退款的关系
商城售后退款会走更完整的业务流程:用户申请售后、商家审核、退货收货、确认退款、Pay 退款回调。示例订单只演示 Pay 层接入;正式商城退款建议阅读 商城售后退款。
| 场景 | 建议使用的业务单号 |
|---|---|
| 示例订单 | {demoOrderId}-refund |
| 商城售后 | 售后单 ID 或售后单号 |
| 订单整单退款 | order-{orderId} 或稳定订单退款单号 |
| 分账/转账退回 | 独立财务退款单号 |
排查清单
| 现象 | 优先检查 |
|---|---|
| 发起退款失败 | 订单是否已支付、是否已经退款、退款金额是否大于可退金额 |
| 退款单一直处理中 | 渠道退款状态、payRefundSyncJob、渠道证书/权限 |
| 业务单未更新 | PayNotifyJob、业务回调接口、merchantRefundId 是否匹配 |
| 退款金额异常 | 是否使用分为单位,是否存在部分退款或重复退款 |
| 渠道退款号为空 | 渠道是否真正受理退款,还是只创建了本地 Pay 退款单 |
二次开发建议
- 增加业务退款申请表,不要只在订单表上放一个退款状态。
- 支持部分退款时,必须计算剩余可退金额。
- 退款回调要幂等,重复通知不能重复增加退款金额。
- 退款失败要保留渠道错误码和错误信息,方便客服处理。
- 对财务敏感场景,确认退款动作建议拆分权限并记录操作日志。
