瀏覽代碼

:new: #2188 【微信支付】增加v3合单支付和账单相关接口

thinsstar 3 年之前
父節點
當前提交
fb0460e1a1
共有 15 個文件被更改,包括 2370 次插入113 次删除
  1. 576 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/CombineNotifyResult.java
  2. 2 1
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyV3Result.java
  3. 91 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java
  4. 429 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineTransactionsRequest.java
  5. 66 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayApplyFundFlowBillV3Request.java
  6. 66 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayApplyTradeBillV3Request.java
  7. 558 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/CombineQueryResult.java
  8. 120 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/CombineTransactionsResult.java
  9. 59 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayApplyBillV3Result.java
  10. 89 40
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryV3Result.java
  11. 93 44
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundV3Result.java
  12. 9 4
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/TradeTypeEnum.java
  13. 0 24
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BasePayV3Service.java
  14. 127 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
  15. 85 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java

+ 576 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/CombineNotifyResult.java

@@ -0,0 +1,576 @@
+package com.github.binarywang.wxpay.bean.notify;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * <pre>
+ * 微信支付通过支付通知接口将用户支付成功消息通知给商户
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_13.shtml
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class CombineNotifyResult implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * 源数据
+   */
+  private OriginNotifyResponse rawData;
+  /**
+   * 解密后的数据
+   */
+  private DecryptNotifyResult result;
+
+  @Data
+  @NoArgsConstructor
+  public static class DecryptNotifyResult implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:合单商户appid
+     * 变量名:combine_appid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  合单发起方的appid。
+     *  示例值:wxd678efh567hg6787
+     * </pre>
+     */
+    @SerializedName(value = "combine_appid")
+    private String combineAppid;
+    /**
+     * <pre>
+     * 字段名:合单商户号
+     * 变量名:combine_mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  合单发起方商户号。
+     *  示例值:1900000109
+     * </pre>
+     */
+    @SerializedName(value = "combine_mchid")
+    private String combineMchid;
+    /**
+     * <pre>
+     * 字段名:合单商户订单号
+     * 变量名:combine_out_trade_no
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+     *  示例值:P20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "combine_out_trade_no")
+    private String combineOutTradeNo;
+    /**
+     * <pre>
+     * 字段名:场景信息
+     * 变量名:scene_info
+     * 是否必填:否
+     * 类型:object
+     * 描述:
+     *  支付场景信息描述
+     * </pre>
+     */
+    @SerializedName(value = "scene_info")
+    private SceneInfo sceneInfo;
+
+    /**
+     * <pre>
+     * 字段名:子单信息
+     * 变量名:sub_orders
+     * 是否必填:是
+     * 类型:array
+     * 描述:
+     *  最多支持子单条数:10
+     * </pre>
+     */
+    @SerializedName(value = "sub_orders")
+    private List<SubOrders> subOrders;
+
+    /**
+     * <pre>
+     * 字段名:支付者
+     * 变量名:combine_payer_info
+     * 是否必填:否
+     * 类型:object
+     * 描述:
+     *  示例值:见请求示例
+     * </pre>
+     */
+    @SerializedName(value = "combine_payer_info")
+    private CombinePayerInfo combinePayerInfo;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class SceneInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:商户端设备号
+     * 变量名:device_id
+     * 是否必填:否
+     * 类型:string[7,16]
+     * 描述:
+     *  终端设备号(门店号或收银设备ID)。
+     *  特殊规则:长度最小7个字节
+     *  示例值:POS1:1
+     * </pre>
+     */
+    @SerializedName(value = "device_id")
+    private String deviceId;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class SubOrders implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:子单商户号
+     * 变量名:mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  子单发起方商户号,必须与发起方Appid有绑定关系。
+     *  示例值:1900000109
+     * </pre>
+     */
+    @SerializedName(value = "mchid")
+    private String mchid;
+    /**
+     * <pre>
+     * 字段名:交易类型
+     * 变量名:trade_type
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  枚举值:
+     *  NATIVE:扫码支付
+     *  JSAPI:公众号支付
+     *  APP:APP支付
+     *  MWEB:H5支付
+     *  示例值: JSAPI
+     * </pre>
+     */
+    @SerializedName(value = "trade_type")
+    private String tradeType;
+    /**
+     * <pre>
+     * 字段名:交易状态
+     * 变量名:trade_state
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  枚举值:
+     *  SUCCESS:支付成功
+     *  REFUND:转入退款
+     *  NOTPAY:未支付
+     *  CLOSED:已关闭
+     *  USERPAYING:用户支付中
+     *  PAYERROR:支付失败(其他原因,如银行返回失败)
+     *  示例值: SUCCESS
+     * </pre>
+     */
+    @SerializedName(value = "trade_state")
+    private String tradeState;
+    /**
+     * <pre>
+     * 字段名:付款银行
+     * 变量名:bank_type
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  银行类型,采用字符串类型的银行标识。银行标识请参考《银行类型对照表》https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6
+     *  示例值:CMC
+     * </pre>
+     */
+    @SerializedName(value = "bank_type")
+    private String bankType;
+    /**
+     * <pre>
+     * 字段名:附加信息
+     * 变量名:attach
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
+     *  示例值:深圳分店
+     * </pre>
+     */
+    @SerializedName(value = "attach")
+    private String attach;
+    /**
+     * <pre>
+     * 字段名:支付完成时间
+     * 变量名:success_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年5月20日 13点29分35秒。
+     *  示例值:2015-05-20T13:29:35.120+08:00
+     * </pre>
+     */
+    @SerializedName(value = "success_time")
+    private String successTime;
+    /**
+     * <pre>
+     * 字段名:微信订单号
+     * 变量名:transaction_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付订单号。
+     *  示例值: 1009660380201506130728806387
+     * </pre>
+     */
+    @SerializedName(value = "transaction_id")
+    private String transactionId;
+    /**
+     * <pre>
+     * 字段名:子单商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:string[6,32]
+     * 描述:
+     *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+     *  特殊规则:最小字符长度为6
+     *  示例值:20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "out_trade_no")
+    private String outTradeNo;
+    /**
+     * <pre>
+     * 字段名:订单金额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:object
+     * 描述:
+     *  订单金额信息
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Amount amount;
+    /**
+     * <pre>
+     * 字段名:优惠功能
+     * 变量名:promotion_detail
+     * 是否必填:是
+     * 类型:array
+     * 描述:
+     *  优惠功能,子单有核销优惠券时有返回
+     * </pre>
+     */
+    @SerializedName(value = "promotion_detail")
+    private List<PromotionDetail> promotionDetail;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class CombinePayerInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:用户标识
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  使用合单appid获取的对应用户openid。是用户在商户appid下的唯一标识。
+     *  示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * </pre>
+     */
+    @SerializedName(value = "openid")
+    private String openid;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class Amount implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:标价金额
+     * 变量名:total_amount
+     * 是否必填:是
+     * 类型:int64
+     * 描述:
+     *  子单金额,单位为分。
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "total_amount")
+    private Integer totalAmount;
+    /**
+     * <pre>
+     * 字段名:标价币种
+     * 变量名:currency
+     * 是否必填:是
+     * 类型:string[1,8]
+     * 描述:
+     *  符合ISO 4217标准的三位字母代码,人民币:CNY。
+     *  示例值:CNY
+     * </pre>
+     */
+    @SerializedName(value = "currency")
+    private String currency;
+    /**
+     * <pre>
+     * 字段名:现金支付金额
+     * 变量名:payer_amount
+     * 是否必填:是
+     * 类型:int64
+     * 描述:
+     *  订单现金支付金额。
+     *  示例值:10
+     * </pre>
+     */
+    @SerializedName(value = "payer_amount")
+    private Integer payerAmount;
+    /**
+     * <pre>
+     * 字段名:现金支付币种
+     * 变量名:payer_currency
+     * 是否必填:是
+     * 类型:string[1,8]
+     * 描述:
+     *  货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY。
+     *  示例值: CNY
+     * </pre>
+     */
+    @SerializedName(value = "payer_currency")
+    private String payerCurrency;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class PromotionDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:券ID
+     * 变量名:coupon_id
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  券ID
+     *  示例值:109519
+     * </pre>
+     */
+    @SerializedName(value = "coupon_id")
+    private String couponId;
+    /**
+     * <pre>
+     * 字段名:优惠名称
+     * 变量名:name
+     * 是否必填:否
+     * 类型:string[1, 64]
+     * 描述:
+     *  优惠名称
+     *  示例值:单品惠-6
+     * </pre>
+     */
+    @SerializedName(value = "name")
+    private String name;
+    /**
+     * <pre>
+     * 字段名:优惠范围
+     * 变量名:scope
+     * 是否必填:否
+     * 类型:string[1, 32]
+     * 描述:
+     *  GLOBAL:全场代金券
+     *  SINGLE:单品优惠
+     *  示例值:GLOBALSINGLE
+     * </pre>
+     */
+    @SerializedName(value = "scope")
+    private String scope;
+    /**
+     * <pre>
+     * 字段名:优惠类型
+     * 变量名:type
+     * 是否必填:否
+     * 类型:string[1,8]
+     * 描述:
+     *  CASH:充值;
+     *  NOCASH:预充值。
+     *  示例值:CASH
+     * </pre>
+     */
+    @SerializedName(value = "type")
+    private String type;
+    /**
+     * <pre>
+     * 字段名:优惠券面额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  当前子单中享受的优惠券金额
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Integer amount;
+    /**
+     * <pre>
+     * 字段名:活动ID
+     * 变量名:stock_id
+     * 是否必填:否
+     * 类型:string[1, 32]
+     * 描述:
+     *  活动ID,批次ID
+     *  示例值:931386
+     * </pre>
+     */
+    @SerializedName(value = "stock_id")
+    private String stockId;
+    /**
+     * <pre>
+     * 字段名:微信出资
+     * 变量名:wechatpay_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  单位为分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "wechatpay_contribute")
+    private Integer wechatpayContribute;
+    /**
+     * <pre>
+     * 字段名:商户出资
+     * 变量名:merchant_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  单位为分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "merchant_contribute")
+    private Integer merchantContribute;
+    /**
+     * <pre>
+     * 字段名:其他出资
+     * 变量名:other_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  单位为分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "other_contribute")
+    private Integer otherContribute;
+    /**
+     * <pre>
+     * 字段名:优惠币种
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * </pre>
+     */
+    @SerializedName(value = "currency")
+    private String currency;
+    /**
+     * <pre>
+     * 字段名:单品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  单品列表信息
+     * </pre>
+     */
+    @SerializedName(value = "goods_detail")
+    private List<GoodsDetail> goodsDetail;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class GoodsDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:商品编码
+     * 变量名:goods_id
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  商品编码
+     *  示例值:M1006
+     * </pre>
+     */
+    @SerializedName(value = "goods_id")
+    private String goodsId;
+    /**
+     * <pre>
+     * 字段名:商品数量
+     * 变量名:quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品数量
+     *  示例值:1
+     * </pre>
+     */
+    @SerializedName(value = "quantity")
+    private Integer quantity;
+    /**
+     * <pre>
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品价格
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "unit_price")
+    private Integer unitPrice;
+    /**
+     * <pre>
+     * 字段名:商品优惠金额
+     * 变量名:discount_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品优惠金额
+     *  示例值:1
+     * </pre>
+     */
+    @SerializedName(value = "discount_amount")
+    private Integer discountAmount;
+    /**
+     * <pre>
+     * 字段名:商品备注
+     * 变量名:goods_remark
+     * 是否必填:否
+     * 类型:string[1, 128]
+     * 描述:
+     *  商品备注
+     *  示例值:商品备注信息
+     * </pre>
+     */
+    @SerializedName(value = "goods_remark")
+    private String goodsRemark;
+  }
+}

