业务示例代码
更新时间:2025.09.261. 分账
通过分账接口,根据实际业务场景将交易款项分账到其他业务参与方的账户(如:平台抽取佣金),目前默认最高分账比例30%;同时通过该接口,实现合单交易冻结资金的解冻,从而实现对二级商户的账期管理和资金分配。
适用于已开通平台收付通的平台及二级商户,平台可通过供应链分账实现对平台二级商户的账期管理和资金分配。
1.1 使用场景
二级商户账期管理:二级商户直接收款,平台通过供应链分账的冻结解冻能力实现对二级商户账期的管理。
平台交易抽成:二级商户直接收款,平台根据二级商户的每笔交易实现服务费的在线抽成。
分账给供应商、达人或其他分账方:二级商户直接收款,按每笔交易分账给二级商户上游的供应商、下游分销的达人、或者其他分润方。
1.2 产品模型

分账发起方: 发起分账的一方,这里指平台。
分账方: 交易的直接收款方,平台二级商户。
接收方: 接收资金的一方,平台已被默认添加为接收方,二级商户可直接向平台进行分账;其他接收方,平台通过添加分账接收方接口,建立平台维度统一的分账接收方列表,添加成功后,所有二级商户号均可向其分账。接收方可以是微信支付商户或微信支付的个人账户。
1.3 功能特点
需分账的订单,平台在下单时打上分账标识。
周期可控: 平台根据平台运营规则,可对交易订单准实时(支付成功后30s)分账,或按周期延时分账,并完结分账(解冻订单未分账资金)。系统默认最长冻结周期默认180天,若超时仍未发起分账指令,该笔订单的剩余资金将自动解冻。
多次分账+多方分账: 同一笔订单最多分账50次,每次分账可最多向50个接收方分账。
状态可查+支持回退: 提供接口查询分账结果;若已分账的订单需要退款,对于商户类型的分账接收方,平台可发起分账回退,将已分账资金回退回分账方账户。
2. 目标
通过本文档的学习可以利用分账相关接口完成分账流程操作
3. 业务处理流程
3.1 分账
微信订单支付成功后,平台商户可以在180天内发起分账,超过180天的订单,微信支付系统会自动把该笔订单剩余未分金额解冻给二级子商户
分账的流程正常是:
先通过 请求分账 查询订单的剩余可分金额
通过 添加分账接收方 添加分账接收方
通过 请求分账 发起分账,分账接收方的总金额不能超过步骤1中返回的剩余可分金额,同时分账接收方的总金额不能超过这笔订单全部可分金额的30%(分账给其他商户或者其他人的,不包括解冻给二级子商户的资金), 请求分账 是受理型接口,即请求分账接口成功之后不代表分账成功,需要通过 查询分账结果 查询分账的最终结果
发起分账成功之后,可以通过 查询分账结果 查询分账结果
分账单状态:
分账接收方分账结果:
1package com.java.ecommerce.profitsharing; 2 3import com.java.demo.QueryOrderAmount; // 使用查询订单剩余待分金额接口:https://pay.weixin.qq.com/doc/v3/partner/4012477751 4import static com.java.demo.QueryOrderAmount.*; 5import com.java.demo.AddReceiver; // 使用添加分账接收方接口:https://pay.weixin.qq.com/doc/v3/partner/4012477758 6import static com.java.demo.AddReceiver.*; 7import com.java.demo.CreateOrder; // 使用请求分账接口:https://pay.weixin.qq.com/doc/v3/partner/4012691594 8import static com.java.demo.CreateOrder.*; 9import com.java.demo.QueryOrder; // 使用查询分账结果接口:https://pay.weixin.qq.com/doc/v3/partner/4012477734 10import static com.java.demo.QueryOrder.*; 11import com.java.demo.FinishOrder; // 使用请求分账完结接口:https://pay.weixin.qq.com/doc/v3/partner/4012477745 12import static com.java.demo.FinishOrder.*; 13import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/partner/4014985777 14 15import java.util.ArrayList; 16 17public class ProfitSharingDemo { 18 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 19 // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 20 // https://pay.weixin.qq.com/doc/v3/partner/4013080340 21 private static String mchid = "19xxxxxxxx"; 22 // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 23 private static String certificateSerialNo = "1DDE55AD98Exxxxxxxxxx"; 24 // 商户API证书私钥文件路径,本地文件路径 25 private static String privateKeyFilePath = "/path/to/apiclient_key.pem"; 26 // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 27 private static String wechatPayPublicKeyId = "PUB_KEY_ID_xxxxxxxxxxxxx"; 28 // 微信支付公钥文件路径,本地文件路径 29 private static String wechatPayPublicKeyFilePath = "/path/to/wxp_pub.pem"; 30 31 public static void main(String[] argv) { 32 String transactionId = "4208450740201411110007820472"; 33 ProfitSharingDemo demo = new ProfitSharingDemo(); 34 35 // 建议用户支付完成30s之后,再发起分账请求 36 37 // 1. 查询订单剩余待分金额 38 long unsplitAmount = demo.getUnsplitAmount(transactionId); 39 if (unsplitAmount <= 0) { 40 // 该笔订单没有可分金额了,不能发起分账,退出 41 return; 42 } 43 44 // 2. 添加分账接收方(若已添加过的分账接收方无需重复添加,可跳过这步骤。) 45 demo.addReceiver(); 46 47 // 3. 申请分账(分账的金额一定小于等于步骤1返回的订单剩余待分金额) 48 // 商户分账单号需系统内唯一,且完结分账的商户分账单号与请求分账单号不可以一致。 49 String outOrderNo = "P20150806125346"; 50 demo.applyProfitSharing(transactionId, outOrderNo); 51 52 // 4. 查询分账结果 53 // 步骤三申请分账成功,不代表分账成功,需要查询分账结果才执行,建议申请分账成功之后等5分钟之后再查询分账结果 54 demo.queryProfitSharingResult(transactionId, outOrderNo); 55 56 // 5. 完结分账(如果订单不需要分账给其他商户或者用户并且订单还有剩余可分金额时,可以请求完结分账接口,把剩余可分金额解冻给二级商户) 57 outOrderNo = "P20150806125347"; 58 demo.FinishProfitSharing(transactionId, outOrderNo); 59 60 // 6. 查询完结分账结果 61 // 步骤五完结分账成功,不代表完结分账成功,需要查询分账结果才执行,建议完结分账成功之后等5分钟之后再查询分账结果 62 demo.queryProfitSharingResult(transactionId, outOrderNo); 63 } 64 65 private long getUnsplitAmount(String transactionId) { 66 QueryOrderAmount client = new QueryOrderAmount( 67 mchid, 68 certificateSerialNo, 69 privateKeyFilePath, 70 wechatPayPublicKeyId, 71 wechatPayPublicKeyFilePath); 72 QueryOrderAmountRequest request = new QueryOrderAmountRequest(); 73 request.transactionId = transactionId; 74 try { 75 QueryOrderAmountResponse response = client.run(request); 76 return response.unsplitAmount; 77 } catch (WXPayUtility.ApiException e) { 78 // 异常处理逻辑 79 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 80 // 错误:系统错误 81 // 解决方式:稍后重试 82 // 描述:微信支付系统失败,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 83 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 84 // 错误:限频报错 85 // 解决方式:稍后重试 86 // 描述: 接口频率限制,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 87 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 88 // 错误:签名错误 89 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 90 // 描述:签名报错,需要确认签名材料和签名流程是否正确 91 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 92 // 错误:参数错误 93 // 解决方式:按照报错返回的message,重新输入请求参数 94 // 描述:参数的类型,长度,或者必填选项没有填写等,大概率是传的微信支付订单号是非法的 95 } else if (e.getErrorCode().equals("ORDER_NOT_EXIST")) { 96 // 错误:订单不存在 97 // 解决方式:查询的订单不存在,大概率是该笔订单和对应的商户不一致 98 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 99 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 100 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试 101 // 描述:不符合业务规则的场景如: 102 // - 订单还未结算完成,请等分账完成后再发起分账,一般等待2分钟即可 103 // - 非分账订单 104 } else { 105 // 其他类型错误:稍等一会后原单重试 106 } 107 throw e; 108 } 109 } 110 111 private void addReceiver() { 112 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 113 AddReceiver client = new AddReceiver( 114 mchid, 115 certificateSerialNo, 116 privateKeyFilePath, 117 wechatPayPublicKeyId, 118 wechatPayPublicKeyFilePath); 119 120 AddReceiverRequest request = new AddReceiverRequest(); 121 request.appid = "wx8888888888888888"; 122 request.type = "MERCHANT_ID"; 123 request.account = "190001001"; 124 request.name = "示例商户全称"; 125 request.relationType = "SUPPLIER"; 126 try { 127 AddReceiverResponse response = client.run(request); 128 // 添加分账接收方成功 129 // 可以发起分账 130 } catch (WXPayUtility.ApiException e) { 131 // 异常处理逻辑 132 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 133 // 错误:系统错误 134 // 解决方式:稍后重试 135 // 描述:微信支付系统失败,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 136 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 137 // 错误:限频报错 138 // 解决方式:稍后重试 139 // 描述: 接口频率限制,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 140 } else if (e.getErrorCode().equals("NO_AUTH")) { 141 // 错误:无分账权限 142 // 解决方式: 检查商户是否是被处罚:登录商户平台进入账户中心-违约记录查询是否违约记录,如果有按照上面的指引解决违约记录之后重试 143 // 描述:平台商户被处罚或者平台商户和二级商户没有父子受理关系 144 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 145 // 错误:签名错误 146 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 147 // 描述:签名报错,需要确认签名材料和签名流程是否正确 148 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 149 // 错误:参数错误 150 // 解决方式:按照报错返回的message,重新输入请求参数 151 // 描述:参数的类型,长度,或者必填选项没有填写等 152 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 153 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 154 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试 155 // 描述:不符合业务规则的场景如: 156 // - 分账接收用户没有实名 157 // - 分账接收商户不存在 158 // - 分账给用户传的appid和openid不匹配 159 // - 分账接收商户全称不匹配 160 } else { 161 // 其他类型错误:稍等一会后原单重试 162 } 163 throw e; 164 } 165 } 166 167 private void applyProfitSharing(String transactionId, String outOrderNo) { 168 CreateOrder client = new CreateOrder( 169 mchid, 170 certificateSerialNo, 171 privateKeyFilePath, 172 wechatPayPublicKeyId, 173 wechatPayPublicKeyFilePath); 174 175 CreateOrderRequest request = new CreateOrderRequest(); 176 request.appid = "wx8888888888888888"; 177 request.subMchid = "1900000109"; 178 request.transactionId = transactionId; 179 request.outOrderNo = outOrderNo; 180 request.receivers = new ArrayList<>(); 181 // 分账给商户 182 { 183 CreateOrderReceiver reciever = new CreateOrderReceiver(); 184 reciever.type = "MERCHANT_ID"; 185 reciever.receiverAccount = "1900000109"; 186 reciever.receiverMchid = "1900000110"; 187 reciever.amount = 1L; 188 reciever.description = "分给商户1900000110"; 189 reciever.receiverName = client.encrypt("商户1900000110的全称"); 190 request.receivers.add(reciever); 191 } 192 // 分账给用户 193 { 194 CreateOrderReceiver reciever = new CreateOrderReceiver(); 195 reciever.type = "PERSONAL_OPENID"; 196 reciever.receiverAccount = "oLIsd5O4GKSw4Qcsv2cQAk_mS"; 197 reciever.amount = 2L; 198 reciever.description = "分给用户"; 199 reciever.receiverName = client.encrypt("用户oLIsd5O4GKSw4Qcsv2cQAk_mS的姓名"); 200 request.receivers.add(reciever); 201 } 202 // 注意 203 // 上面分给商户的金额+分给用户的金额之和不能大于步骤1返回的订单剩余待分金额 204 // 同时分给商户的金额+分给用户的金额之和不能超过该笔订单的总的可分金额的30% 205 // 每次分账最多可分给50个接收方 206 // 同一个分账请求内,不支持有重复的接收方 207 208 // 是否分账完成 209 // 为true时:该笔订单剩余所有的未分金额都会自动解冻给二级商户 210 // 为false时:该笔订单剩余所有的未分金额不会解冻给二级商户,该笔订单的剩余可分金额还可以继续分账 211 // 一笔订单最多可以发起50次分账 212 request.finish = false; 213 try { 214 CreateOrderResponse response = client.run(request); 215 // 请求分账成功,但是不代表分账成功,需要通过查询分账结果来判断分账是否成功 216 } catch (WXPayUtility.ApiException e) { 217 // 异常处理逻辑 218 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 219 // 错误:系统错误 220 // 解决方式:稍后原单重试 221 // 描述:微信支付系统失败,一定要原单重试,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 222 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 223 // 错误:限频报错 224 // 解决方式:稍后原单重试 225 // 描述: 接口频率限制,一定要原单重试,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 226 } else if (e.getErrorCode().equals("NO_AUTH")) { 227 // 错误:无分账权限 228 // 解决方式: 检查商户是否是被处罚:登录商户平台进入账户中心-违约记录查询是否违约记录,如果有按照上面的指引解决违约记录之后原单重试 229 // 描述:平台商户被处罚或者平台商户和二级商户没有父子受理关系 230 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 231 // 错误:签名错误 232 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 233 // 描述:签名报错,需要确认签名材料和签名流程是否正确 234 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 235 // 错误:参数错误 236 // 解决方式:按照报错返回的message,重新输入请求参数 237 // 描述:参数的类型,长度,或者必填选项没有填写等 238 } else if (e.getErrorCode().equals("NOT_ENOUGH")) { 239 // 错误:账户余额不足 240 // 解决方式:商户充值之后原单重试 241 // 描述:商户账户余额不足,导致退款失败,商户充值之后一定要原单重试 242 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 243 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 244 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试 245 // 描述:不符合业务规则的场景如: 246 // - 分账次数过多,该笔订单分账次数已经超过50次了,不能再发起分账了 247 // - 该笔订单还未结算完成,请等待结算完成才能发起分账 248 // - 剩余可分账金额不足 249 // - 小程序交易被冻结,在用户主动/系统自动确认收货后才进行资金结算,详细规则可查看《交易类小程序运营规范》 250 // - 订单已过期,不支持分账,请等待系统自动解冻(订单已经超过180天,不允许发起分账) 251 252 } else { 253 // 其他类型错误:稍等一会后原单重试 254 } 255 throw e; 256 } 257 } 258 259 private void queryProfitSharingResult(String transactionId, String outOrderNo) { 260 QueryOrder client = new QueryOrder( 261 mchid, 262 certificateSerialNo, 263 privateKeyFilePath, 264 wechatPayPublicKeyId, 265 wechatPayPublicKeyFilePath); 266 267 QueryOrderRequest request = new QueryOrderRequest(); 268 request.subMchid = "1900000109"; 269 request.transactionId = transactionId; 270 request.outOrderNo = outOrderNo; 271 try { 272 QueryOrderResponse response = client.run(request); 273 // 1. 根据分账单状态处理分账结果 274 switch (response.status) { 275 case "PROCESSING": 276 // 分账处理中 277 // 稍等2分钟之后再重新查单,直到分账单状态为FINISHED 278 break; 279 case "FINISHED": 280 // 分账完成,检查每个接收方状态 281 for (QueryOrder.OrderReceiverDetail receiver : response.receivers) { 282 switch (receiver.result) { 283 case "SUCCESS": 284 // 分账成功 285 // 处理商户自己的业务逻辑 286 break; 287 case "CLOSED": 288 // 分账失败 289 // 分账给该分账方失败了,可以通过receiver.failReason查看失败原因,对应的处理指引见:https://pay.weixin.qq.com/doc/v3/partner/4015504955 290 // 商户如果根据失败原因做了相应的处理,可以换单重新发起分账 291 break; 292 default: 293 // 非法状态,因为上面分账单已经是FINISHED状态了,所以分账接收方的状态也不会出现pending状态 294 throw new RuntimeException("非法分账接收方状态:" + receiver.result); 295 } 296 } 297 break; 298 default: 299 // 非法状态 300 throw new RuntimeException("非法分账单状态:" + response.status); 301 } 302 } catch (WXPayUtility.ApiException e) { 303 // 异常处理逻辑 304 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 305 // 错误:系统错误 306 // 解决方式:稍后重试 307 // 描述:微信支付系统失败,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 308 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 309 // 错误:限频报错 310 // 解决方式:稍后重试 311 // 描述: 接口频率限制,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 312 } else if (e.getErrorCode().equals("NO_AUTH")) { 313 // 错误:无分账权限 314 // 解决方式:检查商户是否是被处罚:登录商户平台进入账户中心-违约记录查询是否违约记录,如果有按照上面的指引解决违约记录之后重试 315 // 描述:平台商户被处罚或者平台商户和二级商户没有父子受理关系 316 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 317 // 错误:签名错误 318 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 319 // 描述:签名报错,需要确认签名材料和签名流程是否正确 320 } else if (e.getErrorCode().equals("RESOURCE_NOT_EXISTS")) { 321 // 错误:分账单不存在 322 // 解决方式:确定outOrderId和transactionId输入是否正确 323 // 描述:申请分账未成功 324 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 325 // 错误:参数错误 326 // 解决方式:按照报错返回的message,重新输入请求参数 327 // 描述:参数的类型,长度,或者必填选项没有填写等 328 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 329 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 330 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再重试 331 // 描述:不符合业务规则的场景如: 332 // - 电商商户不允许调用非电商分账API 333 } else { 334 // 其他类型错误:稍等一会后原单重试 335 } 336 throw e; 337 } 338 } 339 340 private void FinishProfitSharing(String transactionId, String outOrderNo) { 341 342 FinishOrder client = new FinishOrder( 343 mchid, 344 certificateSerialNo, 345 privateKeyFilePath, 346 wechatPayPublicKeyId, 347 wechatPayPublicKeyFilePath); 348 349 FinishOrderRequest request = new FinishOrderRequest(); 350 request.subMchid = "1900000109"; 351 request.transactionId = transactionId; 352 request.outOrderNo = outOrderNo; 353 request.description = "分账完结"; 354 try { 355 FinishOrderResponse response = client.run(request); 356 // 请求完结分账成功,但是不代表完结分账成功,需要通过查询分账结果来判断分账是否成功 357 } catch (WXPayUtility.ApiException e) { 358 // 异常处理逻辑 359 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 360 // 错误:系统错误 361 // 解决方式:稍后原单重试 362 // 描述:微信支付系统失败,一定要原单重试,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 363 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 364 // 错误:限频报错 365 // 解决方式:稍后原单重试 366 // 描述: 接口频率限制,一定要原单重试,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 367 } else if (e.getErrorCode().equals("NO_AUTH")) { 368 // 错误:无分账权限 369 // 解决方式:检查商户是否是被处罚:登录商户平台进入账户中心-违约记录查询是否违约记录,如果有按照上面的指引解决违约记录之后原单重试 370 // 描述:平台商户被处罚或者平台商户和二级商户没有父子受理关系 371 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 372 // 错误:签名错误 373 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 374 // 描述:签名报错,需要确认签名材料和签名流程是否正确 375 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 376 // 错误:参数错误 377 // 解决方式:按照报错返回的message,重新输入请求参数 378 // 描述:参数的类型,长度,或者必填选项没有填写等 379 } else if (e.getErrorCode().equals("NOT_ENOUGH")) { 380 // 错误:账户余额不足 381 // 解决方式:商户充值之后原单重试 382 // 描述:商户账户余额不足,导致退款失败,商户充值之后一定要原单重试 383 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 384 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 385 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试 386 // 描述:不符合业务规则的场景如: 387 // - 分账次数过多,该笔订单分账次数已经超过50次了,不能再发起分账了 388 // - 该笔订单还未结算完成,请等待结算完成才能发起分账 389 // - 剩余可分账金额不足 390 // - 小程序交易被冻结,在用户主动/系统自动确认收货后才进行资金结算,详细规则可查看《交易类小程序运营规范》 391 // - 订单已过期,不支持分账,请等待系统自动解冻(订单已经超过180天,不允许发起分账) 392 393 } else { 394 // 其他类型错误:稍等一会后原单重试 395 } 396 throw e; 397 } 398 } 399} 400
3.2 分账回退
当成功分账给商户之后(分账给用户不支持分账回退),如果因为退款需要回退分账金额时,可以请求分账回退接口退还分账给商户的资金,请求分账回退接口会交易分账订单的状态,只有发生过退款的分账单才支持分账回退
分账回退接口为同步接口,接口返回成功即代表回退到终态,但是可能是回退成功或者回退失败,需要根据回退结果来判断,如果请求回退返回报错,可以通过查询分账回退结果接口查询分账回退结果
分账回退单状态机:

