支付宝、微信退款接入
这篇解决什么
已支付订单怎么发起退款、渠道成功后业务单怎么回写。读完能对上 PayRefundApi、退款列表,以及支付宝没有退款回调这件事。
默认端口 48080。先完成 支付功能设计。建议先用 模拟支付、退款 把闭环跑通,再换成真渠道。
示意图:业务调 createRefund。支付模块按原渠道退。回写看应用上的 refundNotifyUrl。
从哪改
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 模块 | 退款实现 | ruoyi-office/yudao-module-pay/ |
| 退款表 | @TableName("pay_refund") | PayRefundDO |
| 接口 | 管理端查询、导出 | @RequestMapping("/pay/refund") |
| 示例退款 | PUT /pay/demo-order/refund | PayDemoOrderServiceImpl |
| 回写 | POST /pay/demo-order/update-refunded | 同一 Controller |
| 页面 | 退款订单 | views/pay/refund/index.vue |
菜单 1161,路由 /pay/refund。示例退款在支付&退款案例里点「退款」,商户退款号是 {订单id}-refund。
PayRefundApi.createRefund 要带 appKey、原商户订单号 merchantOrderId、商户退款号 merchantRefundId、原因 reason、金额 price(分)。金额加上已退不能超过原支付金额。同一支付单不能同时有状态 0(等待退款)的退款单。
状态字典 pay_refund_status:0 等待退款、10 退款成功、20 退款失败。一张支付单可以对应多张退款单(PayOrderDO : PayRefundDO = 1 : n),示例单限制只能退一次。
支付宝和微信不一样
支付宝:调用退款接口成功就当退款成功,doParseRefundNotify 会抛「支付宝无退款回调」。ACQ.SYSTEM_ERROR 会先记等待,交给 payRefundSyncJob 再查。
微信:有退款回调 POST /pay/notify/refund/{channelId}。v2 / v3 都在 AbstractWxPayClient。证书要齐,否则只能下单不能退。
业务回写仍要自己做
渠道成功后,支付模块按应用的 refundNotifyUrl 通知业务。示例是 update-refunded。自己的售后单也要核对退款单号和金额,不要只听前端点了退款。
挂上 payRefundSyncJob(默认每分钟)。回调任务仍走 payNotifyJob。列表导出权限 pay:refund:export。
钱包支付的退款由 WalletPayClient 调钱包 orderRefund,把钱加回余额,解析回调会抛「钱包支付无退款回调」。模拟退款立刻成功、没有渠道回调,见 模拟支付。
配置与操作
退款没有单独渠道菜单。先在 应用信息(1126,/pay/app)把应用的 refundNotifyUrl 配好(示例是 POST /pay/demo-order/update-refunded)。渠道回调入口是 yudao.pay.refund-notify-url + /{channelId},也就是 POST /admin-api/pay/notify/refund/{channelId},必须公网。微信会打这条;支付宝、钱包、mock 都没有退款回调。
保存后业务调 PayRefundApi.createRefund。必填:appKey、merchantOrderId、merchantRefundId、reason、price(分)。金额不能超过已支付未退;同一支付单不能同时有等待中的退款。示例走 支付&退款案例(2549,/pay/demo/order),已支付单点「退款」,商户退款号是 {订单id}-refund,一次退全款,同一示例单只能退一次。
台账在 退款订单(1161,/pay/refund)。导出权限 pay:refund:export。渠道成功后支付模块再 POST 应用上的 refundNotifyUrl,业务必须核对退款单号和金额。同步挂 payRefundSyncJob(dump 默认每分钟),业务回写重试仍走 payNotifyJob。开启见 支付功能设计。

本系统截图:支付管理 → 退款订单(/pay/refund)。渠道单和状态都在这里。

本系统截图:退款订单点「详情」。核对金额、渠道、商户退款号,不要只听前端点了退款。