+ 2 - 1
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyV3Result.java

@@ -105,7 +105,7 @@ public class WxPayRefundNotifyV3Result implements Serializable {
      *  SUCCESS:退款成功
      *  CLOSE:退款关闭
      *  ABNORMAL:退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款
-     * 示例值:SUCCESS
+     *  示例值:SUCCESS
      * </pre>
      */
     @SerializedName(value = "refund_status")
@@ -158,6 +158,7 @@ public class WxPayRefundNotifyV3Result implements Serializable {
   @Data
   @NoArgsConstructor
   public static class Amount implements Serializable {
+    private static final long serialVersionUID = 1L;
     /**
      * <pre>
      * 字段名:订单金额

+ 91 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java

@@ -0,0 +1,91 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * <pre>
+ * 合单支付订单只能使用此合单关单api完成关单。
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_12.shtml
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class CombineCloseRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * <pre>
+   * 字段名:合单商户appid
+   * 变量名:combine_appid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单发起方的appid。
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "combine_appid")
+  private String combineAppid;
+  /**
+   * <pre>
+   * 字段名:合单商户订单号
+   * 变量名:combine_out_trade_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+   *  示例值:P20150806125346
+   * </pre>
+   */
+  private transient String combineOutTradeNo;
+  /**
+   * <pre>
+   * 字段名:子单信息
+   * 变量名:sub_orders
+   * 是否必填:是
+   * 类型:array
+   * 描述:
+   *  最多支持子单条数:10
+   * </pre>
+   */
+  @SerializedName(value = "sub_orders")
+  private List<SubOrders> subOrders;
+
+  @Data
+  @NoArgsConstructor
+  public static class SubOrders implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:子单商户号
+     * 变量名:mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  子单发起方商户号,必须与发起方appid有绑定关系。
+     *  示例值:1900000109
+     * </pre>
+     */
+    @SerializedName(value = "mchid")
+    private String mchid;
+    /**
+     * <pre>
+     * 字段名:子单商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:string[6,32]
+     * 描述:
+     *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+     *  示例值:20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "out_trade_no")
+    private String outTradeNo;
+  }
+}

+ 429 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineTransactionsRequest.java

@@ -0,0 +1,429 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * <pre>
+ * 使用合单支付接口,用户只输入一次密码,即可完成多个订单的支付。目前最多一次可支持50笔订单进行合单支付。
+ * 参考文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_2.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_3.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_4.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_5.shtml
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class CombineTransactionsRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * <pre>
+   * 字段名:合单商户appid
+   * 变量名:combine_appid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单发起方的appid。
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "combine_appid")
+  private String combineAppid;
+  /**
+   * <pre>
+   * 字段名:合单商户号
+   * 变量名:combine_mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单发起方商户号。
+   *  示例值:1900000109
+   * </pre>
+   */
+  @SerializedName(value = "combine_mchid")
+  private String combineMchid;
+  /**
+   * <pre>
+   * 字段名:合单商户订单号
+   * 变量名:combine_out_trade_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 。
+   *  示例值:P20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "combine_out_trade_no")
+  private String combineOutTradeNo;
+  /**
+   * <pre>
+   * 字段名:场景信息
+   * 变量名:scene_info
+   * 是否必填:否
+   * 类型:object
+   * 描述:
+   *  支付场景信息描述
+   * </pre>
+   */
+  @SerializedName(value = "scene_info")
+  private SceneInfo sceneInfo;
+  /**
+   * <pre>
+   * 字段名:子单信息
+   * 变量名:sub_orders
+   * 是否必填:是
+   * 类型:array
+   * 描述:
+   *  最多支持子单条数:10
+   * </pre>
+   */
+  @SerializedName(value = "sub_orders")
+  private List<SubOrders> subOrders;
+  /**
+   * <pre>
+   * 字段名:支付者
+   * 变量名:combine_payer_info
+   * 是否必填:否(JSAPI必填)
+   * 类型:object
+   * 描述:
+   *  支付者信息
+   * </pre>
+   */
+  @SerializedName(value = "combine_payer_info")
+  private CombinePayerInfo combinePayerInfo;
+  /**
+   * <pre>
+   * 字段名:交易起始时间
+   * 变量名:time_start
+   * 是否必填:否
+   * 类型: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年5月20日 13点29分35秒。
+   *  示例值:2019-12-31T15:59:59+08:00
+   * </pre>
+   */
+  @SerializedName(value = "time_start")
+  private String timeStart;
+  /**
+   * <pre>
+   * 字段名:交易结束时间
+   * 变量名:time_expire
+   * 是否必填:否
+   * 类型: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年5月20日 13点29分35秒。
+   *  示例值:2019-12-31T15:59:59+08:00
+   * </pre>
+   */
+  @SerializedName(value = "time_expire")
+  private String timeExpire;
+  /**
+   * <pre>
+   * 字段名:通知地址
+   * 变量名:notify_url
+   * 是否必填:是
+   * 类型:string[1,256]
+   * 描述:
+   *  接收微信支付异步通知回调地址,通知url必须为直接可访问的URL,不能携带参数。
+   *  格式: URL
+   *  示例值:https://yourapp.com/notify
+   * </pre>
+   */
+  @SerializedName(value = "notify_url")
+  private String notifyUrl;
+
+  @Data
+  @NoArgsConstructor
+  public static class SceneInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:商户端设备号
+     * 变量名:device_id
+     * 是否必填:否
+     * 类型:string[7,16]
+     * 描述:
+     *  终端设备号(门店号或收银设备ID)。
+     *  示例值:POS1:123
+     * </pre>
+     */
+    @SerializedName(value = "device_id")
+    private String deviceId;
+    /**
+     * <pre>
+     * 字段名:用户终端IP
+     * 变量名:payer_client_ip
+     * 是否必填:是
+     * 类型:string[1,45]
+     * 描述:
+     *  用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。
+     *  格式: ip(ipv4+ipv6)
+     *  示例值:14.17.22.32
+     * </pre>
+     */
+    @SerializedName(value = "payer_client_ip")
+    private String payerClientIp;
+    /**
+     * <pre>
+     * 字段名:H5场景信息
+     * 变量名:h5_info
+     * 是否必填:否(H5支付必填)
+     * 类型:object
+     * 描述:
+     *  H5场景信息
+     * </pre>
+     */
+    @SerializedName(value = "h5_info")
+    private H5Info h5Info;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class SubOrders implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:子单商户号
+     * 变量名:mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  子单发起方商户号,必须与发起方appid有绑定关系。
+     *  示例值:1900000109
+     * </pre>
+     */
+    @SerializedName(value = "mchid")
+    private String mchid;
+    /**
+     * <pre>
+     * 字段名:附加信息
+     * 变量名:attach
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
+     *  示例值:深圳分店
+     * </pre>
+     */
+    @SerializedName(value = "attach")
+    private String attach;
+    /**
+     * <pre>
+     * 字段名:订单金额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:object
+     * 描述:
+     *  订单金额信息
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Amount amount;
+    /**
+     * <pre>
+     * 字段名:子单商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+     *  特殊规则:最小字符长度为6
+     *  示例值:20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "out_trade_no")
+    private String outTradeNo;
+    /**
+     * <pre>
+     * 字段名:商品描述
+     * 变量名:description
+     * 是否必填:是
+     * 类型:string[1,127]
+     * 描述:
+     *  商品简单描述。需传入应用市场上的APP名字-实际商品名称,例如:天天爱消除-游戏充值。
+     *  示例值:腾讯充值中心-QQ会员充值
+     * </pre>
+     */
+    @SerializedName(value = "description")
+    private String description;
+    /**
+     * <pre>
+     * 字段名:结算信息
+     * 变量名:settle_info
+     * 是否必填:否
+     * 类型:Object
+     * 描述:结算信息
+     * </pre>
+     */
+    @SerializedName(value = "settle_info")
+    private SettleInfo settleInfo;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class CombinePayerInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:用户标识
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  使用合单appid获取的对应用户openid。是用户在商户appid下的唯一标识。
+     *  示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * </pre>
+     */
+    @SerializedName(value = "openid")
+    private String openid;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class Amount implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:标价金额
+     * 变量名:total_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  子单金额,单位为分
+     *  境外场景下,标价金额要超过商户结算币种的最小单位金额,例如结算币种为美元,则标价金额必须大于1美分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "total_amount")
+    private Integer totalAmount;
+    /**
+     * <pre>
+     * 字段名:标价币种
+     * 变量名:currency
+     * 是否必填:是
+     * 类型:string[1,8]
+     * 描述:
+     *  符合ISO 4217标准的三位字母代码,人民币:CNY 。
+     *  示例值:CNY
+     * </pre>
+     */
+    @SerializedName(value = "currency")
+    private String currency;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class SettleInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:是否指定分账
+     * 变量名:profit_sharing
+     * 是否必填:否
+     * 类型:bool
+     * 描述:
+     *  是否指定分账,枚举值
+     *  true:是
+     *  false:否
+     *  示例值:true
+     * </pre>
+     */
+    @SerializedName(value = "profit_sharing")
+    private Boolean profitSharing;
+    /**
+     * <pre>
+     * 字段名:补差金额
+     * 变量名:subsidy_amount
+     * 是否必填:否
+     * 类型:int64
+     * 描述:
+     *  SettleInfo.profit_sharing为true时,该金额才生效。
+     *  注意:单笔订单最高补差金额为5000元
+     *  示例值:10
+     * </pre>
+     */
+    @SerializedName(value = "subsidy_amount")
+    private Integer subsidyAmount;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class H5Info implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:场景类型
+     * 变量名:type
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  场景类型,枚举值:
+     *  iOS:IOS移动应用;
+     *  Android:安卓移动应用;
+     *  Wap:WAP网站应用;
+     *  示例值:iOS
+     * </pre>
+     */
+    @SerializedName(value = "type")
+    private String type;
+    /**
+     * <pre>
+     * 字段名:应用名称
+     * 变量名:app_name
+     * 是否必填:否
+     * 类型:string[1,64]
+     * 描述:
+     *  应用名称
+     *  示例值:王者荣耀
+     * </pre>
+     */
+    @SerializedName(value = "app_name")
+    private String appName;
+    /**
+     * <pre>
+     * 字段名:网站URL
+     * 变量名:app_url
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  网站URL
+     *  示例值:https://pay.qq.com
+     * </pre>
+     */
+    @SerializedName(value = "app_url")
+    private String appUrl;
+    /**
+     * <pre>
+     * 字段名:iOS平台BundleID
+     * 变量名:bundle_id
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  iOS平台BundleID
+     *  示例值:com.tencent.wzryiOS
+     * </pre>
+     */
+    @SerializedName(value = "bundle_id")
+    private String bundleId;
+    /**
+     * <pre>
+     * 字段名:Android平台PackageName
+     * 变量名:package_name
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  Android平台PackageName
+     *  示例值:com.tencent.tmgp.sgame
+     * </pre>
+     */
+    @SerializedName(value = "package_name")
+    private String packageName;
+  }
+}

