Explorar el Código

:new:【微信支付】增加品牌红包商家转账到零钱发放、查询批次、查询明细等接口

墨染 hace 2 años
padre
commit
87322e6d78
Se han modificado 13 ficheros con 1453 adiciones y 0 borrados
  1. 71 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandMerchantBatchesQueryRequest.java
  2. 52 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandMerchantDetailsQueryRequest.java
  3. 249 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandTransferBatchesRequest.java
  4. 72 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandWxBatchesQueryRequest.java
  5. 52 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandWxDetailsQueryRequest.java
  6. 354 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/result/BrandBatchesQueryResult.java
  7. 273 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/result/BrandDetailsQueryResult.java
  8. 62 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/result/BrandTransferBatchesResult.java
  9. 93 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BrandMerchantTransferService.java
  10. 7 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
  11. 3 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
  12. 87 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java
  13. 78 0
      weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImplTest.java

+ 71 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandMerchantBatchesQueryRequest.java

@@ -0,0 +1,71 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 品牌红包商家批次单号查询批次单API参数
+ *
+ * @author moran
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class BrandMerchantBatchesQueryRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包批次单号
+   * 变量名:out_batch_no
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  path商户系统内部的商家品牌红包批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
+   * 示例值:plfk2020042013
+   * </pre>
+   */
+  @SerializedName("out_batch_no")
+  private String outBatchNo;
+
+  /**
+   * <pre>
+   * 字段名:是否需要查询品牌红包明细单
+   * 变量名:need_query_detail
+   * 是否必填:否
+   * 类型:boolean
+   * 描述:
+   *  query枚举值:
+   * true:是;
+   * false:否,默认否。
+   * 商户可选择是否查询指定状态的品牌红包明细单,当品牌红包批次单状态为“FINISHED”(已完成)时,才会返回满足条件的品牌红包明细单
+   * </pre>
+   */
+  @SerializedName("need_query_detail")
+  private Boolean needQueryDetail;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包明细单状态
+   * 变量名:detail_state
+   * 是否必填:否
+   * 类型:string
+   * 描述:
+   *  query查询指定状态的品牌红包明细单信息
+   * DETAIL_VIEW_ALL - 全部,需要同时查询发送成功和发送失败的品牌红包明细单
+   * DETAIL_VIEW_SUCCESS - 发送成功,只查询发送成功的品牌红包明细单
+   * DETAIL_VIEW_FAIL - 发送失败,只查询发送失败的品牌红包明细单
+   * 示例值:DETAIL_VIEW_FAIL
+   * </pre>
+   */
+  @SerializedName("detail_state")
+  private String detailState;
+}

+ 52 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandMerchantDetailsQueryRequest.java

@@ -0,0 +1,52 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 品牌红包商家明细单号查询明细单API参数
+ *
+ * @author moran
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class BrandMerchantDetailsQueryRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包批次单号
+   * 变量名:out_batch_no
+   * 是否必填:是
+   * 类型:string[5, 32]
+   * 描述:
+   *  path商户系统内部的商家品牌红包批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
+   * 示例值:plfk2020042013
+   * </pre>
+   */
+  @SerializedName("out_batch_no")
+  private String outBatchNo;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包明细单号
+   * 变量名:out_detail_no
+   * 是否必填:是
+   * 类型:string[5, 32]
+   * 描述:
+   *  path商户系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识,要求此参数只能由数字、大小写字母组成
+   * 示例值:x23zy545Bd5436
+   * </pre>
+   */
+  @SerializedName("out_detail_no")
+  private String outDetailNo;
+}

+ 249 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandTransferBatchesRequest.java

