一、问题发现
1.1 遇到的问题
在测试小程序提现功能时,调用微信支付商家转账接口时遇到权限错误:
错误信息:
{
"code": "NO_AUTH",
"message": "当前商户号没有相关权限,暂不支持使用"
}
1.2 问题原因
微信支付在 2025年1月15日 对商家转账功能进行了重大升级:
2025年1月15号之后申请的权限都是新的商家转账产品(对应转账接口
/v3/fund-app/mch-transfer/transfer-bills),需要用户确认才能收款。2025年1月15号之前已有权限的商户仍可使用旧的商家转账到零钱产品权限(对应转账接口/v3/transfer/batches)。
1.3 新旧接口对比
| 对比维度 | 旧版接口 | 新版接口 |
|---|---|---|
| 用户体验 | 后台直接打款,用户无感知 | 必须用户手动确认收款 |
| 接口路径 | /v3/transfer/batches | /v3/fund-app/mch-transfer/transfer-bills |
| 核心流程 | 商户发起 → 微信直接打款 | 商户发起 → 用户确认 → 微信打款 |
| 超时机制 | 无确认环节 | 24小时未确认自动关单退款 |
二、流程改造方案
2.1 整体流程对比
旧版流程:
用户申请提现 → 后台审核通过 → 直接调用微信支付接口 → 打款成功
新版流程:
用户申请提现 → 后台审核通过 → 调用微信支付接口获取packageInfo
→ 用户在小程序中点击"确认收款" → 调起微信支付确认页
→ 用户确认 → 打款成功
2.2 流程时序图
sequenceDiagram
participant 用户
participant 小程序
participant 后端服务
participant 微信支付
用户->>小程序: 1. 申请提现
小程序->>后端服务: 2. 提交提现申请
后端服务->>后端服务: 3. 创建订单(待审核)
Note over 后端服务: 管理员审核
后端服务->>微信支付: 4. 调用转账接口
微信支付-->>后端服务: 5. 返回 package_info
后端服务->>后端服务: 6. 更新订单状态(待确认收款)
用户->>小程序: 7. 查看提现记录
小程序->>小程序: 显示"确认收款"按钮
用户->>小程序: 8. 点击"确认收款"
小程序->>后端服务: 9. 获取 packageInfo
后端服务-->>小程序: 返回 packageInfo
小程序->>微信支付: 10. 调起 wx.requestMerchantTransfer
微信支付->>用户: 11. 显示确认收款页
用户->>微信支付: 12. 确认收款
微信支付->>后端服务: 13. 回调通知打款结果
后端服务->>后端服务: 14. 更新订单状态(打款成功)
2.3 订单状态流转
待审核(0) → 待确认收款(1) → 打款成功(2)
↓ ↓
审核驳回(3) 打款失败(4)
状态说明:
0- 待审核:用户提交申请,等待管理员审核1- 待确认收款:审核通过,等待用户确认收款2- 打款成功:用户确认收款,打款成功3- 审核驳回:管理员审核拒绝4- 打款失败:打款失败(余额不足、用户信息错误等)
三、小程序端实现
3.1 提现记录页面改造
核心改动:新增"确认收款"按钮和确认收款逻辑
3.1.1 显示确认收款按钮
当订单状态为 1(待确认收款)时,显示"确认收款"按钮:
<template>
<div v-if="item.status === 1" class="withdrawal-item__actions">
<button
class="withdrawal-item__btn"
:disabled="isConfirming"
@click="handleConfirmTransfer(item)"
>
{{ isConfirming ? '处理中...' : '确认收款' }}
</button>
</div>
</template>
3.1.2 实现确认收款逻辑
const handleConfirmTransfer = async (item) => {
// 1. 版本检测
if (!wx.canIUse('requestMerchantTransfer')) {
wx.showModal({
content: '你的微信版本过低,请更新至8.0.30及以上版本后重试',
showCancel: false
});
return;
}
try {
isConfirming.value = true;
wx.showLoading({ title: '处理中...', mask: true });
// 2. 调用后端接口,获取 packageInfo
const result = await apiConfirmWithdrawalTransfer(item.withdrawalOrderNo);
wx.hideLoading();
// 3. 调用微信支付接口
wx.requestMerchantTransfer({
mchId: result.mchId,
appId: result.appId,
package: result.packageInfo,
success: (res) => {
showToast('收款确认成功,请稍候查看到账情况');
setTimeout(() => refreshList(), 2000);
},
fail: (err) => {
if (err.errMsg?.includes('cancel')) {
showToast('已取消收款');
} else {
showToast('收款失败:' + err.errMsg);
}
},
complete: () => {
isConfirming.value = false;
}
});
} catch (error) {
wx.hideLoading();
isConfirming.value = false;
showToast(error.message || '确认打款失败,请稍后重试');
}
};
3.1.3 状态文本映射
const getStatusText = (status: number) => {
const statusMap = {
0: '待审核',
1: '待确认收款', // 新增状态
2: '打款成功',
3: '审核驳回',
4: '打款失败'
};
return statusMap[status] || '未知状态';
};
3.2 API 接口封装
新增确认打款接口:
/**
* 确认提现打款(获取 packageInfo)
*/
export const apiConfirmWithdrawalTransfer = (withdrawalOrderNo: string) => {
return request('/commission/confirmWithdrawalTransfer', {
type: 'post',
data: { withdrawalOrderNo }
}) as Promise<{
packageInfo: string;
appId: string;
mchId: string;
}>;
};
四、关键技术点
4.1 微信支付新版接口
4.1.1 发起转账接口
接口路径:POST /v3/fund-app/mch-transfer/transfer-bills
关键参数:
{
"appid": "wx1234567890abcdef",
"out_bill_no": "商户单号",
"transfer_amount": 10000, // 单位:分
"transfer_scene": "佣金发放",
"openid": "用户openid",
"user_name": "加密后的用户姓名"
}
响应示例:
{
"out_bill_no": "商户单号",
"transfer_bill_no": "微信转账单号",
"state": "WAIT_USER_CONFIRM",
"package_info": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
关键注意事项:
transfer_amount单位是分,需要将元转换为分user_name需要使用微信支付公钥加密- 0.3元以下不支持传入
user_name校验 - 返回的
package_info需要保存,供小程序调起确认页使用
4.1.2 小程序调起确认收款
API:wx.requestMerchantTransfer
参数说明:
wx.requestMerchantTransfer({
mchId: '商户号',
appId: '小程序appid',
package: '从后端获取的 packageInfo',
success: (res) => {
// 用户确认成功
},
fail: (err) => {
// 用户取消或失败
}
});
版本要求:
- 微信版本 >= 8.0.30
- 基础库版本 >= 3.4.5
兼容性检测:
if (!wx.canIUse('requestMerchantTransfer')) {
wx.showModal({
content: '你的微信版本过低,请更新至8.0.30及以上版本后重试',
showCancel: false
});
return;
}
4.2 超时处理
用户需在 24小时内 确认收款,超时后系统会自动关单并将资金退回商户运营账户。
建议处理方式:
- 设置定时任务,检查超过24小时未确认的订单
- 调用微信支付查询接口确认订单状态
- 如果订单已关闭,更新订单状态为"打款失败"
- 解冻用户的提现金额
4.3 回调处理
微信支付会通过回调通知转账结果。
回调内容示例:
{
"out_bill_no": "商户单号",
"transfer_bill_no": "微信转账单号",
"state": "SUCCESS",
"fail_reason": "",
"transfer_success_time": "2026-03-12T15:30:00+08:00"
}
处理逻辑:
- 验证签名
- 解密回调数据
- 根据商户单号查询订单
- 更新订单状态为"打款成功"
- 更新用户账户余额
- 返回成功响应
注意事项:
- 必须同时接入查询接口兜底,以防收不到回调通知
- 回调接口需要做幂等性处理,避免重复处理
五、常见问题
5.1 权限类错误
问题:调用旧接口报错 NO_AUTH
原因:商户号是2025年1月15日之后开通的,只能使用新版接口
解决方案:改用新版接口 /v3/fund-app/mch-transfer/transfer-bills
5.2 参数类错误
问题:Openid格式错误或者不属于商家公众账号
原因:openid 与 appid 不匹配
解决方案:
- 确保使用该 appid 下获取的 openid
- 检查 appid 是否已绑定商户号
5.3 前端调起错误
问题:package_info信息有误
原因:package 参数与后端返回的不一致
解决方案:
- 检查参数是否完整、正确
- 确保没有对 packageInfo 进行额外处理(如 trim、encode 等)
问题:system:access_denied
原因:在非小程序环境调起(如 webview)
解决方案:只能在小程序页面内直接调用,不支持 webview
5.4 用户体验问题
问题:用户不知道需要确认收款
解决方案:
- 在提现记录页面显著位置显示"待确认收款"状态
- 提供明确的"确认收款"按钮
- 可以考虑推送模板消息提醒用户确认
问题:用户24小时未确认导致提现失败
解决方案:
- 在提现申请时明确告知用户需要在24小时内确认
- 提供重新申请提现的入口
- 审核通过后立即引导用户确认收款