+ 66 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayApplyFundFlowBillV3Request.java

@@ -0,0 +1,66 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ * 微信支付-申请账单入参
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class WxPayApplyFundFlowBillV3Request implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * <pre>
+   * 字段名:账单日期
+   * 变量名:bill_date
+   * 是否必填:是
+   * 类型:string[1,10]
+   * 描述:
+   *  格式YYYY-MM-DD
+   *  仅支持三个月内的账单下载申请。
+   *  示例值:2019-06-11
+   * </pre>
+   */
+  @SerializedName(value = "bill_date")
+  private String billDate;
+  /**
+   * <pre>
+   * 字段名:资金账户类型
+   * 变量名:account_type
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  不填则默认是BASIC
+   *  枚举值:
+   *  BASIC:基本账户
+   *  OPERATION:运营账户
+   *  FEES:手续费账户
+   *  示例值:BASIC
+   * </pre>
+   */
+  @SerializedName(value = "account_type")
+  private String accountType;
+  /**
+   * <pre>
+   * 字段名:压缩类型
+   * 变量名:tar_type
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  不填则默认是数据流
+   *  枚举值:
+   *  GZIP:返回格式为.gzip的压缩包账单
+   *  示例值:GZIP
+   * </pre>
+   */
+  @SerializedName(value = "tar_type")
+  private String tarType;
+}

+ 66 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayApplyTradeBillV3Request.java

@@ -0,0 +1,66 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ * 微信支付-申请账单入参
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class WxPayApplyTradeBillV3Request implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * <pre>
+   * 字段名:账单日期
+   * 变量名:bill_date
+   * 是否必填:是
+   * 类型:string[1,10]
+   * 描述:
+   *  格式YYYY-MM-DD
+   *  仅支持三个月内的账单下载申请。
+   *  示例值:2019-06-11
+   * </pre>
+   */
+  @SerializedName(value = "bill_date")
+  private String billDate;
+  /**
+   * <pre>
+   * 字段名:账单类型
+   * 变量名:bill_type
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  不填则默认是ALL
+   *  枚举值:
+   *  ALL:返回当日所有订单信息(不含充值退款订单)
+   *  SUCCESS:返回当日成功支付的订单(不含充值退款订单)
+   *  REFUND:返回当日退款订单(不含充值退款订单)
+   *  示例值:ALL
+   * </pre>
+   */
+  @SerializedName(value = "bill_type")
+  private String billType;
+  /**
+   * <pre>
+   * 字段名:压缩类型
+   * 变量名:tar_type
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  不填则默认是数据流
+   *  枚举值:
+   *  GZIP:返回格式为.gzip的压缩包账单
+   *  示例值:GZIP
+   * </pre>
+   */
+  @SerializedName(value = "tar_type")
+  private String tarType;
+}

+ 558 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/CombineQueryResult.java