@@ -0,0 +1,249 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.request;
+
+import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 发起品牌红包商家转账API参数
+ *
+ * @author moran
+ **/
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class BrandTransferBatchesRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:品牌ID
+   * 变量名:brand_id
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  body品牌在微信支付进行品牌认证后的唯一标识品牌ID
+   * 示例值:1234
+   * </pre>
+   */
+  @SerializedName("brand_id")
+  private Integer brandId;
+
+  /**
+   * <pre>
+   * 字段名:品牌AppID
+   * 变量名:brand_appid
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  body品牌商户在微信申请公众号/小程序或移动应用成功后分配的账号ID,需与品牌有绑定关系,使用品牌的AppID时需要填写
+   * 示例值:wxf636efh567hg4356
+   * </pre>
+   */
+  @SerializedName("brand_appid")
+  private String brandAppid;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包发放场景
+   * 变量名:scene
+   * 是否必填:是
+   * 类型:string
+   * 描述:
+   *  body品牌红包发放场景,用户可以在指定的场景领取到红包
+   * CUSTOM_SEND - 自定义发放场景,自定义场景发放红包,使用已配置的自定义发放模板进行发红包
+   * 示例值:CUSTOM_SEND
+   * </pre>
+   */
+  @SerializedName("scene")
+  private String scene;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包模板ID
+   * 变量名:template_id
+   * 是否必填:是
+   * 类型:string[1, 128]
+   * 描述:
+   *  body品牌主配置的品牌红包模板ID
+   * 示例值:123400001
+   * </pre>
+   */
+  @SerializedName("template_id")
+  private String templateId;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包批次单号
+   * 变量名:out_batch_no
+   * 是否必填:是
+   * 类型:string[5, 32]
+   * 描述:
+   *  body品牌商户系统内部的品牌红包批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
+   * 示例值:plfk2020042013
+   * </pre>
+   */
+  @SerializedName("out_batch_no")
+  private String outBatchNo;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次名称
+   * 变量名:batch_name
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  body该品牌红包批次的名称,展示在用户红包领取通知的红包活动名称
+   * 示例值:双十一营销用品牌红包
+   * </pre>
+   */
+  @SerializedName("batch_name")
+  private String batchName;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次备注
+   * 变量名:batch_remark
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  body该批次品牌红包的备注,仅用于品牌商户内部管理
+   * 示例值:双十一营销用品牌红包
+   * </pre>
+   */
+  @SerializedName("batch_remark")
+  private String batchRemark;
+
+  /**
+   * <pre>
+   * 字段名:总金额
+   * 变量名:total_amount
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  body品牌红包总金额必须与品牌红包批次内所有品牌红包明细发送金额之和保持一致,否则无法发送品牌红包
+   * 示例值:10000
+   * </pre>
+   */
+  @SerializedName("total_amount")
+  private Integer totalAmount;
+
+  /**
+   * <pre>
+   * 字段名:总笔数
+   * 变量名:total_num
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  body一个品牌红包批次单最多发送10笔品牌红包明细。品牌红包总笔数必须与批次内所有品牌红包明细之和保持一致,否则无法发送品牌红包
+   * 示例值:10
+   * </pre>
+   */
+  @SerializedName("total_num")
+  private Integer totalNum;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包明细列表
+   * 变量名:detail_list
+   * 是否必填:否
+   * 类型:array
+   * 描述:
+   *  body品牌红包明细列表,最多10笔
+   * </pre>
+   */
+  @SpecEncrypt
+  @SerializedName("detail_list")
+  private List<BrandTransferDetail> detailList;
+
+  @Data
+  @Builder(builderMethodName = "newBuilder")
+  @AllArgsConstructor
+  @NoArgsConstructor
+  public static class BrandTransferDetail {
+
+    /**
+     * <pre>
+     * 字段名:商家品牌红包明细单号
+     * 变量名:out_detail_no
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  品牌商户系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识,要求此参数只能由数字、大小写字母组成
+     * 示例值:x23zy545Bd5436
+     * </pre>
+     */
+    @SerializedName("out_detail_no")
+    private String outDetailNo;
+
+    /**
+     * <pre>
+     * 字段名:红包金额(单位:分)
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  红包金额单位为“分”,红包金额的最大限额取决于商户在商户平台的设置额度
+     * 示例值:100
+     * </pre>
+     */
+    @SerializedName("amount")
+    private Integer amount;
+
+    /**
+     * <pre>
+     * 字段名:接收红包用户OpenID
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1, 64]
+     * 描述:
+     *  接收红包的用户OpenID,该OpenID为用户在上方指定的AppID下的唯一标识。
+     *  注:openid是微信用户在公众号appid下的唯一用户标识(appid不同,则获取到的openid就不同),可用于永久标记一个用户。
+     *  获取openid:https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml
+     * 示例值:o-MYE42l80oelYMDE34nYD456Xoy
+     * </pre>
+     */
+    @SerializedName("openid")
+    private String openid;
+
+    /**
+     * <pre>
+     * 字段名:接收红包用户姓名
+     * 变量名:user_name
+     * 是否必填:否
+     * 类型:string[1, 1024]
+     * 描述:
+     *  1、明细转账金额 >= 2,000,收款用户姓名必填;
+     *  2、同一批次转账明细中,收款用户姓名字段需全部填写、或全部不填写;
+     *  3、若传入收款用户姓名,微信支付会校验用户OpenID与姓名是否一致,并提供电子回单;
+     *  4、收款方姓名。采用标准RSA算法,公钥由微信侧提供
+     *  5、该字段需进行加密处理,加密方法详见敏感信息加密说明。(提醒:必须在HTTP头中上送Wechatpay-Serial)
+     * 示例值:757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45
+     * </pre>
+     */
+    @SpecEncrypt
+    @SerializedName("user_name")
+    private String userName;
+
+    /**
+     * <pre>
+     * 字段名:红包备注
+     * 变量名:remark
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  单个红包备注,会展示在客户端收款凭证的“红包说明”字段,UTF8编码,最多允许32个字符
+     * 示例值:来自XX的红包
+     * </pre>
+     */
+    @SerializedName("remark")
+    private String remark;
+  }
+}

