From e6cb577305e4668de6ddae968bcd32386332e0f3 Mon Sep 17 00:00:00 2001 From: txai-dev Date: Mon, 14 Sep 2026 14:23:44 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BE=AE=E4=BF=A1=E9=80=80=E6=AC=BEAPI?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=BF=AE=E6=AD=A3=E2=80=94=E2=80=94refund=5F?= =?UTF-8?q?order=E6=AD=A3=E7=A1=AE=E5=AD=97=E6=AE=B5(openid/order=5Fid/ref?= =?UTF-8?q?und=5Forder=5Fid/left=5Ffee/refund=5Ffee/refund=5Freason/req=5F?= =?UTF-8?q?from/env)=E6=9B=BF=E6=8D=A2=E9=94=99=E8=AF=AF=E7=9A=84offerId/o?= =?UTF-8?q?utTradeNo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/routes/admin.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/server/src/routes/admin.js b/server/src/routes/admin.js index 0ff243e..973aaae 100755 --- a/server/src/routes/admin.js +++ b/server/src/routes/admin.js @@ -1294,7 +1294,20 @@ router.post('/vpay/orders/:id/refund', requirePermission('orders:write'), async const accessToken = tokenRes.access_token if (!accessToken) throw new Error('获取access_token失败: ' + JSON.stringify(tokenRes)) - const refundBody = JSON.stringify({ offerId: OFFER_ID, outTradeNo: order.orderNo }) + // refund_order 正确参数(snake_case,官方文档 https://developers.weixin.qq.com/miniprogram/dev/server/API/VirtualPayment/api_refund_order.html) + const refundOrderId = `RF${Date.now()}${require('crypto').randomBytes(3).toString('hex').toUpperCase()}` + const refundFee = Math.round(order.amount * 100) // 退款金额(分)= 订单金额 + const refundBody = JSON.stringify({ + openid: user.openid, + order_id: order.orderNo, // 商户单号(下单时的 outTradeNo) + refund_order_id: refundOrderId, // 本次退款单号(8-32位) + left_fee: refundFee, // 剩余可退金额(分) + refund_fee: refundFee, // 本次退款金额(分),须 ≤ left_fee + biz_meta: JSON.stringify({ admin: req.admin.username, reason: 'user_refund' }), + refund_reason: 0, // 0=用户申请退款 + req_from: 1, // 1=商户后台发起 + env: ENV, + }) const paySig = require('crypto').createHmac('sha256', APPKEY).update('/xpay/refund_order&' + refundBody).digest('hex') const wxRes = await fetch(`https://api.weixin.qq.com/xpay/refund_order?access_token=${accessToken}&pay_sig=${paySig}`, {