微信支付-电商收付通开发-05.请求分账


需要注意的地方如下:

  • 需要分账的订单必须有分账标识;
  • 账期控制:可以控制二级商户的资金周结或月结。系统默认最长冻结周期180天,若超时仍未发起分账指令,该笔订单的剩余资金将自动解冻。
  • 订单分润:平台方可以抽取手续费,推广员/带货网红/分销员可以获得佣金,“分账完结”后订单资金全部解冻给二级商户。
  • 多次分账:一笔订单最大分账20次,单次分账最多5个分账接受方。
  • 已分账订单可退款。
    在这里插入图片描述

添加分账接收方

接受方是指接受资金的一方;

电商平台默认已经添加为接收方,其他接收方由电商平台通过“添加分账接收方”接口,建立平台维度统一的“分账接收方列表”,添加成功后,所有二级商户号均可向其分账。接收方可以是微信支付商户或微信支付的个人账户。

这里的测试类使用了电商平台作为接受方,调用结果当然是{“code”:“INVALID_REQUEST”,“message”:“操作已完成,无需二次请求”}

    /**
     * 添加分账接收方
     */
    @Test
    public void addReceivers() {
        JSONObject reqJsonObject = new JSONObject();
        //合单商户appid
        reqJsonObject.put("appid", WxPayConfig.merchantAppId);
        //接收方类型
        reqJsonObject.put("type", "MERCHANT_ID");
        //接收方账号,商户号或者个人openId
        reqJsonObject.put("account", WxPayConfig.merchantId);

        //接收方名称,商户全称如:张三网络公司
        reqJsonObject.put("name", "杭州张三网络有限公司");
        /* 与分账方的关系类型:
            SUPPLIER:供应商
            DISTRIBUTOR:分销商
            SERVICE_PROVIDER:服务商
            PLATFORM:平台
            OTHERS:其他
        */
        reqJsonObject.put("relation_type", "PLATFORM");

        String headerToken = WxPayUtils.getHeaderAuthorization("POST",
                HttpUrl.parse(WxPayConfig.profit_sharing_add_receivers_url), reqJsonObject.toJSONString());

        Map<String, String> headersMap = new HashMap<>();
        headersMap.put("User-Agent", WxPayConfig.userAgent);
        headersMap.put("Accept", "application/json");
        headersMap.put("Authorization", headerToken);
        headersMap.put("Wechatpay-Serial", WxPayConfig.api_v3_cert_serial_no);

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqJsonObject.toJSONString());
        ResponseAndStatusAndHeaders response = ClientUtil.getAndPostJson("POST", WxPayConfig.profit_sharing_add_receivers_url, requestBody, headersMap);
        if (response.getStatus() != Status.SUCCESS || response.getResponseData() == null) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "添加分账接收方接口请求错误,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + reqJsonObject + "\n\n");
            return;
        }
        LogUtil.printInfoLog(LogUtil.log_front_wxpay + "添加分账接收方接口请求成功,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + reqJsonObject + "\n\n");
    }

请求分账

最大分账比例为30%是指订单分账最多可以分出去30%,即保证供应商最少也有7成的收益。当然有些需求是让分账到供应商的多个账户之类,或者有多级供应商,这就导致30%分账无法满足业务。

如果要提高30%的最大分账比例,官方的回答是“联系BD”也不给联系方式…,所以目前微信根本不支持高比例分账,切实的办法还是使用三方MallBook之类的分账合作。

由于是单商户的分账,所以本次分账就已经分账完结了,分账订单完成后订单剩余资金会解冻到给二级商户。
如果是多次分账的话,每次分账,平台的分账订单号不能相同。

微信收取手续费是在分账之前,也就是先扣除手续费再算分账比例,否则会失败。


    /**
     * 请求分账
     */
    @Test
    public void order() throws Exception {
        JSONObject reqJsonObject = new JSONObject();
        //合单商户appid
        reqJsonObject.put("appid", WxPayConfig.merchantAppId);
        //合单商户,分账出资的商户号
        reqJsonObject.put("sub_mchid", WxPayConfig.testMerchantIdRxz);
        //微信订单号
        reqJsonObject.put("transaction_id", "4325300104202005287616306099");
        //电商平台 分账订单号
        reqJsonObject.put("out_order_no", "20200528807139");
        //是否完成分账
        reqJsonObject.put("finish", true);
        //分账接收方列表
        JSONArray receivers = new JSONArray();
        //分账接收方
        JSONObject receiver1 = new JSONObject();
        //分账接收商户号
        receiver1.put("receiver_mchid", WxPayConfig.merchantId);
        //分账金额,最大分账金额需小于全部金额的30%
        receiver1.put("amount", 2);
        //分账描述
        receiver1.put("description", "电商平台手续费+推广员收益代收");
        receivers.set(0, receiver1);
        reqJsonObject.put("receivers", receivers);

        String headerToken =WxPayUtils.getHeaderAuthorization("POST",
                HttpUrl.parse(WxPayConfig.profit_sharing_order_url), reqJsonObject.toJSONString());

        Map<String, String> headersMap = new HashMap<>();
        headersMap.put("User-Agent", WxPayConfig.userAgent);
        headersMap.put("Accept", "application/json");
        headersMap.put("Authorization", headerToken);
        headersMap.put("Wechatpay-Serial", WxPayConfig.api_v3_cert_serial_no);

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqJsonObject.toJSONString());
        ResponseAndStatusAndHeaders response = ClientUtil.getAndPostJson("POST", WxPayConfig.profit_sharing_order_url, requestBody, headersMap);
        if (response.getStatus() != Status.SUCCESS || response.getResponseData() == null) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "请求分账接口请求错误,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + reqJsonObject + "\n\n");
            return;
        }
        LogUtil.printInfoLog(LogUtil.log_front_wxpay + "请求分账接口请求成功,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + reqJsonObject + "\n\n");


        JSONObject jsonObject = JSON.parseObject(response.getResponseData().toString());
        String order_id = jsonObject.get("order_id").toString();
        System.out.println("分账成功,分账订单id为:" + order_id);
        //{"order_id":"30000101372020052700873705962","out_order_no":"20200527584262","sub_mchid":"1595728911","transaction_id":"4326700103202005271848011909"}
    }