+ 72 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandWxBatchesQueryRequest.java

@@ -0,0 +1,72 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 品牌红包微信支付批次单号查询批次单API参数
+ *
+ * @author moran
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class BrandWxBatchesQueryRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:微信支付品牌红包批次单号
+   * 变量名:batch_no
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  path微信支付品牌红包批次单号,微信商家品牌红包系统返回的唯一标识
+   * 示例值:1030000071100999991182020050700019480001
+   * </pre>
+   */
+  @SerializedName("batch_no")
+  private String batchNo;
+
+  /**
+   * <pre>
+   * 字段名:是否需要查询品牌红包明细单
+   * 变量名:need_query_detail
+   * 是否必填:是
+   * 类型:boolean
+   * 描述:
+   *  query枚举值:
+   *  true:是;
+   *  false:否,默认否。
+   * 商户可选择是否查询指定状态的品牌红包明细单,当品牌红包批次单状态为“FINISHED”(已完成)时,才会返回满足条件的品牌红包明细单
+   * 示例值:true
+   * </pre>
+   */
+  @SerializedName("need_query_detail")
+  private Boolean needQueryDetail;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包明细单状态
+   * 变量名:detail_status
+   * 是否必填:否
+   * 类型:string[1,32]
+   * 描述:
+   *  query查询指定状态的品牌红包明细单信息
+   * DETAIL_VIEW_ALL - 全部,需要同时查询发送成功和发送失败的品牌红包明细单
+   * DETAIL_VIEW_SUCCESS - 发送成功,只查询发送成功的品牌红包明细单
+   * DETAIL_VIEW_FAIL - 发送失败,只查询发送失败的品牌红包明细单
+   * 示例值:DETAIL_VIEW_FAIL
+   * </pre>
+   */
+  @SerializedName("detail_state")
+  private String detailState;
+}

+ 52 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/request/BrandWxDetailsQueryRequest.java

@@ -0,0 +1,52 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 品牌红包微信支付明细单号查询明细单API参数
+ *
+ * @author moran
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class BrandWxDetailsQueryRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:微信支付品牌红包批次单号
+   * 变量名:batch_no
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  path微信支付品牌红包批次单号,微信商家品牌红包系统返回的唯一标识
+   * 示例值:1030000071100999991182020050700019480001
+   * </pre>
+   */
+  @SerializedName("batch_no")
+  private String batchNo;
+
+  /**
+   * <pre>
+   * 字段名:微信明细单号
+   * 变量名:detail_no
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  path微信支付系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识
+   * 示例值:1040000071100999991182020050700019500100
+   * </pre>
+   */
+  @SerializedName("detail_no")
+  private String detailNo;
+}

+ 354 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/result/BrandBatchesQueryResult.java