@@ -0,0 +1,558 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * <pre>
+ * 商户通过合单查询订单API查询订单状态,完成下一步的业务逻辑。
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_11.shtml
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class CombineQueryResult implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * <pre>
+   * 字段名:合单商户appid
+   * 变量名:combine_appid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单发起方的appid。
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "combine_appid")
+  private String combineAppid;
+  /**
+   * <pre>
+   * 字段名:合单商户号
+   * 变量名:combine_mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单发起方商户号。
+   *  示例值:1900000109
+   * </pre>
+   */
+  @SerializedName(value = "combine_mchid")
+  private String combineMchid;
+  /**
+   * <pre>
+   * 字段名:合单商户订单号
+   * 变量名:combine_out_trade_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+   *  示例值:P20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "combine_out_trade_no")
+  private String combineOutTradeNo;
+  /**
+   * <pre>
+   * 字段名:场景信息
+   * 变量名:scene_info
+   * 是否必填:否
+   * 类型:object
+   * 描述:支付场景信息描述
+   * </pre>
+   */
+  @SerializedName(value = "scene_info")
+  private SceneInfo sceneInfo;
+  /**
+   * <pre>
+   * 字段名:子单信息
+   * 变量名:sub_orders
+   * 是否必填:是
+   * 类型:array
+   * 描述:
+   *  最多支持子单条数:10
+   * </pre>
+   */
+  @SerializedName(value = "sub_orders")
+  private List<SubOrders> subOrders;
+  /**
+   * <pre>
+   * 字段名:支付者
+   * 变量名:combine_payer_info
+   * 是否必填:否
+   * 类型:object
+   * 描述:
+   *  示例值:见请求示例
+   * </pre>
+   */
+  @SerializedName(value = "combine_payer_info")
+  private CombinePayerInfo combinePayerInfo;
+
+  @Data
+  @NoArgsConstructor
+  public static class SceneInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:商户端设备号
+     * 变量名:device_id
+     * 是否必填:否
+     * 类型:string[7,16]
+     * 描述:
+     *  终端设备号(门店号或收银设备ID)。
+     *  示例值:POS1:1
+     * </pre>
+     */
+    @SerializedName(value = "device_id")
+    private String deviceId;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class SubOrders implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:子单商户号
+     * 变量名:mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  子单发起方商户号,必须与发起方Appid有绑定关系。
+     *  示例值:1900000109
+     * </pre>
+     */
+    @SerializedName(value = "mchid")
+    private String mchid;
+    /**
+     * <pre>
+     * 字段名:交易类型
+     * 变量名:trade_type
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  枚举值:
+     *  NATIVE:扫码支付
+     *  JSAPI:公众号支付
+     *  APP:APP支付
+     *  MWEB:H5支付
+     *  示例值: JSAPI
+     * </pre>
+     */
+    @SerializedName(value = "trade_type")
+    private String tradeType;
+    /**
+     * <pre>
+     * 字段名:交易状态
+     * 变量名:trade_state
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  枚举值:
+     *  SUCCESS:支付成功
+     *  REFUND:转入退款
+     *  NOTPAY:未支付
+     *  CLOSED:已关闭
+     *  USERPAYING:用户支付中
+     *  PAYERROR:支付失败(其他原因,如银行返回失败)
+     *  ACCEPT:已接收,等待扣款
+     *  示例值: SUCCESS
+     * </pre>
+     */
+    @SerializedName(value = "trade_state")
+    private String tradeState;
+    /**
+     * <pre>
+     * 字段名:付款银行
+     * 变量名:bank_type
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  银行类型,采用字符串类型的银行标识。
+     *  示例值:CMC
+     * </pre>
+     */
+    @SerializedName(value = "bank_type")
+    private String bankType;
+    /**
+     * <pre>
+     * 字段名:附加信息
+     * 变量名:attach
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
+     *  示例值:深圳分店
+     * </pre>
+     */
+    @SerializedName(value = "attach")
+    private String attach;
+    /**
+     * <pre>
+     * 字段名:支付完成时间
+     * 变量名:success_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+08:00表示,北京时间2015年5月20日13点29分35秒。
+     *  示例值: 2015-05-20T13:29:35.120+08:00
+     * </pre>
+     */
+    @SerializedName(value = "success_time")
+    private String successTime;
+    /**
+     * <pre>
+     * 字段名:微信订单号
+     * 变量名:transaction_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付订单号。
+     *  示例值:1009660380201506130728806387
+     * </pre>
+     */
+    @SerializedName(value = "transaction_id")
+    private String transactionId;
+    /**
+     * <pre>
+     * 字段名:子单商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:string[6,32]
+     * 描述:
+     *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+     *  示例值:20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "out_trade_no")
+    private String outTradeNo;
+    /**
+     * <pre>
+     * 字段名:订单金额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:object
+     * 描述:
+     *  订单金额信息
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Amount amount;
+    /**
+     * <pre>
+     * 字段名:优惠功能
+     * 变量名:promotion_detail
+     * 是否必填:是
+     * 类型:array
+     * 描述:
+     *  优惠功能,子单有核销优惠券时有返回
+     * </pre>
+     */
+    @SerializedName(value = "promotion_detail")
+    private List<PromotionDetail> promotionDetail;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class CombinePayerInfo implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:用户标识
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  使用合单appid获取的对应用户openid。是用户在商户appid下的唯一标识。
+     *  示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * </pre>
+     */
+    @SerializedName(value = "openid")
+    private String openid;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class Amount implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:标价金额
+     * 变量名:total_amount
+     * 是否必填:是
+     * 类型:int64
+     * 描述:
+     *  子单金额,单位为分。
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "total_amount")
+    private Integer totalAmount;
+    /**
+     * <pre>
+     * 字段名:标价币种
+     * 变量名:currency
+     * 是否必填:是
+     * 类型:string[1,8]
+     * 描述:
+     *  符合ISO 4217标准的三位字母代码,人民币:CNY。
+     *  示例值:CNY
+     * </pre>
+     */
+    @SerializedName(value = "currency")
+    private String currency;
+    /**
+     * <pre>
+     * 字段名:现金支付金额
+     * 变量名:payer_amount
+     * 是否必填:是
+     * 类型:int64
+     * 描述:
+     *  订单现金支付金额。
+     *  示例值:10
+     * </pre>
+     */
+    @SerializedName(value = "payer_amount")
+    private Integer payerAmount;
+    /**
+     * <pre>
+     * 字段名:现金支付币种
+     * 变量名:payer_currency
+     * 是否必填:是
+     * 类型:string[1,8]
+     * 描述:
+     *  货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY。
+     *  示例值: CNY
+     * </pre>
+     */
+    @SerializedName(value = "payer_currency")
+    private String payerCurrency;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class PromotionDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:券ID
+     * 变量名:coupon_id
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  券ID
+     *  示例值:109519
+     * </pre>
+     */
+    @SerializedName(value = "coupon_id")
+    private String couponId;
+    /**
+     * <pre>
+     * 字段名:优惠名称
+     * 变量名:name
+     * 是否必填:否
+     * 类型:string[1, 64]
+     * 描述:
+     *  优惠名称
+     *  示例值:单品惠-6
+     * </pre>
+     */
+    @SerializedName(value = "name")
+    private String name;
+    /**
+     * <pre>
+     * 字段名:优惠范围
+     * 变量名:scope
+     * 是否必填:否
+     * 类型:string[1, 32]
+     * 描述:
+     *  GLOBAL:全场代金券
+     *  SINGLE:单品优惠
+     *  示例值:GLOBALSINGLE
+     * </pre>
+     */
+    @SerializedName(value = "scope")
+    private String scope;
+    /**
+     * <pre>
+     * 字段名:优惠类型
+     * 变量名:type
+     * 是否必填:否
+     * 类型:string[1,8]
+     * 描述:
+     *  CASH:充值;
+     *  NOCASH:预充值。
+     *  示例值:CASH
+     * </pre>
+     */
+    @SerializedName(value = "type")
+    private String type;
+    /**
+     * <pre>
+     * 字段名:优惠券面额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  当前子单中享受的优惠券金额
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Integer amount;
+    /**
+     * <pre>
+     * 字段名:活动ID
+     * 变量名:stock_id
+     * 是否必填:否
+     * 类型:string[1, 32]
+     * 描述:
+     *  活动ID,批次ID
+     *  示例值:931386
+     * </pre>
+     */
+    @SerializedName(value = "stock_id")
+    private String stockId;
+    /**
+     * <pre>
+     * 字段名:微信出资
+     * 变量名:wechatpay_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  单位为分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "wechatpay_contribute")
+    private Integer wechatpayContribute;
+    /**
+     * <pre>
+     * 字段名:商户出资
+     * 变量名:merchant_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  单位为分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "merchant_contribute")
+    private Integer merchantContribute;
+    /**
+     * <pre>
+     * 字段名:其他出资
+     * 变量名:other_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  单位为分
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "other_contribute")
+    private Integer otherContribute;
+    /**
+     * <pre>
+     * 字段名:优惠币种
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * </pre>
+     */
+    @SerializedName(value = "currency")
+    private String currency;
+    /**
+     * <pre>
+     * 字段名:单品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  单品列表信息
+     * </pre>
+     */
+    @SerializedName(value = "goods_detail")
+    private List<GoodsDetail> goodsDetail;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class GoodsDetail implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:商品编码
+     * 变量名:goods_id
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  商品编码
+     *  示例值:M1006
+     * </pre>
+     */
+    @SerializedName(value = "goods_id")
+    private String goodsId;
+    /**
+     * <pre>
+     * 字段名:商品数量
+     * 变量名:quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品数量
+     *  示例值:1
+     * </pre>
+     */
+    @SerializedName(value = "quantity")
+    private Integer quantity;
+    /**
+     * <pre>
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品价格
+     *  示例值:100
+     * </pre>
+     */
+    @SerializedName(value = "unit_price")
+    private Integer unitPrice;
+    /**
+     * <pre>
+     * 字段名:商品优惠金额
+     * 变量名:discount_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品优惠金额
+     *  示例值:1
+     * </pre>
+     */
+    @SerializedName(value = "discount_amount")
+    private Integer discountAmount;
+    /**
+     * <pre>
+     * 字段名:商品备注
+     * 变量名:goods_remark
+     * 是否必填:否
+     * 类型:string[1, 128]
+     * 描述:
+     *  商品备注
+     *  示例值:商品备注信息
+     * </pre>
+     */
+    @SerializedName(value = "goods_remark")
+    private String goodsRemark;
+  }
+}