分账动账结果回调通知

  • 配置分账通知:
    在服务商户后台【交易中心】-【分账接收设置】里可以设置分账回调地址。
    在这里插入图片描述
    配置了分账动账的回调URL后,也需要设置秘钥才能正常接受到通知,设置路径:【微信商户平台->账户中心->账户设置->API安全->密钥设置】

  • 调用分账接口或分账回退接口都会触发回调通知。

  • 需要在分账接受方对应的商户平台设置分账动账通知url,也只有分账接收方才能收到分账动账通知,分账方是不会有通知的。

注意:经过个人测试分账回调通知不太稳定,有时很快收到通知有时分账成功了还收不到通知,建议使用定时器轮询查询分账结果。

	/**
     * 微信分账回调通知
     */
    @PostMapping("sharingCallback")
    public JSONObject callBackNotifyForSharing(@RequestBody String requestJsonStr, @RequestHeader HttpHeaders headers, HttpServletResponse response) {
        LogUtil.printErrorLog(LogUtil.log_front_wxpay + "分账动账通知接受成功,header为:" + headers + "\n body为:" + requestJsonStr);

        //返回通知的应答报文,code(32):SUCCESS为清算机构接收成功;message(64):错误原因
        JSONObject responseJson = new JSONObject();
        responseJson.put("code", "FAIL");
        //支付通知http应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

        if (!headers.containsKey("Wechatpay-Serial") || !headers.containsKey("Wechatpay-Timestamp")
                || !headers.containsKey("Wechatpay-Nonce") || !headers.containsKey("Wechatpay-Signature")) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "回调请求header缺失");
            responseJson.put("message", "回调请求header缺失");
            return responseJson;
        }

        String WechatpaySerial = headers.getFirst("Wechatpay-Serial");//平台证书序列号
        String WechatpayTimestamp = headers.getFirst("Wechatpay-Timestamp");//应答时间戳
        String WechatpayNonce = headers.getFirst("Wechatpay-Nonce");//应答随机串
        String WechatpaySignature = headers.getFirst("Wechatpay-Signature"); //应答签名
        if (!WechatpaySerial.equals(WxPayConfig.api_v3_cert_serial_no)) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "回调请求证书序列化不一致");
            responseJson.put("message", "回调请求证书序列化不一致");
            return responseJson;
        }

        //获取签名串,验签
        String srcData = WechatpayTimestamp + "\n" + WechatpayNonce + "\n" + requestJsonStr + "\n";
        if (!WxPayUtils.verify(srcData, WechatpaySignature)) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "验签失败");
            responseJson.put("message", "验签失败");
            return responseJson;
        }

        JSONObject requestJson = JSONObject.parseObject(requestJsonStr);
        /*通知的类型,:
        PROFITSHARING:分账
        PROFITSHARING_RETURN:分账回退
        */
        String event_type = requestJson.get("event_type").toString();
        //通知数据
        JSONObject resource = JSONObject.parseObject(requestJson.get("resource").toString());
        //数据密文,Base64编码后的开启/停用结果数据密文
        String ciphertext = resource.get("ciphertext").toString();
        String associated_data = resource.get("associated_data").toString();
        String nonce = resource.get("nonce").toString();

        //密文串进行解密
        String verify = WxPayUtils.getNotifyData(associated_data, nonce, ciphertext);
        JSONObject sharingSuccess = JSONObject.parseObject(verify);
        //商户分账订单号
        String orderNo = sharingSuccess.get("out_order_no").toString();
        if (StrUtil.isBlank(orderNo)) {
            responseJson.put("message", "操作失败,未接受到商户分账订单号");
            return responseJson;
        }

        WxProfitSharingOrderDO wxProfitSharingOrder = wxProfitSharingOrderService.getById(orderNo);
        if (wxProfitSharingOrder == null) {
            responseJson.put("message", "操作失败,未查询到商户分账订单号");
            return responseJson;
        }
        if (wxProfitSharingOrder.getSharingStatus() != 1) {
            response.setStatus(HttpServletResponse.SC_OK);
            responseJson.put("code", "SUCCESS");
            responseJson.put("message", "微信分账成功,商户处理已结束,分账单号:" + wxProfitSharingOrder.getSharingOrderNo());
        }

        //分账成功
        if (event_type.equals("PROFITSHARING")) {
            boolean result = wxProfitSharingOrderService.updateSharingOrder(wxProfitSharingOrder, 2);
            if (result) {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "分账结果通知:分账成功,处理成功。分账单号为:" + wxProfitSharingOrder.getSharingOrderNo());
                response.setStatus(HttpServletResponse.SC_OK);
                responseJson.put("code", "SUCCESS");
                responseJson.put("message", "微信分账成功,商户处理成功,分账单号:" + wxProfitSharingOrder.getSharingOrderNo());
            } else {
                LogUtil.printErrorLog(LogUtil.log_front_wxpay + "分账结果通知:分账成功,处理失败。分账单号为:" + wxProfitSharingOrder.getSharingOrderNo());
                responseJson.put("message", "微信分账成功,商户处理失败,分账单号:" + wxProfitSharingOrder.getSharingOrderNo());
            }
            return responseJson;
        }
        return responseJson;
    }

