服务商模式微信分账教程

Last Modified: 2024/08/08

概述

本文将介绍如何在微信服务商模式下进行分账操作。注意本文基于微信支付 apiv2 版本,另外本文的目标是服务商模式下的分账,实现从特约商户分账到服务商商户,相当于服务商拿提成。

准备工作

第一步就是要找到微信分账的文档,另外商户又分为直连商户和服务商商户,我们要找的是服务商模式下的分账文档。以下分别是 v2 和 v3 版本的文档地址:

了解分账流程,这里放一张官方给出的分账流程图:

实现分账

可以随便拿个 Http Client 来实现分账,但是要处理签名,比较麻烦。官方提供了一个 sdk,可以点击这里查看使用方法

但这个 sdk 是 apiv3 版本,但本篇中我们要介绍的如何使用 apiv2 版本 api 来实现分账。好在有个 weixin-java-pay 库,这个库同时封装了微信分账的v2、v3 版本 api。

引入依赖

<dependency>
  <groupId>com.github.binarywang</groupId>
  <artifactId>weixin-java-pay</artifactId>
  <version>4.6.0</version>
</dependency>

分账

这里以从特约商户分账到服务商商户为例。首先要创建一个 ProfitSharingService 对象,该对象提供接口用来操作分账。该对象需要一个 WxPayService 对象,下面让我们创建一个 WxPayService 对象。

WxPayService 对象需要一个 WxPayConfig 对象,该对象提供微信支付的配置信息。该对象中属性可以通过登录 合作伙伴平台 获取。

WxPayService wxPayService = new WxPayServiceImpl();
WxPayConfig payConfig = new WxPayConfig();
//【产品中心】/【AppID账号管理】下找到 appId
payConfig.setAppId("服务商appId");
//【产品中心】/【开发配置】下找到商户号
payConfig.setMchId("服务商商户号");
//【产品中心】/【安全中心】页面可以设置 API 密钥,设置的时候注意保存,后续无法查看但可以重置。
payConfig.setMchKey("服务商商户号API密钥");
// 【产品中心】/【安全中心】找到 “API证书” 选项卡点击进入,下载证书。
// 解压后可以看到一个后缀为.p12 的证书。keyPath 便是这个 p12 证书的文件路径
payConfig.setKeyPath(keyPath);
wxPayService.setConfig(payConfig);

上面的 keyPath 就是后缀为 .p12 证书的路径。证书是一个压缩包,其中包含四个文件:

  • apiclient_cert.p12
  • apiclient_cert.pem
  • apiclient_key.pem
  • 证书使用说明.txt

注意保存上面三个文件,他们都将在后续的分账通知中使用到。接下来就可以创建一个 ProfitSharingService 对象了。

 ProfitSharingService srv = new ProfitSharingServiceImpl(wxPayService);

然后就可以通过 profitSharingService 的 profitSharing 发起分账请求了。既然是分账,那么肯定已经有了一笔微信支付订单,支付成功后,我们要记录订单号和微信订单号(transaction_id),以便后续分账使用。

ProfitSharingRequest req = new ProfitSharingRequest();
// subMchId 为分账方的商户号,它是服务商账号下的一个特约商户。
request.setSubMchId(subMchId);
// 服务商的商户号
req.setMchId(payConfig.getMchId());
// 服务商的 appId
req.setAppid(payConfig.getAppId());
// 查看分账文档中具体说明
req.setOutOrderNo(outOrderNo);
// 微信订单号
req.setTransactionId(transactionId);
req.setReceivers(receivers);
ProfitSharingResult profitSharingResult = profitSharingService.profitSharing(req);

subMchId 是分账方的商户号,它是服务商账号下的一个特约商户。它的订单产生的收入分给服务商一定的比例。其中分账接收方由 receivers 参数指定,类型为字符串,格式为 json 数组。

这里假设服务商的商户号为 190001001,订单支付金额为 1 元,也就是 100 分。如果分账比例为 10%,那么分给接收方的金额为 10 分钱。注意最大分账比例不能超过 30%。那么 receivers 对应的 json 串应该是下面这样的:

[{
	"type": "MERCHANT_ID",
	"account": "190001001",
	"amount": 10,
	"description": "销售分账"
}]

分账注意事项

  • 如果要对订单分账,必须在微信统一下单的时候传入 profit_sharing 参数,否则后续无法分账。
  • 在调用分账接口之前需要先调用添加分账接收方API接口来添加分账接收方,否则无法分账。或者通过微信商户平台添加分账接收方。

具体来说可在【商户平台 > 交易中心 > 管理分账接收方】中添加分账接收方。这里需要说明添加分账接收方是一次性操作,所以没必要通过接口来做,可直接通过微信商户平台来做。

如果在分账之前没有搞定分账接收方,再调用分账接口会返回错误:“服务商分账---分账接收方关系不存在,请检查参数中每个接收方的关系。

那有家人就要问了,什么是分账接收方呢?分账接收方就是接收分成的那一方,具体到我们这里,就是服务商商户。钱是直接到特约子商户的,特约子商户按照一定的比例分给服务商作为服务费。

处理分账通知

首先也是找到分账通知的文档地址:https://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=25_9&index=11。我们需要在合作伙伴平台找到【交易中心】/【分账】/【分账接收设置】中配置一个回调地址,用来接收分账通知。

处理分账通知最重要就是验证通知的真伪,验签文档:https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html

@RequestMapping("profitshare/notify")
@ResponseBody
public Object notify(@RequestBody String data,
                     @RequestHeader("Wechatpay-Nonce") String nonce,
                     @RequestHeader("Wechatpay-Signature") String sig,
                     @RequestHeader("Wechatpay-Timestamp") String timestamp,
                     @RequestHeader("Wechatpay-Serial") String serial) {
    Map<String, String> ret = new HashMap<>();
    WxPayService payService = new WxPayServiceImpl();
    WxPayConfig config = new WxPayConfig();
    config.setMchId("服务商商户号");
    config.setApiV3Key("apiv3 密钥");
    config.setPrivateCertPath("classpath:/certs/apiclient_cert.pem");
    config.setPrivateKeyPath("classpath:/certs/apiclient_key.pem");

    payService.setConfig(config);
    ProfitSharingService srv = new ProfitSharingServiceImpl(payService);
    SignatureHeader header = new SignatureHeader();
    header.setSignature(sig);
    header.setNonce(nonce);
    header.setSerial(serial);
    header.setTimeStamp(timestamp);
    try {
        srv.parseProfitSharingNotifyResult(data, header);
        ret.put("code", "SUCCESS");
        return ret;
    } catch (WxPayException exception) {
        logger.error("分账通知处理异常", exception);
    }
    ret.put("code", "FAIL");
    return ret;
}

以上代码的关键在于 srv.parseProfitSharingNotifyResult(data, header) 方法,如果调用该方法之后不抛异常则表明验签通过。

这里有个特别的地方在于,虽然我们使用了 v2 版本的 api 来实现分账,但是分账通知的验签需要用到 apiv3 版本的密钥。这一点在分账动账通知中有明确说明。

另外不推荐证书路径使用 “classpath:xx” 这种写法,这种写法在调试没有任何问题,打成 jar 包部署时可能会报找不到证书之类的错误,推荐使用绝对路径来指定证书路径。

有问题吗?点此反馈!

温馨提示:反馈需要登录