@@ -0,0 +1,354 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.result;
+
+import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 查询批次单结果
+ *
+ * @author moran
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class BrandBatchesQueryResult implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:品牌主商户号
+   * 变量名:brand_mchid
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  微信服务商下特约商户的商户号,且已经认证品牌的品牌主商户号
+   * 示例值:1900001109
+   * </pre>
+   */
+  @SerializedName("brand_mchid")
+  private String brandMchid;
+
+  /**
+   * <pre>
+   * 字段名:微信支付品牌红包批次单号
+   * 变量名:batch_no
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  品牌在微信支付进行品牌认证后的唯一标识品牌ID
+   * 示例值:1030000071100999991182020050700019480001
+   * </pre>
+   */
+  @SerializedName("batch_no")
+  private String batchNo;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包批次单号
+   * 变量名:out_batch_no
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  品牌商户系统内部的品牌红包批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
+   * 示例值:plfk2020042013
+   * </pre>
+   */
+  @SerializedName("out_batch_no")
+  private String outBatchNo;
+
+  /**
+   * <pre>
+   * 字段名:品牌ID
+   * 变量名:brand_id
+   * 是否必填:否
+   * 类型:int
+   * 描述:
+   *  品牌在微信支付进行品牌认证后的唯一标识品牌ID
+   * 示例值:1234
+   * </pre>
+   */
+  @SerializedName("brand_id")
+  private Integer brandId;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包模板ID
+   * 变量名:template_id
+   * 是否必填:否
+   * 类型:string[1, 128]
+   * 描述:
+   *  品牌主配置的品牌红包模板ID
+   * 示例值:12340000000001
+   * </pre>
+   */
+  @SerializedName("template_id")
+  private String templateId;
+
+  /**
+   * <pre>
+   * 字段名:品牌AppID
+   * 变量名:brand_appid
+   * 是否必填:否
+   * 类型:string[1, 32]
+   * 描述:
+   *  品牌商户在微信申请公众号/小程序或移动应用成功后分配的账号ID,该AppID需与品牌ID有绑定关系(B-A绑定关系)
+   * 示例值:wxf636efh567hg4356
+   * </pre>
+   */
+  @SerializedName("brand_appid")
+  private String brandAppid;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次状态
+   * 变量名:batch_state
+   * 是否必填:是
+   * 类型:string
+   * 描述:
+   *  当前品牌红包批次状态
+   * WAIT_PAY - 待付款,商户员工确认付款阶段
+   * ACCEPTED - 已受理,批次已受理成功,若发起品牌红包的30分钟后,品牌红包批次单仍处于该状态,可能原因是商户账户余额不足等。商户可查询账户资金流水,若该笔品牌红包批次单的扣款已经发生,则表示批次已经进入发送中,请再次查单确认
+   * PROCESSING - 发送中,已开始处理批次内的品牌红包明细单
+   * FINISHED - 已完成,批次内的所有品牌红包明细单都已处理完成
+   * CLOSED - 已关闭,可查询具体的批次关闭原因确认
+   * 示例值:ACCEPTED
+   * </pre>
+   */
+  @SerializedName("batch_state")
+  private String batchState;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次名称
+   * 变量名:batch_name
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  该批次品牌红包的备注,用于品牌商户内部管理
+   * 示例值:双十一营销发放品牌红包
+   * </pre>
+   */
+  @SerializedName("batch_name")
+  private String batchName;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次备注
+   * 变量名:batch_remark
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  该批次品牌红包的备注,仅用于品牌商户内部管理
+   * 示例值:双十一营销发放品牌红包
+   * </pre>
+   */
+  @SerializedName("batch_remark")
+  private String batchRemark;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次单关闭原因
+   * 变量名:close_reason
+   * 是否必填:否
+   * 类型:string
+   * 描述:
+   *  品牌红包批次单状态为“CLOSED”(已关闭)时返回
+   * MERCHANT_REVOCATION - 商户主动撤销
+   * SYSTEM_OVERDUE_CLOSE - 系统超时关闭
+   * 示例值:SYSTEM_OVERDUE_CLOSE
+   * </pre>
+   */
+  @SerializedName("close_reason")
+  private String closeReason;
+
+  /**
+   * <pre>
+   * 字段名:总金额
+   * 变量名:total_amount
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  品牌红包金额单位为“分”
+   * 示例值:10000
+   * </pre>
+   */
+  @SerializedName("total_amount")
+  private Integer totalAmount;
+
+  /**
+   * <pre>
+   * 字段名:总笔数
+   * 变量名:total_num
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  一个品牌红包批次单最多发送10笔品牌红包明细。品牌红包总笔数必须与批次内所有品牌红包明细之和保持一致,否则无法发送品牌红包
+   * 示例值:10
+   * </pre>
+   */
+  @SerializedName("total_num")
+  private Integer totalNum;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次创建时间
+   * 变量名:create_time
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  品牌红包批次受理成功时返回,遵循rfc3339标准格式,
+   *  格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   *  例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒
+   * 示例值:2015-05-20T13:29:35+08:00
+   * </pre>
+   */
+  @SerializedName("create_time")
+  private String createTime;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次更新时间
+   * 变量名:update_time
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  品牌红包批次最近一次状态变更时间,遵循rfc3339标准格式,
+   *  格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   *  例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒
+   * 示例值:2015-05-20T13:29:35+08:00
+   * </pre>
+   */
+  @SerializedName("update_time")
+  private String updateTime;
+
+  /**
+   * <pre>
+   * 字段名:发放成功金额
+   * 变量名:success_amount
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  品牌红包发放成功的金额,单位为“分”。当批次状态为“PROCESSING”(发送中)时,发放成功金额随时可能变化
+   * 示例值:5000
+   * </pre>
+   */
+  @SerializedName("success_amount")
+  private Integer successAmount;
+
+  /**
+   * <pre>
+   * 字段名:发放成功笔数
+   * 变量名:success_num
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  品牌红包发放成功的笔数。当批次状态为“PROCESSING”(发放中)时,发放成功笔数随时可能变化
+   * 示例值:10
+   * </pre>
+   */
+  @SerializedName("success_num")
+  private Integer successNum;
+
+  /**
+   * <pre>
+   * 字段名:发放失败金额
+   * 变量名:fail_amount
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  品牌红包发放失败的金额,单位为“分”
+   * 示例值:5000
+   * </pre>
+   */
+  @SerializedName("fail_amount")
+  private Integer failAmount;
+
+  /**
+   * <pre>
+   * 字段名:发放失败笔数
+   * 变量名:fail_num
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  品牌红包发放失败的笔数
+   * 示例值:10
+   * </pre>
+   */
+  @SerializedName("fail_num")
+  private Integer failNum;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包明细列表
+   * 变量名:detail_list
+   * 是否必填:否
+   * 类型:array
+   * 描述:
+   *  当批次状态为“FINISHED”(已完成),且成功查询到品牌红包明细单时返回。包括微信支付品牌红包明细单号、明细状态信息
+   * </pre>
+   */
+  @SpecEncrypt
+  @SerializedName("detail_list")
+  private List<BrandDetailResult> detailList;
+
+  @Data
+  @Accessors(chain = true)
+  public static class BrandDetailResult implements Serializable {
+
+    /**
+     * <pre>
+     * 字段名:微信支付品牌红包明细单号
+     * 变量名:transfer_detail_no
+     * 是否必填:是
+     * 类型:string[32, 64]
+     * 描述:
+     *  微信支付系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识
+     * 示例值:1220000071100999991182020050700019500100
+     * </pre>
+     */
+    @SerializedName("transfer_detail_no")
+    private String transferDetailNo;
+
+    /**
+     * <pre>
+     * 字段名:商家品牌红包明细单号
+     * 变量名:out_detail_no
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  品牌商户系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识,要求此参数只能由数字、大小写字母组成
+     * 示例值:x23zy545Bd5436
+     * </pre>
+     */
+    @SerializedName("out_detail_no")
+    private String outDetailNo;
+
+    /**
+     * <pre>
+     * 字段名:品牌红包明细单状态
+     * 变量名:detail_state
+     * 是否必填:是
+     * 类型:string[1, 64]
+     * 描述:
+     *  品牌红包明细单的状态
+     * DETAIL_PROCESSING - 发送中,正在处理中,品牌红包发送结果尚未明确
+     * DETAIL_SUCCESS - 发送成功,发送成功
+     * DETAIL_FAIL - 发送失败,需要确认失败原因后,再决定是否重新对该笔品牌红包明细单进行发送(并非整个品牌红包批次单)
+     * 示例值:DETAIL_SUCCESS
+     * </pre>
+     */
+    @SerializedName("detail_state")
+    private String detailState;
+
+  }
+}