+ 120 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/CombineTransactionsResult.java

@@ -0,0 +1,120 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.v3.util.SignUtils;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.security.PrivateKey;
+
+/**
+ * <pre>
+ * 使用合单支付接口,用户只输入一次密码,即可完成多个订单的支付。目前最多一次可支持50笔订单进行合单支付。
+ * 参考文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_2.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_3.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_4.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_5.shtml
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class CombineTransactionsResult implements Serializable {
+  private static final long serialVersionUID = 1L;
+  /**
+   * <pre>
+   * 字段名:预支付交易会话标识(APP支付、JSAPI和小程序支付返回)
+   * 变量名:prepay_id
+   * 是否必填:是
+   * 类型:string[1,64]
+   * 描述:
+   *  数字和字母。微信生成的预支付会话标识,用于后续接口调用使用,该值有效期为2小时。
+   *  示例值:wx201410272009395522657a690389285100
+   * </pre>
+   */
+  @SerializedName("prepay_id")
+  private String prepayId;
+  /**
+   * <pre>
+   * 字段名:支付跳转链接(H5支付返回)
+   * 变量名:h5_url
+   * 是否必填:是
+   * 类型:string[1,512]
+   * 描述:
+   *  支付跳转链接,h5_url的有效期为5分钟
+   *  示例值:https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458241
+   * </pre>
+   */
+  @SerializedName("h5_url")
+  private String h5Url;
+  /**
+   * <pre>
+   * 字段名:二维码链接(NATIVE支付返回)
+   * 变量名:h5_url
+   * 是否必填:是
+   * 类型:string[1,512]
+   * 描述:
+   *  二维码链接
+   *  示例值:weixin://pay.weixin.qq.com/bizpayurl/up?pr=NwY5Mz9&groupid=00
+   * </pre>
+   */
+  @SerializedName("code_url")
+  private String codeUrl;
+
+  @Data
+  @Accessors(chain = true)
+  public static class JsapiResult implements Serializable {
+    private String appId;
+    private String timeStamp;
+    private String nonceStr;
+    private String packageValue;
+    private String signType;
+    private String paySign;
+
+    private String getSignStr() {
+      return String.format("%s\n%s\n%s\n%s\n", appId, timeStamp, nonceStr, packageValue);
+    }
+  }
+
+  @Data
+  @Accessors(chain = true)
+  public static class AppResult implements Serializable {
+    private String appid;
+    private String partnerid;
+    private String prepayid;
+    private String packageValue;
+    private String noncestr;
+    private String timestamp;
+  }
+
+  public <T> T getPayInfo(TradeTypeEnum tradeType, String appId, String mchId, PrivateKey privateKey) {
+    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+    String nonceStr = SignUtils.genRandomStr();
+    switch (tradeType) {
+      case JSAPI:
+        JsapiResult jsapiResult = new JsapiResult();
+        jsapiResult.setAppId(appId).setTimeStamp(timestamp)
+          .setPackageValue("prepay_id=" + this.prepayId).setNonceStr(nonceStr)
+          //签名类型,默认为RSA,仅支持RSA。
+          .setSignType("RSA").setPaySign(SignUtils.sign(jsapiResult.getSignStr(), privateKey));
+        return (T) jsapiResult;
+      case H5:
+        return (T) this.h5Url;
+      case APP:
+        AppResult appResult = new AppResult();
+        appResult.setAppid(appId).setPrepayid(this.prepayId).setPartnerid(mchId)
+          .setNoncestr(nonceStr).setTimestamp(timestamp)
+          //暂填写固定值Sign=WXPay
+          .setPackageValue("Sign=WXPay");
+        return (T) appResult;
+      case NATIVE:
+        return (T) this.codeUrl;
+    }
+    return null;
+  }
+}

+ 59 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayApplyBillV3Result.java

@@ -0,0 +1,59 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ * 微信支付-申请账单返回结果.
+ * </pre>
+ *
+ * @author thinsstar
+ */
+@Data
+@NoArgsConstructor
+public class WxPayApplyBillV3Result implements Serializable {
+  private static final long serialVersionUID = -1L;
+  /**
+   * <pre>
+   * 字段名:哈希类型
+   * 变量名:hash_type
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  原始账单(gzip需要解压缩)的摘要值,用于校验文件的完整性。
+   *  示例值:SHA1
+   * </pre>
+   */
+  @SerializedName(value = "hash_type")
+  private String hashType;
+  /**
+   * <pre>
+   * 字段名:哈希值
+   * 变量名:hash_value
+   * 是否必填:是
+   * 类型:string[1,1024]
+   * 描述:
+   *  原始账单(gzip需要解压缩)的摘要值,用于校验文件的完整性。
+   *  示例值:79bb0f45fc4c42234a918000b2668d689e2bde04
+   * </pre>
+   */
+  @SerializedName(value = "out_refund_no")
+  private String outRefundNo;
+  /**
+   * <pre>
+   * 字段名:账单下载地址
+   * 变量名:download_url
+   * 是否必填:是
+   * 类型:string[1,2048]
+   * 描述:
+   *  供下一步请求账单文件的下载地址,该地址30s内有效。
+   *  示例值:https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx
+   * </pre>
+   */
+  @SerializedName(value = "download_url")
+  private String downloadUrl;
+}

+ 89 - 40
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryV3Result.java

@@ -17,7 +17,6 @@ import java.util.List;
 @Data
 @NoArgsConstructor
 public class WxPayRefundQueryV3Result implements Serializable {
-  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名:微信支付退款号
@@ -25,7 +24,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  微信支付退款号
+   *  微信支付退款号
    *  示例值:50000000382019052709732678859
    * </pre>
    */
@@ -51,7 +50,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  微信支付交易订单号
+   *  微信支付交易订单号
    *  示例值:1217752501201407033233368018
    * </pre>
    */
@@ -64,7 +63,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  原支付交易对应的商户订单号
+   *  原支付交易对应的商户订单号
    *  示例值:1217752501201407033233368018
    * </pre>
    */
@@ -96,10 +95,10 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 描述:
    *  取当前退款单的退款入账方,有以下几种情况:
    *  1)退回银行卡:{银行名称}{卡类型}{卡尾号}
-   *  2)退回支付用户零钱支付用户零钱
-   *  3)退还商户商户基本账户商户结算银行账户
-   *  4)退回支付用户零钱通:支付用户零钱通。
-   *  示例值:招商银行信用卡0403
+   *  2)退回支付用户零钱:支付用户零钱
+   *  3)退还商户:商户基本账户商户结算银行账户
+   *  4)退回支付用户零钱通:支付用户零钱通
+   * 示例值:招商银行信用卡0403
    * </pre>
    */
   @SerializedName(value = "user_received_account")
@@ -111,7 +110,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:否
    * 类型:string[1, 64]
    * 描述:
-   *  退款成功时间,当退款状态为退款成功时有返回。遵循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年5月20日13点29分35秒。
+   *  退款成功时间,当退款状态为退款成功时有返回。
    *  示例值:2020-12-01T16:18:12+08:00
    * </pre>
    */
@@ -124,7 +123,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 64]
    * 描述:
-   *  退款受理时间。 遵循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年5月20日13点29分35秒。
+   *  退款受理时间
    *  示例值:2020-12-01T16:18:12+08:00
    * </pre>
    */
@@ -137,7 +136,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
+   *  退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台(pay.weixin.qq.com)-交易中心,手动处理此笔退款。
    *  枚举值:
    *  SUCCESS:退款成功
    *  CLOSED:退款关闭
@@ -155,11 +154,13 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:否
    * 类型:string[1, 32]
    * 描述:
-   *  退款所使用资金对应的资金账户类型。 枚举值:
+   *  退款所使用资金对应的资金账户类型
+   *  枚举值:
    *  UNSETTLED : 未结算资金
    *  AVAILABLE : 可用余额
    *  UNAVAILABLE : 不可用余额
    *  OPERATION : 运营户
+   *  BASIC : 基本账户(含可用余额和不可用余额)
    *  示例值:UNSETTLED
    * </pre>
    */
@@ -172,7 +173,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:是
    * 类型:object
    * 描述:
-   *  金额详细信息
+   *  金额详细信息
    * </pre>
    */
   @SerializedName(value = "amount")
