微信支付分账开发实例分析和部分源码讲解
1.微信支付分账简介
普通商户分账主要用于商户将交易成功的资金,按照一定的周期,分账给其他方,可以是合作伙伴、员工、用户或者其他分润方。

2. 使用场景
员工奖励:
零售、餐饮等行业中,当销售人员销售完成后,达到可奖励的条件,可以通过分账,将销售奖励分给员工。
管理资金到账时间:
在 酒店行业 中,利用分账功能中的“冻结/解冻”能力,避免用户退款时商户账户资金不足的情况。当用户预订/入住酒店时,交易资金先冻结在酒店的账户中;当用户确认消费离店后,再利用“分账”功能中的“分账完结”解冻资金到酒店的账户中。
分润给合作伙伴:
在与他方合作的情况下,可以用“分账”功能,将交易资金分给合作伙伴,例如物流合作商。
3. 名词解释
分账方: 将部分交易资金分出的一方,这里指直连商户本身。
分账接收方: 接收资金的一方,可以是商户,可以是个人。
4. 商户分账全流程
微信支付分账开发
5. 特性说明
待分账资金冻结,可实时分账或延时分账,实现管理账期
微信支付平台提供资金冻结的能力,所有需要分账的订单,待分账资金将先冻结在商户的商户号中,商户可根据实际业务情况,在交易完成后,实时(建议1分钟后)或30天内调分账接口,传输分账指令, 微信 支付平台将根据商户的指令进行分账。
基于每笔订单按金额进行分账,可单次或多次分账,每次分给多方
实际分账时,商户传入具体的分账接收方和分账金额进行订单分账。一笔订单最多可以分50次,每一次可以分给50方。
可分给微信商户账户或个人零钱
分账是在微信体系内进行的,分账接收方的账户可以是商户微信账户或个人零钱账户。
商户的超管须配置允许分账的最大比例
以下是分账的源码 实例
package com.java.demo; import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/merchant/4014931831 import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.Expose; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import java.io.IOException; import java.io.UncheckedIOException; import java.security.PrivateKey; import java.security.PublicKey; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 请求分账 */ public class CreateOrder { private static String HOST = "https://api.mch.weixin.qq.com"; private static String METHOD = "POST"; private static String PATH = "/v3/profitsharing/orders"; public static void main(String[] args) { // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/merchant/4013070756 CreateOrder client = new CreateOrder( "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 ); CreateOrderRequest request = new CreateOrderRequest(); request.appid = "wx8888888888888888"; request.transactionId = "4208450740201411110007820472"; request.outOrderNo = "P20150806125346"; request.receivers = new ArrayList<>(); { CreateOrderReceiver receiversItem = new CreateOrderReceiver(); receiversItem.type = "MERCHANT_ID"; receiversItem.account = "86693852"; receiversItem.name = client.encrypt("name"); receiversItem.amount = 888L; receiversItem.description = "分给商户A"; request.receivers.add(receiversItem); }; request.unfreezeUnsplit = true; try { OrdersEntity response = client.run(request); // TODO: 请求成功,继续业务逻辑 System.out.println(response); } catch (WXPayUtility.ApiException e) { // TODO: 请求失败,根据状态码执行不同的逻辑 e.printStackTrace(); } } public OrdersEntity run(CreateOrderRequest request) { String uri = PATH; String reqBody = WXPayUtility.toJson(request); Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); reqBuilder.addHeader("Accept", "application/json"); reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody)); reqBuilder.addHeader("Content-Type", "application/json"); RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody); reqBuilder.method(METHOD, requestBody); Request httpRequest = reqBuilder.build(); // 发送HTTP请求 OkHttpClient client = new OkHttpClient.Builder().build(); try (Response httpResponse = client.newCall(httpRequest).execute()) { String respBody = WXPayUtility.extractBody(httpResponse); if (httpResponse.code() >= 200 && httpResponse.code() < 300) { // 2XX 成功,验证应答签名 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, httpResponse.headers(), respBody); // 从HTTP应答报文构建返回数据 return WXPayUtility.fromJson(respBody, OrdersEntity.class); } else { throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); } } catch (IOException e) { throw new UncheckedIOException("Sending request to " + uri + " failed.", e); } } private final String mchid; private final String certificateSerialNo; private final PrivateKey privateKey; private final String wechatPayPublicKeyId; private final PublicKey wechatPayPublicKey; public CreateOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { this.mchid = mchid; this.certificateSerialNo = certificateSerialNo; this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); this.wechatPayPublicKeyId = wechatPayPublicKeyId; this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); } public String encrypt(String plainText) { return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText); } public static class CreateOrderRequest { @SerializedName("appid") public String appid; @SerializedName("transaction_id") public String transactionId; @SerializedName("out_order_no") public String outOrderNo; @SerializedName("receivers") public List<CreateOrderReceiver> receivers = new ArrayList<CreateOrderReceiver>(); @SerializedName("unfreeze_unsplit") public Boolean unfreezeUnsplit; } public static class OrdersEntity { @SerializedName("transaction_id") public String transactionId; @SerializedName("out_order_no") public String outOrderNo; @SerializedName("order_id") public String orderId; @SerializedName("state") public OrderStatus state; @SerializedName("receivers") public List<OrderReceiverDetail> receivers = new ArrayList<OrderReceiverDetail>(); } public static class CreateOrderReceiver { @SerializedName("type") public String type; @SerializedName("account") public String account; @SerializedName("name") public String name; @SerializedName("amount") public Long amount; @SerializedName("description") public String description; } public enum OrderStatus { @SerializedName("PROCESSING") PROCESSING, @SerializedName("FINISHED") FINISHED } public static class OrderReceiverDetail { @SerializedName("amount") public Long amount; @SerializedName("description") public String description; @SerializedName("type") public ReceiverType type; @SerializedName("account") public String account; @SerializedName("result") public DetailStatus result; @SerializedName("fail_reason") public DetailFailReason failReason; @SerializedName("create_time") public String createTime; @SerializedName("finish_time") public String finishTime; @SerializedName("detail_id") public String detailId; } public enum ReceiverType { @SerializedName("MERCHANT_ID") MERCHANT_ID, @SerializedName("PERSONAL_OPENID") PERSONAL_OPENID } public enum DetailStatus { @SerializedName("PENDING") PENDING, @SerializedName("SUCCESS") SUCCESS, @SerializedName("CLOSED") CLOSED } public enum DetailFailReason { @SerializedName("ACCOUNT_ABNORMAL") ACCOUNT_ABNORMAL, @SerializedName("NO_RELATION") NO_RELATION, @SerializedName("RECEIVER_HIGH_RISK") RECEIVER_HIGH_RISK, @SerializedName("RECEIVER_REAL_NAME_NOT_VERIFIED") RECEIVER_REAL_NAME_NOT_VERIFIED, @SerializedName("NO_AUTH") NO_AUTH, @SerializedName("RECEIVER_RECEIPT_LIMIT") RECEIVER_RECEIPT_LIMIT, @SerializedName("PAYER_ACCOUNT_ABNORMAL") PAYER_ACCOUNT_ABNORMAL, @SerializedName("INVALID_REQUEST") INVALID_REQUEST } }
查询分账结果
package com.java.demo; import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/merchant/4014931831 import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.Expose; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import java.io.IOException; import java.io.UncheckedIOException; import java.security.PrivateKey; import java.security.PublicKey; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 查询分账结果 */ public class QueryOrder { private static String HOST = "https://api.mch.weixin.qq.com"; private static String METHOD = "GET"; private static String PATH = "/v3/profitsharing/orders/{out_order_no}"; public static void main(String[] args) { // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/merchant/4013070756 QueryOrder client = new QueryOrder( "19xxxxxxxx", // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756 "1DDE55AD98Exxxxxxxxxx", // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053 "/path/to/apiclient_key.pem", // 商户API证书私钥文件路径,本地文件路径 "PUB_KEY_ID_xxxxxxxxxxxxx", // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816 "/path/to/wxp_pub.pem" // 微信支付公钥文件路径,本地文件路径 ); QueryOrderRequest request = new QueryOrderRequest(); request.outOrderNo = "P20150806125346"; request.transactionId = "4208450740201411110007820472"; try { OrdersEntity response = client.run(request); // TODO: 请求成功,继续业务逻辑 System.out.println(response); } catch (WXPayUtility.ApiException e) { // TODO: 请求失败,根据状态码执行不同的逻辑 e.printStackTrace(); } } public OrdersEntity run(QueryOrderRequest request) { String uri = PATH; uri = uri.replace("{out_order_no}", WXPayUtility.urlEncode(request.outOrderNo)); Map<String, Object> args = new HashMap<>(); args.put("transaction_id", request.transactionId); String queryString = WXPayUtility.urlEncode(args); if (!queryString.isEmpty()) { uri = uri + "?" + queryString; } Request.Builder reqBuilder = new Request.Builder().url(HOST + uri); reqBuilder.addHeader("Accept", "application/json"); reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId); reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, null)); reqBuilder.method(METHOD, null); Request httpRequest = reqBuilder.build(); // 发送HTTP请求 OkHttpClient client = new OkHttpClient.Builder().build(); try (Response httpResponse = client.newCall(httpRequest).execute()) { String respBody = WXPayUtility.extractBody(httpResponse); if (httpResponse.code() >= 200 && httpResponse.code() < 300) { // 2XX 成功,验证应答签名 WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, httpResponse.headers(), respBody); // 从HTTP应答报文构建返回数据 return WXPayUtility.fromJson(respBody, OrdersEntity.class); } else { throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers()); } } catch (IOException e) { throw new UncheckedIOException("Sending request to " + uri + " failed.", e); } } private final String mchid; private final String certificateSerialNo; private final PrivateKey privateKey; private final String wechatPayPublicKeyId; private final PublicKey wechatPayPublicKey; public QueryOrder(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) { this.mchid = mchid; this.certificateSerialNo = certificateSerialNo; this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath); this.wechatPayPublicKeyId = wechatPayPublicKeyId; this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath); } public static class QueryOrderRequest { @SerializedName("transaction_id") @Expose(serialize = false) public String transactionId; @SerializedName("out_order_no") @Expose(serialize = false) public String outOrderNo; } public static class OrdersEntity { @SerializedName("transaction_id") public String transactionId; @SerializedName("out_order_no") public String outOrderNo; @SerializedName("order_id") public String orderId; @SerializedName("state") public OrderStatus state; @SerializedName("receivers") public List<OrderReceiverDetail> receivers = new ArrayList<OrderReceiverDetail>(); } public enum OrderStatus { @SerializedName("PROCESSING") PROCESSING, @SerializedName("FINISHED") FINISHED } public static class OrderReceiverDetail { @SerializedName("amount") public Long amount; @SerializedName("description") public String description; @SerializedName("type") public ReceiverType type; @SerializedName("account") public String account; @SerializedName("result") public DetailStatus result; @SerializedName("fail_reason") public DetailFailReason failReason; @SerializedName("create_time") public String createTime; @SerializedName("finish_time") public String finishTime; @SerializedName("detail_id") public String detailId; } public enum ReceiverType { @SerializedName("MERCHANT_ID") MERCHANT_ID, @SerializedName("PERSONAL_OPENID") PERSONAL_OPENID } public enum DetailStatus { @SerializedName("PENDING") PENDING, @SerializedName("SUCCESS") SUCCESS, @SerializedName("CLOSED") CLOSED } public enum DetailFailReason { @SerializedName("ACCOUNT_ABNORMAL") ACCOUNT_ABNORMAL, @SerializedName("NO_RELATION") NO_RELATION, @SerializedName("RECEIVER_HIGH_RISK") RECEIVER_HIGH_RISK, @SerializedName("RECEIVER_REAL_NAME_NOT_VERIFIED") RECEIVER_REAL_NAME_NOT_VERIFIED, @SerializedName("NO_AUTH") NO_AUTH, @SerializedName("RECEIVER_RECEIPT_LIMIT") RECEIVER_RECEIPT_LIMIT, @SerializedName("PAYER_ACCOUNT_ABNORMAL") PAYER_ACCOUNT_ABNORMAL, @SerializedName("INVALID_REQUEST") INVALID_REQUEST } }
软件开发微信:15889726201

浙公网安备 33010602011771号