+ 273 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/result/BrandDetailsQueryResult.java

@@ -0,0 +1,273 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 品牌红包微信明细单号查询明细单 响应实体、
+ *
+ * @author moran
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class BrandDetailsQueryResult implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:品牌主商户号
+   * 变量名:brand_mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  微信服务商下特约商户的商户号,且已经认证品牌的品牌主商户号
+   * 示例值:1900001109
+   * </pre>
+   */
+  @SerializedName("brand_mchid")
+  private String brandMchid;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包批次单号
+   * 变量名:out_batch_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  商户系统内部的商家品牌红包批次单号,在商户系统内部唯一
+   * 示例值:plfk2020042013
+   * </pre>
+   */
+  @SerializedName("out_batch_no")
+  private String outBatchNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付品牌红包批次单号
+   * 变量名:batch_no
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  微信支付品牌红包批次单号,微信商家品牌红包系统返回的唯一标识
+   * 示例值:1030000071100999991182020050700019480001
+   * </pre>
+   */
+  @SerializedName("batch_no")
+  private String batchNo;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包明细单号
+   * 变量名:out_detail_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  品牌商户系统内部的品牌红包批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
+   * 示例值:x23zy545Bd5436
+   * </pre>
+   */
+  @SerializedName("out_detail_no")
+  private String outDetailNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付品牌红包明细单号
+   * 变量名:detail_id
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  微信支付系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识
+   * 示例值:1040000071100999991182020050700019500100
+   * </pre>
+   */
+  @SerializedName("detail_no")
+  private String detailNo;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包明细单状态
+   * 变量名:detail_state
+   * 是否必填:是
+   * 类型:string
+   * 描述:
+   *  品牌红包明细单状态
+   * DETAIL_PROCESSING - 发送中,正在处理中,品牌红包发送结果尚未明确
+   * DETAIL_SUCCESS - 发送成功,发送成功
+   * DETAIL_FAIL - 发送失败,需要确认失败原因后,再决定是否重新对该笔品牌红包明细单进行发送(并非整个品牌红包批次单)
+   * 示例值:DETAIL_SUCCESS
+   * </pre>
+   */
+  @SerializedName("detail_state")
+  private String detailState;
+
+  /**
+   * <pre>
+   * 字段名:红包金额
+   * 变量名:amount
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  红包金额单位为“分”
+   * 示例值:100
+   * </pre>
+   */
+  @SerializedName("amount")
+  private Integer amount;
+
+  /**
+   * <pre>
+   * 字段名:红包备注
+   * 变量名:remark
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  单个品牌红包备注(微信用户会收到该备注),UTF8编码,最多允许32个字符
+   * 示例值:来自XX品牌红包
+   * </pre>
+   */
+  @SerializedName("remark")
+  private String remark;
+
+  /**
+   * <pre>
+   * 字段名:明细失败原因
+   * 变量名:fail_reason
+   * 是否必填:否
+   * 类型:string
+   * 描述:
+   *  明细失败原因
+   * ACCOUNT_FROZEN - 该用户账户被冻结
+   * REAL_NAME_CHECK_FAIL - 收款人未实名认证,需要用户完成微信实名认证
+   * NAME_NOT_CORRECT - 收款人姓名校验不通过,请核实信息
+   * OPENID_INVALID - OpenID格式错误或者不属于商家公众账号
+   * TRANSFER_QUOTA_EXCEED - 超过用户单笔收款区间,核实产品设置是否准确
+   * DAY_RECEIVED_QUOTA_EXCEED - 超过用户单日收款额度,核实产品设置是否准确
+   * DAY_RECEIVED_COUNT_EXCEED - 超过用户单日收款次数,核实产品设置是否准确
+   * PRODUCT_AUTH_CHECK_FAIL - 未开通该权限或权限被冻结,请核实产品权限状态
+   * OVERDUE_CLOSE - 该笔转账已关闭
+   * ACCOUNT_NOT_EXIST - 该用户账户不存在
+   * TRANSFER_RISK - 该笔转账可能存在风险,已被微信拦截
+   * USER_ACCOUNT_LIMIT - 用户账户收款受限,请引导用户在微信支付查看详情
+   * FAIL_REASON_UNKNOWN - 失败原因未知
+   * PAYER_ACCOUNT_ABNORMAL - 商户账户付款受限,可前往商户平台获取解除功能限制指引
+   * PAYEE_ACCOUNT_ABNORMAL - 用户账户收款异常,请联系用户完善其在微信支付的身份信息以继续收款
+   * USER_RECEIVE_OVERDUE - 用户逾期未领取
+   * REMARK_NOT_CORRECT - 红包备注设置失败,请修改后再试
+   * 示例值:ACCOUNT_FROZEN
+   * </pre>
+   */
+  @SerializedName("fail_reason")
+  private String failReason;
+
+  /**
+   * <pre>
+   * 字段名:接收红包用户OpenID
+   * 变量名:openid
+   * 是否必填:是
+   * 类型:string[1, 64]
+   * 描述:
+   *  接收红包的用户OpenID,OpenID为用户在对应AppID下的唯一标识
+   * 示例值:o-MYE42l80oelYMDE34nYD456Xoy
+   * </pre>
+   */
+  @SerializedName("openid")
+  private String openid;
+
+  /**
+   * <pre>
+   * 字段名:接收红包用户姓名
+   * 变量名:user_name
+   * 是否必填:否
+   * 类型:string[1,1024]
+   * 描述:
+   *  发放品牌红包时传入的接收红包用户姓名,已使用商户的私钥加密
+   * 示例值:757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45
+   * </pre>
+   */
+  @SerializedName("user_name")
+  private String userName;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包发起时间
+   * 变量名:initiate_time
+   * 是否必填:否
+   * 类型:string[1,32]
+   * 描述:
+   *  品牌红包发起的时间,遵循rfc3339标准格式,
+   *  格式为yyyy-MM-DDTHH:mm:ss.sss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   *  例如:2015-05-20T13:29:35.120+08:00表示北京时间2015年05月20日13点29分35秒
+   * 示例值:2015-05-20T13:29:35.120+08:00
+   * </pre>
+   */
+  @SerializedName("initiate_time")
+  private String initiateTime;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包更新时间
+   * 变量名:update_time
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  品牌红包明细单最后一次状态变更时间,遵循rfc3339标准格式,
+   *  格式为yyyy-MM-DDTHH:mm:ss.sss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.sss表示时分秒毫秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   *  例如:2015-05-20T13:29:35.120+08:00表示北京时间2015年05月20日13点29分35秒
+   * 示例值:2015-05-20T13:29:35.120+08:00
+   * </pre>
+   */
+  @SerializedName("update_time")
+  private String updateTime;
+
+  /**
+   * <pre>
+   * 字段名:品牌ID
+   * 变量名:brand_id
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  品牌在微信支付进行品牌认证后的唯一标识品牌ID
+   * 示例值:1234
+   * </pre>
+   */
+  @SerializedName("brand_id")
+  private Integer brandId;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包模板ID
+   * 变量名:template_id
+   * 是否必填:是
+   * 类型:string[1, 128]
+   * 描述:
+   *  品牌主配置的品牌红包模板ID
+   * 示例值:12340000000001
+   * </pre>
+   */
+  @SerializedName("template_id")
+  private String templateId;
+
+  /**
+   * <pre>
+   * 字段名:品牌AppID
+   * 变量名:brand_appid
+   * 是否必填:否
+   * 类型:string[1, 32]
+   * 描述:
+   *  品牌商户在微信申请公众号/小程序或移动应用成功后分配的账号ID,该AppID需与品牌ID有绑定关系(B-A绑定关系)
+   * 示例值:wxf636efh567hg4356
+   * </pre>
+   */
+  @SerializedName("brand_appid")
+  private String brandAppid;
+
+}