@@ -184,10 +185,11 @@ public class WxPayRefundQueryV3Result implements Serializable {
    * 是否必填:否
    * 类型:array
    * 描述:
-   *  优惠退款信息
+   *  优惠退款信息
    * </pre>
    */
-  public List<PromotionDetail> promotionDetails;
+  @SerializedName(value = "promotion_detail")
+  public List<PromotionDetail> promotionDetail;
 
   @Data
   @NoArgsConstructor
@@ -200,7 +202,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  订单总金额,单位为分
+     *  订单总金额,单位为分
      *  示例值:100
      * </pre>
      */
@@ -213,7 +215,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  退款标价金额,单位为分,可以做部分退款
+     *  退款标价金额,单位为分,可以做部分退款
      *  示例值:100
      * </pre>
      */
@@ -221,12 +223,24 @@ public class WxPayRefundQueryV3Result implements Serializable {
     private Integer refund;
     /**
      * <pre>
+     * 字段名:退款出资账户及金额
+     * 变量名:from
+     * 是否必填:是
+     * 类型:array
+     * 描述:
+     *  退款出资的账户类型及金额信息
+     * </pre>
+     */
+    @SerializedName(value = "from")
+    private List<From> from;
+    /**
+     * <pre>
      * 字段名:用户支付金额
      * 变量名:payer_total
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  现金支付金额,单位为分,只能为整数。
+     *  现金支付金额,单位为分,只能为整数
      *  示例值:90
      * </pre>
      */
@@ -239,7 +253,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  退款给用户的金额,不包含所有优惠券金额
+     *  退款给用户的金额,不包含所有优惠券金额
      *  示例值:90
      * </pre>
      */
@@ -252,7 +266,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
+     *  去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
      *  示例值:100
      * </pre>
      */
@@ -260,12 +274,12 @@ public class WxPayRefundQueryV3Result implements Serializable {
     private Integer settlementRefund;
     /**
      * <pre>
-     * 字段名:用户退款金额
+     * 字段名:应结订单金额
      * 变量名:settlement_total
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分
+     *  应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分
      *  示例值:100
      * </pre>
      */
@@ -276,9 +290,9 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 字段名:优惠退款金额
      * 变量名:discount_refund
      * 是否必填:否
-     * 类型:int64
+     * 类型:int
      * 描述:
-     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分
      *  示例值:10
      * </pre>
      */
@@ -286,7 +300,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
     private Integer discountRefund;
     /**
      * <pre>
-     * 字段名:币类型
+     * 字段名:退款币种
      * 变量名:currency
      * 是否必填:否
      * 类型:string[1, 16]
@@ -310,7 +324,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:string[1, 32]
      * 描述:
-     *  券或者立减优惠id
+     *  券或者立减优惠id
      *  示例值:109519
      * </pre>
      */
@@ -353,7 +367,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额 ),单位为分
+     *  用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额 ),单位为分
      *  示例值:5
      * </pre>
      */
@@ -366,7 +380,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为用户支付的现金,说明详见代金券或立减优惠,单位为分
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为用户支付的现金,说明详见代金券或立减优惠,单位为分
      *  示例值:100
      * </pre>
      */
@@ -379,25 +393,60 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:否
      * 类型:array
      * 描述:
-     *  优惠商品发生退款时返回商品信息
+     *  优惠商品发生退款时返回商品信息
      * </pre>
      */
     @SerializedName(value = "goods_detail")
-    private List<GoodsDetail> goodsDetails;
+    private List<GoodsDetail> goodsDetail;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class From implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:出资账户类型
+     * 变量名:account
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  下面枚举值多选一。
+     *  枚举值:
+     *  AVAILABLE : 可用余额
+     *  UNAVAILABLE : 不可用余额
+     *  示例值:AVAILABLE
+     * </pre>
+     */
+    @SerializedName(value = "account")
+    private String account;
+    /**
+     * <pre>
+     * 字段名:出资金额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  对应账户出资金额
+     *  示例值:444
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Integer amount;
   }
 
   @Data
   @NoArgsConstructor
   public static class GoodsDetail implements Serializable {
-    private static final long serialVersionUID = -1L;
+    private static final long serialVersionUID = 1L;
     /**
      * <pre>
      * 字段名:商户侧商品编码
      * 变量名:merchant_goods_id
      * 是否必填:是
-     * 类型:string[1,32]
+     * 类型:string[1, 32]
      * 描述:
-     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
+     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成
      *  示例值:1217752501201407033233368018
      * </pre>
      */
@@ -408,9 +457,9 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 字段名:微信侧商品编码
      * 变量名:wechatpay_goods_id
      * 是否必填:否
-     * 类型:string[1,32]
+     * 类型:string[1, 32]
      * 描述:
-     *  微信支付定义的统一商品编号(没有可不传)
+     *  微信支付定义的统一商品编号(没有可不传)
      *  示例值:1001
      * </pre>
      */
@@ -421,9 +470,9 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 字段名:商品名称
      * 变量名:goods_name
      * 是否必填:否
-     * 类型:string[1,256]
+     * 类型:string[1, 256]
      * 描述:
-     *  商品的实际名称
+     *  商品的实际名称
      *  示例值:iPhone6s 16G
      * </pre>
      */
@@ -436,7 +485,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  商品单价金额,单位为分
+     *  商品单价金额,单位为分
      *  示例值:528800
      * </pre>
      */
@@ -449,7 +498,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  商品退款金额,单位为分
+     *  商品退款金额,单位为分
      *  示例值:528800
      * </pre>
      */
@@ -462,7 +511,7 @@ public class WxPayRefundQueryV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  单品的退款数量
+     *  单品的退款数量,单位为分
      *  示例值:1
      * </pre>
      */

+ 93 - 44
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundV3Result.java

@@ -21,12 +21,12 @@ public class WxPayRefundV3Result implements Serializable {
   private static final long serialVersionUID = -1L;
   /**
    * <pre>
-   * 字段名:微信退款
+   * 字段名:微信支付退款号
    * 变量名:refund_id
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  微信支付退款号
+   *  微信支付退款号
    *  示例值:50000000382019052709732678859
    * </pre>
    */
@@ -52,7 +52,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  微信支付交易订单号
+   *  微信支付交易订单号
    *  示例值:1217752501201407033233368018
    * </pre>
    */
@@ -65,7 +65,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  原支付交易对应的商户订单号
+   *  原支付交易对应的商户订单号
    *  示例值:1217752501201407033233368018
    * </pre>
    */
@@ -76,13 +76,13 @@ public class WxPayRefundV3Result implements Serializable {
    * 字段名:退款渠道
    * 变量名:channel
    * 是否必填:是
-   * 类型:string[1, 32]
+   * 类型:string[1, 16]
    * 描述:
    *  枚举值:
-   *  ORIGINAL原路退款
-   *  BALANCE退回到余额
-   *  OTHER_BALANCE原账户异常退到其他余额账户
-   *  OTHER_BANKCARD原银行卡异常退到其他银行卡
+   *  ORIGINAL原路退款
+   *  BALANCE退回到余额
+   *  OTHER_BALANCE原账户异常退到其他余额账户
+   *  OTHER_BANKCARD原银行卡异常退到其他银行卡
    *  示例值:ORIGINAL
    * </pre>
    */
@@ -97,9 +97,9 @@ public class WxPayRefundV3Result implements Serializable {
    * 描述:
    *  取当前退款单的退款入账方,有以下几种情况:
    *  1)退回银行卡:{银行名称}{卡类型}{卡尾号}
-   *  2)退回支付用户零钱支付用户零钱
-   *  3)退还商户商户基本账户商户结算银行账户
-   *  4)退回支付用户零钱通:支付用户零钱通。
+   *  2)退回支付用户零钱:支付用户零钱
+   *  3)退还商户:商户基本账户商户结算银行账户
+   *  4)退回支付用户零钱通:支付用户零钱通
    *  示例值:招商银行信用卡0403
    * </pre>
    */
@@ -112,7 +112,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 64]
    * 描述:
-   *  退款成功时间,当退款状态为退款成功时有返回。遵循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年5月20日13点29分35秒。
+   *  退款成功时间,当退款状态为退款成功时有返回。
    *  示例值:2020-12-01T16:18:12+08:00
    * </pre>
    */
@@ -125,7 +125,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 64]
    * 描述:
-   *  退款受理时间。 遵循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年5月20日13点29分35秒。
+   *  退款受理时间
    *  示例值:2020-12-01T16:18:12+08:00
    * </pre>
    */
@@ -138,7 +138,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:是
    * 类型:string[1, 32]
    * 描述:
-   *  退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
+   *  退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台(pay.weixin.qq.com)-交易中心,手动处理此笔退款。
    *  枚举值:
    *  SUCCESS:退款成功
    *  CLOSED:退款关闭
