上一篇介绍了微信支付-现金红包的开发,这一章聊聊商家转账到零钱的开发细节。我当时调研功能的时候,先调研的其实是这个产品。我们产品上的场景是:用户答题,答题正确,然后给发红包。我到微信开放社区上搜了一下这种类型的开发案例,官方给的回复是:这种场景,使用转账到零钱这个产品更合适。那我为啥最后用了现金红包呢?是因为业务上的一些原因,不说了。产品方面,如果是我这种类型的场景,或者其他类型的,比如:抽奖之类的,最好也都是用这个商家转账到零钱。
1、官方文档
https://pay.weixin.qq.com/doc/v3/merchant/4012716434
这里注意一下,我发的这个文档是“商家转账到零钱的最新版本”,是微信支付团队在2025-01-15这一天最新更新的,但是他们还是保留了之前的版本。你要注意,确保你看到的是最新的开发文档,如果看的是之前的版本,等真正调用的时候就提示你,功能不能用,需要使用最新升级的版本。你就白开发了。
2、开发前的准备事项
提前申请“商家转账到零钱”的产品权限,这个权限,貌似是不用等的,我们是2025-01-15当天申请的,填写完资料,直接就审核通过了,但是不确定后面会不会和现金红包一样,审核要等很久。
3、代码开发
代码开发部分,还是使用了IJPay框架。
因为当时只是进行了调研,所以只是写了一个测试用例
@Test
public void testProcess() throws Exception {
//时间戳
long timestamp = System.currentTimeMillis() / 1000;
//加密算法。固定值,目前不支持其他方式
String authType = "WECHATPAY2-SHA256-RSA2048";
//生成nonce_str
String nonceStr = WxPayKit.generateStr();
//商家转账到零钱的请求地址后缀
String urlSuffix = "/v3/fund-app/mch-transfer/transfer-bills";
//发起转账的商户号
String mchId = "15122xx159";
//非对称加密,公钥证书的证书序列号
String serialNo = "54823F07XXXXXXXXXF4FFF455BCB2063";
//非对称加密的私钥
String privateKey = "cert/apiclient_key.pem";
//转账业务信息
JSONObject rootJSON = baseInfo();
String body = JSONUtil.toJsonStr(rootJSON);
System.out.println("入参json:" + body);
// 调用IJPay框架的工具类生成待签名参数
String buildSignMessage = PayKit.buildSignMessage(RequestMethod.POST, urlSuffix, timestamp, nonceStr, body);
//调用IJPay框架的工具类生成签名
String signature = PayKit.createSign(buildSignMessage, privateKey);
System.out.println("signature:" + signature);
// 调用IJPay框架的工具类,根据平台规则生成请求头 authorization
String authorization = PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType);
System.out.println("Authorization:" + authorization);
//完整的"商家转账到零钱"的请求链接
String url = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills";
//调用Hutool包的工具类发起post请求
HttpResponse httpResponse = HttpRequest.post(url)
.header("Authorization", authorization)
.header("Accept", "application/json")
.header("Wechatpay-Serial", "54823F07XXXXXXXXXF4FFF455BCB2063")
.header("Content-Type", "application/json")
.body(body)
.execute();
System.out.println("出参json:" + JSON.toJSONString(httpResponse.body()));
}
//方法里的参数key名称,不要改,这是官方文档的要求。
private JSONObject baseInfo() {
JSONObject rootJSON = new JSONObject();
rootJSON.put("appid", "wx16adxxxxxx75f084d");
//商户单号,随机生成,但需要确保系统内唯一。
rootJSON.put("out_bill_no", "sdkdemobatXXXXX1736928718526");
//转账场景id,默认值1000,代表:现金营销。可以到微信支付后台申请开通其他场景
rootJSON.put("transfer_scene_id", "1000");
rootJSON.put("openid", "o0HMZAAxXXXXXXCChA-t5uhc2PUS7bE");
//转账金额,单位:分
rootJSON.put("transfer_amount", 10L);
rootJSON.put("transfer_remark", "转账备注1");
//转账活动备注
List<JSONObject> childList = getTransferSceneReportInfos();
rootJSON.put("transfer_scene_report_infos", childList);
return rootJSON;
}
private List<JSONObject> getTransferSceneReportInfos() {
List<JSONObject> childList = new ArrayList<>();
JSONObject childJSON1 = new JSONObject();
//注意,注意,注意!!这个info_type的值不能改,只能写:活动名称,否则就会调用失败。
childJSON1.put("info_type", "活动名称");
childJSON1.put("info_content", "活动有礼");
JSONObject childJSON2 = new JSONObject();
//这个也一样。这个info_type的值也不能改,只能写:奖励说明,否则就会调用失败。
childJSON2.put("info_type", "奖励说明");
childJSON2.put("info_content", "活动有礼的奖励说明");
childList.add(childJSON1);
childList.add(childJSON2);
return childList;
}
4、获取证书序列号
https://myssl.com/cert_decode.html
这是微信支付推荐的,查看证书序列号的网站,大家可以把自己的证书上传到这个网站,查看一下证书的序列化
5、注意事项
转账到零钱,其实没什么接入难度,主要就是按照官方文档的要求入参就行了。