+ 62 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/brandmerchanttransfer/result/BrandTransferBatchesResult.java

@@ -0,0 +1,62 @@
+package com.github.binarywang.wxpay.bean.brandmerchanttransfer.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 品牌红包商家转账结果
+ *
+ * @author moran
+ **/
+@Data
+@NoArgsConstructor
+public class BrandTransferBatchesResult implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * <pre>
+   * 字段名:商家品牌红包批次单号
+   * 变量名:out_batch_no
+   * 是否必填:是
+   * 类型:string[5, 32]
+   * 描述:
+   *  品牌商户系统内部区分品牌红包批次单下不同品牌红包明细单的唯一标识,要求此参数只能由数字、大小写字母组成
+   * 示例值:plfk2020042013
+   * </pre>
+   */
+  @SerializedName("out_batch_no")
+  private String outBatchNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付品牌红包批次单号
+   * 变量名:batch_no
+   * 是否必填:是
+   * 类型:string[32, 64]
+   * 描述:
+   *  微信批次单号,微信商家转账系统返回的唯一标识
+   * 示例值:1210000071100999991182020050700019480001
+   * </pre>
+   */
+  @SerializedName("batch_no")
+  private String batchNo;
+
+  /**
+   * <pre>
+   * 字段名:品牌红包批次创建时间
+   * 变量名:create_time
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  批次受理成功时返回,遵循rfc3339标准格式,
+   *  格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
+   *  例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒
+   * 示例值:2015-05-20T13:29:35+08:00
+   * </pre>
+   */
+  @SerializedName("create_time")
+  private String createTime;
+}