查询分账结果

需要在接口后拼接上二级商户号、微信订单号和商户分账单号。

    /**
     * 查询分账接口
     */
    @Test
    public void queryOrder() {
        String param = "?sub_mchid=" + WxPayConfig.testMerchantId + "&transaction_id=" + "4326700103202005271848011909" + "&out_order_no=" + "20200527584262";
        String headerToken = WxPayUtils.getHeaderAuthorization("GET",
                HttpUrl.parse(WxPayConfig.profit_sharing_order_query_url + param), "");

        Map<String, String> headersMap = new HashMap<>();
        headersMap.put("User-Agent", WxPayConfig.userAgent);
        headersMap.put("Accept", "application/json");
        headersMap.put("Authorization", headerToken);
        headersMap.put("Wechatpay-Serial", WxPayConfig.api_v3_cert_serial_no);

        ResponseAndStatusAndHeaders response = ClientUtil.getAndPostJson("GET", WxPayConfig.profit_sharing_order_query_url + param, null, headersMap);
        if (response.getStatus() != Status.SUCCESS || response.getResponseData() == null) {
            LogUtil.printErrorLog(LogUtil.log_front_wxpay + "查询分账接口请求错误,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + param + "\n\n");
            return;
        }
        LogUtil.printInfoLog(LogUtil.log_front_wxpay + "查询分账接口请求成功,返回信息为:\n" + response.toString() + "\n请求的参数为:\n" + param + "\n\n");


        JSONObject jsonObject = JSON.parseObject(response.getResponseData().toString());
        String status = jsonObject.get("status").toString();
        System.out.println("分账结果为:" + status);
        //{"order_id":"30000101372020052700873705962","out_order_no":"20200527584262","receivers":[{"amount":9,"description":"电商平台手续费+推广员收益代收","finish_time":"2020-05-27T21:31:34+08:00","receiver_account":"1586786671","receiver_mchid":"1586786671","result":"SUCCESS","type":"MERCHANT_ID"},{"amount":21,"description":"解冻给分账方","finish_time":"2020-05-27T21:31:34+08:00","receiver_account":"1595728911","receiver_mchid":"1595728911","result":"SUCCESS","type":"MERCHANT_ID"}],"status":"FINISHED","sub_mchid":"1595728911","transaction_id":"4326700103202005271848011909"}
    }

参考链接

很多地方官方文档没有描述清楚或者压根没写的,比如返回“系统繁忙,请稍后重试”可能是你的传参有误,接口的错误状态也是有些混乱。可以参考微信社区的回答,但是还是要自己调用接口测试下实际情况。

分账接口文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/ecommerce/profitsharing/chapter1_1.shtml
(建议看下)分账接口常见问题官方回复:https://developers.weixin.qq.com/community/pay/doc/000284823e8460aada68dacca5b008?blockType=8%3FblockType%3D8%3FblockType%3D8
“微信支付服务商, 分账比例目前最高30%的比例, 怎么申请可以提高分账比例”的官方回复:
https://developers.weixin.qq.com/community/develop/doc/000ca68f484cd015863951b1556000
分账时“订单处理中,暂时无法分账,请稍后重试”的官方回复:https://developers.weixin.qq.com/community/pay/doc/0006e6b6198f5085ce6a1a92551000
接受不到分账通知的官方回复:https://developers.weixin.qq.com/community/develop/doc/00040c2395c7e088af39f13a35b400?highLine=%2520%25E5%2588%2586%25E8%25B4%25A6%25E5%259B%259E%25E8%25B0%2583%25E9%2580%259A%25E7%259F%25A5

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值