@@ -153,14 +153,16 @@ public class WxPayRefundV3Result implements Serializable {
    * <pre>
    * 字段名:资金账户
    * 变量名:funds_account
-   * 是否必填:
+   * 是否必填:
    * 类型:string[1, 32]
    * 描述:
-   *  退款所使用资金对应的资金账户类型。 枚举值:
+   *  退款所使用资金对应的资金账户类型
+   *  枚举值:
    *  UNSETTLED : 未结算资金
    *  AVAILABLE : 可用余额
    *  UNAVAILABLE : 不可用余额
    *  OPERATION : 运营户
+   *  BASIC : 基本账户(含可用余额和不可用余额)
    *  示例值:UNSETTLED
    * </pre>
    */
@@ -173,7 +175,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:是
    * 类型:object
    * 描述:
-   *  金额详细信息
+   *  金额详细信息
    * </pre>
    */
   @SerializedName(value = "amount")
@@ -185,7 +187,7 @@ public class WxPayRefundV3Result implements Serializable {
    * 是否必填:否
    * 类型:array
    * 描述:
-   *  优惠退款信息
+   *  优惠退款信息
    * </pre>
    */
   @SerializedName(value = "promotion_detail")
@@ -202,7 +204,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  订单总金额,单位为分
+     *  订单总金额,单位为分
      *  示例值:100
      * </pre>
      */
@@ -215,7 +217,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  退款标价金额,单位为分,可以做部分退款
+     *  退款标价金额,单位为分,可以做部分退款
      *  示例值:100
      * </pre>
      */
@@ -223,12 +225,24 @@ public class WxPayRefundV3Result implements Serializable {
     private Integer refund;
     /**
      * <pre>
+     * 字段名:退款出资账户及金额
+     * 变量名:from
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  退款出资的账户类型及金额信息
+     * </pre>
+     */
+    @SerializedName(value = "from")
+    private List<From> from;
+    /**
+     * <pre>
      * 字段名:用户支付金额
      * 变量名:payer_total
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  现金支付金额,单位为分,只能为整数。
+     *  现金支付金额,单位为分,只能为整数
      *  示例值:90
      * </pre>
      */
@@ -241,7 +255,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  退款给用户的金额,不包含所有优惠券金额
+     *  退款给用户的金额,不包含所有优惠券金额
      *  示例值:90
      * </pre>
      */
@@ -254,7 +268,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
+     *  去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
      *  示例值:100
      * </pre>
      */
@@ -262,12 +276,12 @@ public class WxPayRefundV3Result implements Serializable {
     private Integer settlementRefund;
     /**
      * <pre>
-     * 字段名:用户退款金额
+     * 字段名:应结订单金额
      * 变量名:settlement_total
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分
+     *  应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分
      *  示例值:100
      * </pre>
      */
@@ -278,9 +292,9 @@ public class WxPayRefundV3Result implements Serializable {
      * 字段名:优惠退款金额
      * 变量名:discount_refund
      * 是否必填:否
-     * 类型:int64
+     * 类型:int
      * 描述:
-     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分
      *  示例值:10
      * </pre>
      */
@@ -290,7 +304,7 @@ public class WxPayRefundV3Result implements Serializable {
      * <pre>
      * 字段名:币类型
      * 变量名:currency
-     * 是否必填:
+     * 是否必填:
      * 类型:string[1, 16]
      * 描述:
      *  符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
@@ -312,7 +326,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:string[1, 32]
      * 描述:
-     *  券或者立减优惠id
+     *  券或者立减优惠id
      *  示例值:109519
      * </pre>
      */
@@ -355,7 +369,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额 ),单位为分
+     *  用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额 ),单位为分
      *  示例值:5
      * </pre>
      */
@@ -368,7 +382,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为用户支付的现金,说明详见代金券或立减优惠,单位为分
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为用户支付的现金,说明详见代金券或立减优惠,单位为分
      *  示例值:100
      * </pre>
      */
@@ -381,25 +395,60 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:否
      * 类型:array
      * 描述:
-     *  优惠商品发生退款时返回商品信息
+     *  优惠商品发生退款时返回商品信息
      * </pre>
      */
     @SerializedName(value = "goods_detail")
-    private List<GoodsDetail> goodsDetails;
+    private List<GoodsDetail> goodsDetail;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class From implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * <pre>
+     * 字段名:出资账户类型
+     * 变量名:account
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  下面枚举值多选一。
+     *  枚举值:
+     *  AVAILABLE : 可用余额
+     *  UNAVAILABLE : 不可用余额
+     *  示例值:AVAILABLE
+     * </pre>
+     */
+    @SerializedName(value = "account")
+    private String account;
+    /**
+     * <pre>
+     * 字段名:出资金额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  对应账户出资金额
+     *  示例值:444
+     * </pre>
+     */
+    @SerializedName(value = "amount")
+    private Integer amount;
   }
 
   @Data
   @NoArgsConstructor
   public static class GoodsDetail implements Serializable {
-    private static final long serialVersionUID = -1L;
+    private static final long serialVersionUID = 1L;
     /**
      * <pre>
      * 字段名:商户侧商品编码
      * 变量名:merchant_goods_id
      * 是否必填:是
-     * 类型:string[1,32]
+     * 类型:string[1, 32]
      * 描述:
-     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
+     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成
      *  示例值:1217752501201407033233368018
      * </pre>
      */
@@ -410,9 +459,9 @@ public class WxPayRefundV3Result implements Serializable {
      * 字段名:微信侧商品编码
      * 变量名:wechatpay_goods_id
      * 是否必填:否
-     * 类型:string[1,32]
+     * 类型:string[1, 32]
      * 描述:
-     *  微信支付定义的统一商品编号(没有可不传)
+     *  微信支付定义的统一商品编号(没有可不传)
      *  示例值:1001
      * </pre>
      */
@@ -423,9 +472,9 @@ public class WxPayRefundV3Result implements Serializable {
      * 字段名:商品名称
      * 变量名:goods_name
      * 是否必填:否
-     * 类型:string[1,256]
+     * 类型:string[1, 256]
      * 描述:
-     *  商品的实际名称
+     *  商品的实际名称
      *  示例值:iPhone6s 16G
      * </pre>
      */
@@ -438,7 +487,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  商品单价金额,单位为分
+     *  商品单价金额,单位为分
      *  示例值:528800
      * </pre>
      */
@@ -451,7 +500,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  商品退款金额,单位为分
+     *  商品退款金额,单位为分
      *  示例值:528800
      * </pre>
      */
@@ -464,7 +513,7 @@ public class WxPayRefundV3Result implements Serializable {
      * 是否必填:是
      * 类型:int
      * 描述:
-     *  单品的退款数量
+     *  单品的退款数量,单位为分
      *  示例值:1
      * </pre>
      */

+ 9 - 4
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/TradeTypeEnum.java

@@ -12,22 +12,27 @@ public enum TradeTypeEnum {
   /**
    * APP
    */
-  APP("/v3/pay/transactions/app"),
+  APP("/v3/pay/transactions/app", "/v3/combine-transactions/app"),
   /**
    * JSAPI 或 小程序
    */
-  JSAPI("/v3/pay/transactions/jsapi"),
+  JSAPI("/v3/pay/transactions/jsapi", "/v3/combine-transactions/jsapi"),
   /**
    * NATIVE
    */
-  NATIVE("/v3/pay/transactions/native"),
+  NATIVE("/v3/pay/transactions/native", "/v3/combine-transactions/native"),
   /**
    * H5
    */
-  H5("/v3/pay/transactions/h5");
+  H5("/v3/pay/transactions/h5", "/v3/combine-transactions/h5");
 
   /**
    * 单独下单url
    */
   private final String partnerUrl;
+
+  /**
+   * 合并下单url
+   */
+  private final String combineUrl;
 }

+ 0 - 24
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BasePayV3Service.java

@@ -1,24 +0,0 @@
-package com.github.binarywang.wxpay.service;
-
-import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
-import com.github.binarywang.wxpay.exception.WxPayException;
-
-/**
- * <pre>
- *  微信基础支付v3相关服务类.
- * </pre>
- *
- * @author thinsstar
- */
-public interface BasePayV3Service {
-
-  /**
-   * 调用统一下单接口,并组装生成支付所需参数对象.
-   *
-   * @param <T>     请使用{@link com.github.binarywang.wxpay.bean.order}包下的类
-   * @param request 统一下单请求参数
-   * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
-   * @throws WxPayException the wx pay exception
-   */
-  <T> T createOrder(WxPayUnifiedOrderV3Request request) throws WxPayException;
-}

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

@@ -348,6 +348,19 @@ public interface WxPayService {
 
   /**
    * <pre>
+   * 合单查询订单API
+   * 请求URL: https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/{combine_out_trade_no}
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_11.shtml
+   * </pre>
+   *
+   * @param combineOutTradeNo 合单商户订单号
+   * @return 合单支付订单信息
+   * @throws WxPayException the wx pay exception
+   */
+  CombineQueryResult queryCombine(String combineOutTradeNo) throws WxPayException;
+
+  /**
+   * <pre>
    * 关闭订单.
    * 应用场景
    * 以下情况需要调用关单接口:
@@ -417,6 +430,18 @@ public interface WxPayService {
   void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException;
 
   /**
+   * <pre>
+   * 合单关闭订单API
+   * 请求URL: https://api.mch.weixin.qq.com/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_12.shtml
+   * </pre>
+   *
+   * @param request 请求对象
+   * @throws WxPayException the wx pay exception
+   */
+  void closeCombine(CombineCloseRequest request) throws WxPayException;
+
+  /**
    * 调用统一下单接口,并组装生成支付所需参数对象.
    *
    * @param <T>     请使用{@link com.github.binarywang.wxpay.bean.order}包下的类
@@ -469,6 +494,42 @@ public interface WxPayService {
   WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException;
 
   /**
+   * <pre>
+   * 合单支付API(APP支付、JSAPI支付、H5支付、NATIVE支付).
+   * 请求URL:
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/app
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/h5
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/jsapi
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/native
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_9_3.shtml
+   * </pre>
+   *
+   * @param tradeType 支付方式
+   * @param request   请求对象
+   * @return 微信合单支付返回 combine transactions result
+   * @throws WxPayException the wx pay exception
+   */
+  CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 合单支付API(APP支付、JSAPI支付、H5支付、NATIVE支付).
+   * 请求URL:
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/app
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/h5
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/jsapi
+   *  https://api.mch.weixin.qq.com/v3/combine-transactions/native
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_9_3.shtml
+   * </pre>
+   *
+   * @param tradeType 支付方式
+   * @param request   请求对象
+   * @return 调起支付需要的参数 t
+   * @throws WxPayException the wx pay exception
+   */
+  <T> T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException;
+
+  /**
    * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数.
    * 详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5
    *
@@ -684,6 +745,19 @@ public interface WxPayService {
   WxPayOrderNotifyV3Result parseOrderNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;
 
   /**
+   * <pre>
+   * 合单支付通知回调数据处理
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_13.shtml
+   * </pre>
+   *
+   * @param notifyData 通知数据
+   * @param header     通知头部数据,不传则表示不校验头
+   * @return 解密后通知数据 combine transactions notify result
+   * @throws WxPayException the wx pay exception
+   */
+  CombineNotifyResult parseCombineNotifyResult(String notifyData, SignatureHeader header) throws WxPayException;
+
+  /**
    * 解析退款结果通知
    * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=9
    *
@@ -908,6 +982,59 @@ public interface WxPayService {
 
   /**
    * <pre>
+   * 申请交易账单API
+   * 微信支付按天提供交易账单文件,商户可以通过该接口获取账单文件的下载地址。文件内包含交易相关的金额、时间、营销等信息,供商户核对订单、退款、银行到账等情况。
+   * 注意:
+   * • 微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致;
+   * • 对账单中涉及金额的字段单位为“元”;
+   * • 对账单接口只能下载三个月以内的账单。
+   * 接口链接:https://api.mch.weixin.qq.com/v3/bill/tradebill
+   * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_6.shtml">申请交易账单</a>
+   * </pre>
+   *
+   * @param request 申请账单请求
+   * @return Result对象 apply trade bill result
+   * @throws WxPayException the wx pay exception
+   */
+  WxPayApplyBillV3Result applyTradeBill(WxPayApplyTradeBillV3Request request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 申请资金账单API
+   * 微信支付按天提供微信支付账户的资金流水账单文件,商户可以通过该接口获取账单文件的下载地址。文件内包含该账户资金操作相关的业务单号、收支金额、记账时间等信息,供商户进行核对。
+   * 注意:
+   * • 资金账单中的数据反映的是商户微信支付账户资金变动情况;
+   * • 对账单中涉及金额的字段单位为“元”。
+   * 接口链接:https://api.mch.weixin.qq.com/v3/bill/fundflowbill
+   * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_7.shtml">申请资金账单</a>
+   * </pre>
+   *
+   * @param request 申请账单请求
+   * @return Result对象 apply fund flow bill result
+   * @throws WxPayException the wx pay exception
+   */
+  WxPayApplyBillV3Result applyFundFlowBill(WxPayApplyFundFlowBillV3Request request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 下载账单API
+   * 下载账单API为通用接口,交易/资金账单都可以通过该接口获取到对应的账单。
+   * 注意:
+   * • 账单文件的下载地址的有效时间为30s。
+   * • 强烈建议商户将实际账单文件的哈希值和之前从接口获取到的哈希值进行比对,以确认数据的完整性。
+   * • 该接口响应的信息请求头中不包含微信接口响应的签名值,因此需要跳过验签的流程
+   * 接口链接:通过申请账单接口获取到“download_url”,URL有效期30s
+   * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_8.shtml">下载账单</a>
+   * </pre>
+   *
+   * @param url 微信返回的账单地址。
+   * @return 返回数据 return input stream
+   * @throws WxPayException the wx pay exception
+   */
+  InputStream downloadBill(String url) throws WxPayException;
+
+  /**
+   * <pre>
    * 提交付款码支付.
    * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
    * 应用场景:

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

@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -379,6 +380,29 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   }
 
   @Override
+  public CombineNotifyResult parseCombineNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
+    if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) {
+      throw new WxPayException("非法请求,头部信息验证失败");
+    }
+    OriginNotifyResponse response = GSON.fromJson(notifyData, OriginNotifyResponse.class);
+    OriginNotifyResponse.Resource resource = response.getResource();
+    String cipherText = resource.getCiphertext();
+    String associatedData = resource.getAssociatedData();
+    String nonce = resource.getNonce();
+    String apiV3Key = this.getConfig().getApiV3Key();
+    try {
+      String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key);
+      CombineNotifyResult.DecryptNotifyResult decryptNotifyResult = GSON.fromJson(result, CombineNotifyResult.DecryptNotifyResult.class);
+      CombineNotifyResult notifyResult = new CombineNotifyResult();
+      notifyResult.setRawData(response);
+      notifyResult.setResult(decryptNotifyResult);
+      return notifyResult;
+    } catch (GeneralSecurityException | IOException e) {
+      throw new WxPayException("解析报文异常!", e);
+    }
+  }
+
+  @Override
   public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException {
     try {
       log.debug("微信支付退款异步通知参数:{}", xmlData);
@@ -488,6 +512,13 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   }
 
   @Override
+  public CombineQueryResult queryCombine(String combineOutTradeNo) throws WxPayException {
+    String url = String.format("%s/v3/combine-transactions/out-trade-no/%s", this.getPayBaseUrl(), combineOutTradeNo);
+    String response = this.getV3(url);
+    return GSON.fromJson(response, CombineQueryResult.class);
+  }
+
+  @Override
   public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException {
     if (StringUtils.isBlank(outTradeNo)) {
       throw new WxPayException("out_trade_no不能为空");
@@ -531,6 +562,12 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   }
 
   @Override
+  public void closeCombine(CombineCloseRequest request) throws WxPayException {
+    String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo());
+    this.postV3(url, GSON.toJson(request));
+  }
+
+  @Override
   public <T> T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
     WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
     String prepayId = unifiedOrderResult.getPrepayId();
@@ -654,6 +691,25 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   }
 
   @Override
+  public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
+    if (StringUtils.isBlank(request.getCombineAppid())) {
+      request.setCombineAppid(this.getConfig().getAppId());
+    }
+    if (StringUtils.isBlank(request.getCombineMchid())) {
+      request.setCombineMchid(this.getConfig().getMchId());
+    }
+    String url = this.getPayBaseUrl() + tradeType.getCombineUrl();
+    String response = this.postV3(url, GSON.toJson(request));
+    return GSON.fromJson(response, CombineTransactionsResult.class);
+  }
+
+  @Override
+  public <T> T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
+    CombineTransactionsResult result = this.combine(tradeType, request);
+    return result.getPayInfo(tradeType, request.getCombineAppid(), request.getCombineAppid(), this.getConfig().getPrivateKey());
+  }
+
+  @Override
   @Deprecated
   public Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException {
     WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
@@ -950,6 +1006,35 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   }
 
   @Override
+  public WxPayApplyBillV3Result applyTradeBill(WxPayApplyTradeBillV3Request request) throws WxPayException {
+    String url;
+    if (StringUtils.isBlank(request.getTarType())) {
+      url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType());
+    } else {
+      url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType(), request.getTarType());
+    }
+    String response = this.getV3(url);
+    return GSON.fromJson(response, WxPayApplyBillV3Result.class);
+  }
+
+  @Override
+  public WxPayApplyBillV3Result applyFundFlowBill(WxPayApplyFundFlowBillV3Request request) throws WxPayException {
+    String url;
+    if (StringUtils.isBlank(request.getTarType())) {
+      url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&bill_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType());
+    } else {
+      url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&bill_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType(), request.getTarType());
+    }
+    String response = this.getV3(url);
+    return GSON.fromJson(response, WxPayApplyBillV3Result.class);
+  }
+
+  @Override
+  public InputStream downloadBill(String url) throws WxPayException {
+    return this.downloadV3(url);
+  }
+
+  @Override
   public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());