+ 93 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BrandMerchantTransferService.java

@@ -0,0 +1,93 @@
+package com.github.binarywang.wxpay.service;
+
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.request.*;
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.result.BrandBatchesQueryResult;
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.result.BrandDetailsQueryResult;
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.result.BrandTransferBatchesResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
+
+/**
+ * 品牌商户发放红包商家转账到零钱(直联商户)
+ *
+ * @author moran
+ */
+public interface BrandMerchantTransferService {
+
+  /**
+   * 品牌商户发放红包API
+   * <p>
+   * 适用对象:直连商户
+   * 文档详见:
+   * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/brand-redpacket/brand-merchant-batches
+   * 请求方式:POST
+   * 接口限频: 单个商户 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
+   * 是否需要证书:是
+   *
+   * @param request the request
+   * @return transfer create result
+   * @throws WxPayException the wx pay exception
+   */
+  BrandTransferBatchesResult createBrandTransfer(BrandTransferBatchesRequest request) throws WxPayException;
+
+  /**
+   * 品牌红包微信批次单号查询批次单API
+   * <p>
+   * 适用对象:直连商户
+   * 文档详见:
+   * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/brand-redpacket/brand-merchant-batches/{batch_no}
+   * 请求方式:GET
+   * 接口限频: 单个商户 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
+   *
+   * @param request the request
+   * @return batches query result
+   * @throws WxPayException the wx pay exception
+   */
+  BrandBatchesQueryResult queryBrandWxBatches(BrandWxBatchesQueryRequest request) throws WxPayException;
+
+  /**
+   * 品牌红包微信支付明细单号查询明细单API
+   * <p>
+   * 适用对象:直连商户
+   * 文档详见:
+   * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/brand-redpacket/brand-merchant-batches/{batch_no}/details/{detail_no}
+   * 请求方式:GET
+   * 接口限频: 单个商户 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
+   *
+   * @param request the request
+   * @return details query result
+   * @throws WxPayException the wx pay exception
+   */
+  BrandDetailsQueryResult queryBrandWxDetails(BrandWxDetailsQueryRequest request) throws WxPayException;
+
+  /**
+   * 品牌红包商家批次单号查询批次单API
+   * <p>
+   * 适用对象:直连商户
+   * 文档详见:
+   * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no}
+   * 请求方式:GET
+   * 接口限频: 单个商户 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
+   *
+   * @param request the request
+   * @return batches query result
+   * @throws WxPayException the wx pay exception
+   */
+  BrandBatchesQueryResult queryBrandMerchantBatches(BrandMerchantBatchesQueryRequest request) throws WxPayException;
+
+  /**
+   * 品牌红包商家明细单号查询明细单API
+   * <p>
+   * 适用对象:直连商户
+   * 文档详见:
+   * 请求URL:https://api.mch.weixin.qq.com/v3/fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no}/out-details/{out_detail_no}
+   * 请求方式:GET
+   * 接口限频: 单个商户 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
+   *
+   * @param request the request
+   * @return details query result
+   * @throws WxPayException the wx pay exception
+   */
+  BrandDetailsQueryResult queryBrandMerchantDetails(BrandMerchantDetailsQueryRequest request) throws WxPayException;
+
+
+}