1package com.java.ecommerce.profitsharing; 2 3import com.java.demo.CreateReturnOrder; // 使用请求分账回退接口:https://pay.weixin.qq.com/doc/v3/partner/4012477737 4import static com.java.demo.CreateReturnOrder.*; 5import com.java.demo.QueryReturnOrder; // 使用查询分账回退结果接口:https://pay.weixin.qq.com/doc/v3/partner/4012477740 6import static com.java.demo.QueryReturnOrder.*; 7import com.java.utils.WXPayUtility; // 引用微信支付工具库,参考:https://pay.weixin.qq.com/doc/v3/partner/4014985777 8 9public class ProfitSharingReturnDemo { 10 // TODO: 请准备商户开发必要参数,参考:https://pay.weixin.qq.com/doc/v3/partner/4013080340 11 // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 12 // https://pay.weixin.qq.com/doc/v3/partner/4013080340 13 private static String mchid = "19xxxxxxxx"; 14 // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013058924 15 private static String certificateSerialNo = "1DDE55AD98Exxxxxxxxxx"; 16 // 商户API证书私钥文件路径,本地文件路径 17 private static String privateKeyFilePath = "/path/to/apiclient_key.pem"; 18 // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/partner/4013038589 19 private static String wechatPayPublicKeyId = "PUB_KEY_ID_xxxxxxxxxxxxx"; 20 // 微信支付公钥文件路径,本地文件路径 21 private static String wechatPayPublicKeyFilePath = "/path/to/wxp_pub.pem"; 22 23 public static void main(String[] args) { 24 ProfitSharingReturnDemo demo = new ProfitSharingReturnDemo(); 25 // 发起分账回退 26 demo.returnProfitSharing(); 27 } 28 29 private void returnProfitSharing() { 30 CreateReturnOrder client = new CreateReturnOrder( 31 mchid, 32 certificateSerialNo, 33 privateKeyFilePath, 34 wechatPayPublicKeyId, 35 wechatPayPublicKeyFilePath); 36 37 CreateReturnOrderRequest request = new CreateReturnOrderRequest(); 38 request.subMchid = "1900000109"; 39 40 // orderId和outOrderNo二选一 41 // orderId是微信支付分账单号,即请求分账返回的orderId 42 // outOrderNo是商户分账单号,即请求分账时传入的outOrderNo 43 request.orderId = "3008450740201411110007820472"; 44 // request.outOrderNo = "P20150806125346"; 45 request.outReturnNo = "R20190516001"; 46 request.returnMchid = "86693852"; 47 // 分账回退金额不能超过分账给该商户的金额 48 request.amount = 10L; 49 request.description = "分账回退"; 50 request.transactionId = "4208450740201411110007820472"; 51 try { 52 CreateReturnOrderResponse response = client.run(request); 53 // 请求分账回退成功,即代表分账回退单到终态,但是可能是回退成功,也可能回退失败 54 switch (response.result) { 55 case "SUCCESS": 56 // 分账回退成功 57 // 商户处理自己的业务逻辑 58 break; 59 case "FAILED": 60 // 分账回退失败 61 // 可以查看response.failReason查看失败原因 62 // 如果商户根据failReason做了相应的处理,可以换单重新发起分账回退,不能原单重试了 63 break; 64 default: 65 // 非法状态,PROCESSING状态也不会出现,因为分账回退接口是同步接口,接口返回成功即代表分账回退单到终态 66 throw new RuntimeException("非法分账回退状态:" + response.result); 67 } 68 69 } catch (WXPayUtility.ApiException e) { 70 // 异常处理逻辑 71 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 72 // 错误:系统错误 73 // 解决方式:稍后原单重试,也可以通过查询分账回退结果进行处理(demo.queryProfitSharingReturnResult()) 74 // 描述:微信支付系统失败,一定要原单重试,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 75 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 76 // 错误:限频报错 77 // 解决方式:稍后原单重试 78 // 描述: 接口频率限制,一定要原单重试,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 79 } else if (e.getErrorCode().equals("NO_AUTH")) { 80 // 错误:无分账权限 81 // 解决方式:检查商户是否是被处罚:登录商户平台进入账户中心-违约记录查询是否违约记录,如果有按照上面的指引解决违约记录之后原单重试 82 // 描述:平台商户被处罚或者平台商户和二级商户没有父子受理关系 83 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 84 // 错误:签名错误 85 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 86 // 描述:签名报错,需要确认签名材料和签名流程是否正确 87 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 88 // 错误:参数错误 89 // 解决方式:按照报错返回的message,重新输入请求参数 90 // 描述:参数的类型,长度,或者必填选项没有填写等 91 } else if (e.getErrorCode().equals("NOT_ENOUGH")) { 92 // 错误:账户余额不足 93 // 解决方式:商户充值之后原单重试 94 // 描述:商户账户余额不足,导致退款失败,商户充值之后一定要原单重试 95 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 96 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 97 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试 98 // 描述:不符合业务规则的场景如: 99 // - 分账单存在,或超过分账回退时效(只能回退180天内的分账单),请检查对应的分账单 100 // - 超过分账回退最大周期(只能回退180天内的分账单) 101 // - 剩余可回退的金额不足 102 // - 当前商户号暂不能进行“资金收款类”相关业务操作,可前往“商户平台>账户中心>违约记录”或“商家助手小程序>风险处理”了解原因 103 // - 分账回退出资商户不允许和接收商户相同,请重新输入回退商户号 104 105 } else { 106 // 其他类型错误:稍等一会后原单重试,也可以通过查询分账回退结果进行处理(demo.queryProfitSharingReturnResult()) 107 } 108 throw e; 109 } 110 } 111 112 private void queryProfitSharingReturnResult() { 113 QueryReturnOrder client = new QueryReturnOrder( 114 mchid, 115 certificateSerialNo, 116 privateKeyFilePath, 117 wechatPayPublicKeyId, 118 wechatPayPublicKeyFilePath); 119 120 QueryReturnOrderRequest request = new QueryReturnOrderRequest(); 121 request.subMchid = "1900000109"; 122 request.outReturnNo = "R20190516001"; 123 request.orderId = "4208450740201411110007820472"; 124 request.outOrderNo = "P20190806125346"; 125 try { 126 QueryReturnOrderResponse response = client.run(request); 127 // 根据response.result处理分账回退结果 128 switch (response.result) { 129 case "PROCESSING": 130 // 分账回退处理中 131 // 稍等2分钟之后再重新查单,直到分账回退单状态为SUCCESS或FAILED 132 // 也可以原单重试请求分账回退接口 133 break; 134 case "SUCCESS": 135 // 分账回退成功 136 // 商户处理自己的业务逻辑 137 break; 138 case "FAILED": 139 // 分账回退失败 140 // 可以查看response.failReason查看失败原因 141 // 如果商户根据failReason做了相应的处理,可以换单重新发起分账回退,不能原单重试了 142 break; 143 default: 144 // 非法状态 145 throw new RuntimeException("非法分账回退状态:" + response.result); 146 } 147 } catch (WXPayUtility.ApiException e) { 148 // 异常处理逻辑 149 if (e.getErrorCode().equals("SYSTEM_ERROR")) { 150 // 错误:系统错误 151 // 解决方式:稍后重试 152 // 描述:微信支付系统失败,系统失败直接立即重试大概率还会是系统失败,建议等1分钟后再重试 153 } else if (e.getErrorCode().equals("FREQUENCY_LIMITED")) { 154 // 错误:限频报错 155 // 解决方式:稍后重试 156 // 描述: 接口频率限制,直接立即重试大概率还会是系统失败,建议等1分钟后再重试 157 } else if (e.getErrorCode().equals("NO_AUTH")) { 158 // 错误:无分账权限 159 // 解决方式:检查商户是否是被处罚:登录商户平台进入账户中心-违约记录查询是否违约记录,如果有按照上面的指引解决违约记录之后重试 160 // 描述:平台商户被处罚或者平台商户和二级商户没有父子受理关系 161 } else if (e.getErrorCode().equals("SIGN_ERROR")) { 162 // 错误:签名错误 163 // 解决方式:检查平台商户证书序列号,证书私钥文件,公钥ID,公钥文件,同时确认下签名过程是不是按照微信支付的签名方式 164 // 描述:签名报错,需要确认签名材料和签名流程是否正确 165 } else if (e.getErrorCode().equals("PARAM_ERROR")) { 166 // 错误:参数错误 167 // 解决方式:按照报错返回的message,重新输入请求参数 168 // 描述:参数的类型,长度,或者必填选项没有填写等,大概率是传的微信支付订单号是非法的 169 } else if (e.getErrorCode().equals("INVALID_REQUEST")) { 170 // 错误:请求非法,请求参数正确,但是不符合分账业务规则 171 // 解决方式:根据具体message查看具体哪里不符合业务规则,如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试 172 } else { 173 // 其他类型错误:稍等一会后原单重试 174 } 175 throw e; 176 } 177 } 178} 179