+ 7 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java

@@ -312,6 +312,13 @@ public interface WxPayService {
   MerchantTransferService getMerchantTransferService();
 
   /**
+   * 获取品牌红包商家转账到零钱服务类
+   *
+   * @return the brand merchant transfer service
+   */
+  BrandMerchantTransferService getBrandMerchantTransferService();
+
+  /**
    * 设置企业付款服务类,允许开发者自定义实现类.
    *
    * @param entPayService the ent pay service

+ 3 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java

@@ -124,6 +124,9 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   @Getter
   private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this);
 
+  @Getter
+  private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this);
+
   protected Map<String, WxPayConfig> configMap;
 
   @Override

+ 87 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java

@@ -0,0 +1,87 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.request.*;
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.result.BrandBatchesQueryResult;
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.result.BrandDetailsQueryResult;
+import com.github.binarywang.wxpay.bean.brandmerchanttransfer.result.BrandTransferBatchesResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.BrandMerchantTransferService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 品牌商户发放红包商家转账到零钱(直联商户)实现
+ *
+ * @author moran
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class BrandMerchantTransferServiceImpl implements BrandMerchantTransferService {
+  private static final Gson GSON = (new GsonBuilder()).create();
+
+  private final WxPayService wxPayService;
+
+
+  @Override
+  public BrandTransferBatchesResult createBrandTransfer(BrandTransferBatchesRequest request) throws WxPayException {
+
+    String url = String.format("%s/v3/fund-app/brand-redpacket/brand-merchant-batches", this.wxPayService.getPayBaseUrl());
+    RsaCryptoUtil.encryptFields(request, this.wxPayService.getConfig().getVerifier().getValidCertificate());
+
+    String response = wxPayService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+    return GSON.fromJson(response, BrandTransferBatchesResult.class);
+  }
+
+  @Override
+  public BrandBatchesQueryResult queryBrandWxBatches(BrandWxBatchesQueryRequest request) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/brand-redpacket/brand-merchant-batches/%s",
+      this.wxPayService.getPayBaseUrl(), request.getBatchNo());
+
+    if (request.getNeedQueryDetail() != null) {
+      url = String.format("%s?need_query_detail=%b", url, request.getNeedQueryDetail());
+    }
+    if (request.getDetailState() != null && request.getDetailState().length() != 0) {
+      url = String.format("%s&detail_state=%s", url, request.getDetailState());
+    }
+
+    String response = wxPayService.getV3(url);
+    return GSON.fromJson(response, BrandBatchesQueryResult.class);
+  }
+
+  @Override
+  public BrandDetailsQueryResult queryBrandWxDetails(BrandWxDetailsQueryRequest request) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/brand-redpacket/brand-merchant-batches/%s/details/%s",
+      this.wxPayService.getPayBaseUrl(), request.getBatchNo(), request.getDetailNo());
+    String response = wxPayService.getV3(url);
+    return GSON.fromJson(response, BrandDetailsQueryResult.class);
+  }
+
+  @Override
+  public BrandBatchesQueryResult queryBrandMerchantBatches(BrandMerchantBatchesQueryRequest request) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/brand-redpacket/brand-merchant-out-batches/%s",
+      this.wxPayService.getPayBaseUrl(), request.getOutBatchNo());
+
+    if (request.getNeedQueryDetail() != null) {
+      url = String.format("%s?need_query_detail=%b", url, request.getNeedQueryDetail());
+    }
+    if (request.getDetailState() != null && request.getDetailState().length() != 0) {
+      url = String.format("%s&detail_state=%s", url, request.getDetailState());
+    }
+
+    String response = wxPayService.getV3(url);
+    return GSON.fromJson(response, BrandBatchesQueryResult.class);
+  }
+
+  @Override
+  public BrandDetailsQueryResult queryBrandMerchantDetails(BrandMerchantDetailsQueryRequest request) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/brand-redpacket/brand-merchant-out-batches/%s/out-details/%s",
+      this.wxPayService.getPayBaseUrl(), request.getOutBatchNo(), request.getOutDetailNo());
+    String response = wxPayService.getV3(url);
+    return GSON.fromJson(response, BrandDetailsQueryResult.class);
+  }
+
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 78 - 0
weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImplTest.java