From efb2c52011fb25575065b9d9b9ce73b7ad360078 Mon Sep 17 00:00:00 2001 From: thinsstar <43289204+thinsstar@users.noreply.github.com> Date: Fri, 21 May 2021 22:07:02 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20#2130=20=E3=80=90=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E3=80=91=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E9=83=A8=E5=88=86v3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/notify/OriginNotifyResponse.java | 165 +++++ .../wxpay/bean/notify/SignatureHeader.java | 32 + .../bean/notify/WxPayOrderNotifyV3Result.java | 542 +++++++++++++++++ .../notify/WxPayRefundNotifyV3Result.java | 214 +++++++ .../request/WxPayOrderCloseV3Request.java | 47 ++ .../request/WxPayOrderQueryV3Request.java | 62 ++ .../request/WxPayRefundQueryV3Request.java | 34 ++ .../bean/request/WxPayRefundV3Request.java | 240 ++++++++ .../request/WxPayUnifiedOrderV3Request.java | 565 ++++++++++++++++++ .../bean/result/WxPayOrderQueryV3Result.java | 528 ++++++++++++++++ .../bean/result/WxPayRefundQueryV3Result.java | 473 +++++++++++++++ .../bean/result/WxPayRefundV3Result.java | 474 +++++++++++++++ .../result/WxPayUnifiedOrderV3Result.java | 124 ++++ .../bean/result/enums/TradeTypeEnum.java | 33 + .../wxpay/service/BasePayV3Service.java | 24 + .../wxpay/service/WxPayService.java | 184 +++++- .../service/impl/BaseWxPayServiceImpl.java | 153 ++++- .../impl/BaseWxPayServiceImplTest.java | 71 +++ 18 files changed, 3959 insertions(+), 6 deletions(-) create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/OriginNotifyResponse.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyV3Result.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyV3Result.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseV3Request.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryV3Request.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryV3Request.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundV3Request.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryV3Result.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryV3Result.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundV3Result.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderV3Result.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/TradeTypeEnum.java create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BasePayV3Service.java diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/OriginNotifyResponse.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/OriginNotifyResponse.java new file mode 100644 index 0000000000..7efd9adb06 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/OriginNotifyResponse.java @@ -0,0 +1,165 @@ +package com.github.binarywang.wxpay.bean.notify; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +public class OriginNotifyResponse implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:通知ID
+   * 变量名:id
+   * 是否必填:是
+   * 类型:string[1,36]
+   * 描述:
+   *  通知的唯一ID
+   *  示例值:EV-2018022511223320873
+   * 
+ */ + @SerializedName(value = "id") + private String id; + /** + *
+   * 字段名:通知创建时间
+   * 变量名: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年5月20日13点29分35秒。
+   *  示例值:2018-06-08T10:34:56+08:00
+   * 
+ */ + @SerializedName(value = "create_time") + private String createTime; + /** + *
+   * 字段名:通知类型
+   * 变量名:event_type
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  通知的类型:
+   *  REFUND.SUCCESS:退款成功通知
+   *  REFUND.ABNORMAL:退款异常通知
+   *  REFUND.CLOSED:退款关闭通知
+   *  示例值:REFUND.SUCCESS
+   * 
+ */ + @SerializedName(value = "event_type") + private String eventType; + /** + *
+   * 字段名:通知简要说明
+   * 变量名:summary
+   * 是否必填:是
+   * 类型:string[1,16]
+   * 描述:
+   *  通知简要说明
+   *  示例值:退款成功
+   * 
+ */ + @SerializedName(value = "summary") + private String summary; + /** + *
+   * 字段名:通知数据类型
+   * 变量名:resource_type
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  通知的资源数据类型,支付成功通知为encrypt-resource
+   *  示例值:encrypt-resource
+   * 
+ */ + @SerializedName(value = "resource_type") + private String resourceType; + /** + *
+   * 字段名:通知数据
+   * 变量名:resource
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  通知资源数据
+   *  json格式,见示例
+   * 
+ */ + @SerializedName(value = "resource") + private Resource resource; + + @Data + @NoArgsConstructor + public static class Resource implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:加密算法类型
+     * 变量名:algorithm
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM
+     *  示例值:AEAD_AES_256_GCM
+     * 
+ */ + @SerializedName(value = "algorithm") + private String algorithm; + /** + *
+     * 字段名:原始类型
+     * 变量名:original_type
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  原始回调类型,为transaction
+     *  示例值:transaction
+     * 
+ */ + @SerializedName(value = "original_type") + private String originalType; + /** + *
+     * 字段名:数据密文
+     * 变量名:ciphertext
+     * 是否必填:是
+     * 类型:string[1,1048576]
+     * 描述:
+     *  Base64编码后的开启/停用结果数据密文
+     *  示例值:sadsadsadsad
+     * 
+ */ + @SerializedName(value = "ciphertext") + private String ciphertext; + /** + *
+     * 字段名:附加数据
+     * 变量名:associated_data
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  附加数据
+     *  示例值:fdasfwqewlkja484w
+     * 
+ */ + @SerializedName(value = "associated_data") + private String associatedData; + /** + *
+     * 字段名:随机串
+     * 变量名:nonce
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  加密使用的随机串
+     *  示例值:fdasflkja484w
+     * 
+ */ + @SerializedName(value = "nonce") + private String nonce; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java new file mode 100644 index 0000000000..d010637a8c --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/SignatureHeader.java @@ -0,0 +1,32 @@ +package com.github.binarywang.wxpay.bean.notify; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 微信通知接口头部信息,需要做签名验证 + * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml + */ +@Data +@NoArgsConstructor +public class SignatureHeader implements Serializable { + private static final long serialVersionUID = -1L; + /** + * 时间戳 + */ + private String timeStamp; + /** + * 随机串 + */ + private String nonce; + /** + * 已签名字符串 + */ + private String signature; + /** + * 证书序列号 + */ + private String serial; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyV3Result.java new file mode 100644 index 0000000000..549e2af16c --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyV3Result.java @@ -0,0 +1,542 @@ +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; + +/** + * 支付结果通知. + * 文档见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml + * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayOrderNotifyV3Result 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; + /** + *
+     * 字段名:应用ID
+     * 变量名:appid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  直连商户申请的公众号或移动应用appid。
+     *  示例值:wxd678efh567hg6787
+     * 
+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+     * 字段名:商户号
+     * 变量名:mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
+     *  特殊规则:最小字符长度为6
+     *  示例值:1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "mchid") + private String mchid; + /** + *
+     * 字段名:商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:string[6,32]
+     * 描述:
+     *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
+     *  特殊规则:最小字符长度为6
+     *  示例值:1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + /** + *
+     * 字段名:微信支付订单号
+     * 变量名:transaction_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付系统生成的订单号。
+     *  示例值:1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+     * 字段名:交易类型
+     * 变量名:trade_type
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  交易类型,枚举值:
+     *  JSAPI:公众号支付
+     *  NATIVE:扫码支付
+     *  APP:APP支付
+     *  MICROPAY:付款码支付
+     *  MWEB:H5支付
+     *  FACEPAY:刷脸支付
+     *  示例值:MICROPAY
+     * 
+ */ + @SerializedName(value = "trade_type") + private String tradeType; + /** + *
+     * 字段名:交易状态
+     * 变量名:trade_state
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  交易状态,枚举值:
+     *  SUCCESS:支付成功
+     *  REFUND:转入退款
+     *  NOTPAY:未支付
+     *  CLOSED:已关闭
+     *  REVOKED:已撤销(付款码支付)
+     *  USERPAYING:用户支付中(付款码支付)
+     *  PAYERROR:支付失败(其他原因,如银行返回失败)
+     *  示例值:SUCCESS
+     * 
+ */ + @SerializedName(value = "trade_state") + private String tradeState; + /** + *
+     * 字段名:交易状态描述
+     * 变量名:trade_state_desc
+     * 是否必填:是
+     * 类型:string[1,256]
+     * 描述:
+     *  交易状态描述
+     *  示例值:支付成功
+     * 
+ */ + @SerializedName(value = "trade_state_desc") + private String tradeStateDesc; + /** + *
+     * 字段名:付款银行
+     * 变量名:bank_type
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  银行类型,采用字符串类型的银行标识。银行标识请参考《银行类型对照表》https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6
+     *  示例值:CMC
+     * 
+ */ + @SerializedName(value = "bank_type") + private String bankType; + /** + *
+     * 字段名:附加数据
+     * 变量名:attach
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
+     *  示例值:自定义数据
+     * 
+ */ + @SerializedName(value = "attach") + private String attach; + /** + *
+     * 字段名:支付完成时间
+     * 变量名:success_time
+     * 是否必填:是
+     * 类型: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秒。
+     *  示例值:2018-06-08T10:34:56+08:00
+     * 
+ */ + @SerializedName(value = "success_time") + private String successTime; + /** + *
+     * 字段名:支付者
+     * 变量名:payer
+     * 是否必填:是
+     * 类型:object
+     * 描述:
+     *  支付者信息
+     * 
+ */ + private Payer payer; + /** + *
+     * 字段名:订单金额
+     * 变量名:amount
+     * 是否必填:否
+     * 类型:object
+     * 描述:
+     *  订单金额信息
+     * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + /** + *
+     * 字段名:场景信息
+     * 变量名:scene_info
+     * 是否必填:否
+     * 类型:object
+     * 描述:
+     *  支付场景信息描述
+     * 
+ */ + @SerializedName(value = "scene_info") + private SceneInfo sceneInfo; + /** + *
+     * 字段名:优惠功能
+     * 变量名:promotion_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  优惠功能,享受优惠时返回该字段。
+     * 
+ */ + @SerializedName(value = "promotion_detail") + private List promotionDetails; + } + @Data + @NoArgsConstructor + public static class Payer implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:用户标识
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  用户在直连商户appid下的唯一标识。
+     *  示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * 
+ */ + @SerializedName(value = "openid") + private String openid; + } + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:总金额
+     * 变量名:total
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  订单总金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:用户支付金额
+     * 变量名:payer_total
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  用户支付金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "payer_total") + private Integer payerTotal; + /** + *
+     * 字段名:货币类型
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + /** + *
+     * 字段名:用户支付币种
+     * 变量名:payer_currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  用户支付币种
+     *  示例值: CNY
+     * 
+ */ + @SerializedName(value = "payer_currency") + private String payerCurrency; + } + + @Data + @NoArgsConstructor + public static class SceneInfo implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:商户端设备号
+     * 变量名:device_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  终端设备号(门店号或收银设备ID)。
+     *  示例值:013467007045764
+     * 
+ */ + @SerializedName(value = "device_id") + private String deviceId; + } + + @Data + @NoArgsConstructor + public static class PromotionDetail implements Serializable { + /** + *
+     * 字段名:券ID
+     * 变量名:coupon_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  券ID
+     *  示例值:109519
+     * 
+ */ + @SerializedName(value = "coupon_id") + private String couponId; + /** + *
+     * 字段名:优惠名称
+     * 变量名:name
+     * 是否必填:否
+     * 类型:string[1,64]
+     * 描述:
+     *  优惠名称
+     *  示例值:单品惠-6
+     * 
+ */ + @SerializedName(value = "name") + private String name; + /** + *
+     * 字段名:优惠范围
+     * 变量名:scope
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  GLOBAL:全场代金券
+     *  SINGLE:单品优惠
+     *  示例值:GLOBAL
+     * 
+ */ + @SerializedName(value = "scope") + private String scope; + /** + *
+     * 字段名:优惠类型
+     * 变量名:type
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  CASH:充值
+     *  NOCASH:预充值
+     *  示例值:CASH
+     * 
+ */ + @SerializedName(value = "type") + private String type; + /** + *
+     * 字段名:优惠券面额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  优惠券面额
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "amount") + private Integer amount; + /** + *
+     * 字段名:活动ID
+     * 变量名:stock_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  活动ID
+     *  示例值:931386
+     * 
+ */ + @SerializedName(value = "stock_id") + private String stockId; + /** + *
+     * 字段名:微信出资
+     * 变量名:wechatpay_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  微信出资,单位为分
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "wechatpay_contribute") + private Integer wechatpayContribute; + /** + *
+     * 字段名:商户出资
+     * 变量名:merchant_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  商户出资,单位为分
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "merchant_contribute") + private Integer merchantContribute; + /** + *
+     * 字段名:其他出资
+     * 变量名:other_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  其他出资,单位为分
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "other_contribute") + private Integer otherContribute; + /** + *
+     * 字段名:优惠币种
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + /** + *
+     * 字段名:单品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  单品列表信息
+     * 
+ */ + @SerializedName(value = "goods_detail") + private List goodsDetails; + } + + @Data + @NoArgsConstructor + public static class GoodsDetail implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:商品编码
+     * 变量名:goods_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  商品编码
+     *  示例值:M1006
+     * 
+ */ + @SerializedName(value = "goods_id") + private String goodsId; + /** + *
+     * 字段名:商品数量
+     * 变量名:quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  用户购买的数量
+     *  示例值:1
+     * 
+ */ + @SerializedName(value = "quantity") + private Integer quantity; + /** + *
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品单价,单位为分
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "unit_price") + private Integer unitPrice; + /** + *
+     * 字段名:商品优惠金额
+     * 变量名:discount_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品优惠金额
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "discount_amount") + private Integer discountAmount; + /** + *
+     * 字段名:商品备注
+     * 变量名:goods_remark
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  商品备注信息
+     *  示例值:商品备注信息
+     * 
+ */ + @SerializedName(value = "goods_remark") + private String goodsRemark; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyV3Result.java new file mode 100644 index 0000000000..39aafe364b --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyV3Result.java @@ -0,0 +1,214 @@ +package com.github.binarywang.wxpay.bean.notify; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 退款结果通知. + * 文档见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_11.shtml + * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayRefundNotifyV3Result 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; + /** + *
+     * 字段名:直连商户号
+     * 变量名:mchid
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  直连商户的商户号,由微信支付生成并下发。
+     *  示例值:1900000100
+     * 
+ */ + @SerializedName(value = "mchid") + private String mchid; + /** + *
+     * 字段名:商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  返回的商户订单号
+     *  示例值: 1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + /** + *
+     * 字段名:微信支付订单号
+     * 变量名:transaction_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付订单号
+     *  示例值: 1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+     * 字段名:商户退款单号
+     * 变量名:out_refund_no
+     * 是否必填:是
+     * 类型:string[1,64]
+     * 描述:
+     *  商户退款单号
+     *  示例值: 1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "out_refund_no") + private String outRefundNo; + /** + *
+     * 字段名:微信支付退款号
+     * 变量名:refund_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  微信退款单号
+     *  示例值: 1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "refund_id") + private String refundId; + /** + *
+     * 字段名:退款状态
+     * 变量名:refund_status
+     * 是否必填:是
+     * 类型:string[1,16]
+     * 描述:
+     *  退款状态,枚举值:
+     *  SUCCESS:退款成功
+     *  CLOSE:退款关闭
+     *  ABNORMAL:退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款
+     * 示例值:SUCCESS
+     * 
+ */ + @SerializedName(value = "refund_status") + private String refundStatus; + /** + *
+     * 字段名:退款成功时间
+     * 变量名:success_time
+     * 是否必填:否
+     * 类型:string[1,64]
+     * 描述:
+     *  1、退款成功时间,遵循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秒。
+     *  2、当退款状态为退款成功时返回此参数。
+     *  示例值:2018-06-08T10:34:56+08:00
+     * 
+ */ + @SerializedName(value = "success_time") + private String successTime; + /** + *
+     * 字段名:退款入账账户
+     * 变量名:user_received_account
+     * 是否必填:是
+     * 类型:string[1,64]
+     * 描述:
+     *  取当前退款单的退款入账方。
+     *  1、退回银行卡:{银行名称}{卡类型}{卡尾号}
+     *  2、退回支付用户零钱: 支付用户零钱
+     *  3、退还商户: 商户基本账户、商户结算银行账户
+     *  4、退回支付用户零钱通:支付用户零钱通
+     *  示例值:招商银行信用卡0403
+     * 
+ */ + @SerializedName(value = "user_received_account") + private String userReceivedAccount; + /** + *
+     * 字段名:金额信息
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:object
+     * 描述:
+     *  金额信息
+     * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + } + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + /** + *
+     * 字段名:订单金额
+     * 变量名:total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  订单总金额,单位为分,只能为整数,详见支付金额
+     *  示例值:999
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:退款金额
+     * 变量名:refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款金额,币种的最小单位,只能为整数,不能超过原订单支付金额,如果有使用券,后台会按比例退。
+     *  示例值:999
+     * 
+ */ + @SerializedName(value = "refund") + private String refund; + /** + *
+     * 字段名:用户支付金额
+     * 变量名:payer_total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  用户实际支付金额,单位为分,只能为整数,详见支付金额
+     *  示例值:999
+     * 
+ */ + @SerializedName(value = "payer_total") + private Integer payerTotal; + /** + *
+     * 字段名:用户退款金额
+     * 变量名:payer_refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款给用户的金额,不包含所有优惠券金额
+     *  示例值:999
+     * 
+ */ + @SerializedName(value = "payer_refund") + private String payerRefund; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseV3Request.java new file mode 100644 index 0000000000..8031d7a25f --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseV3Request.java @@ -0,0 +1,47 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *
+ *  关闭订单请求对象类
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class WxPayOrderCloseV3Request implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:直连商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  直连商户的商户号,由微信支付生成并下发。
+   *  示例值:1230000109
+   * 
+ */ + @SerializedName(value = "mchid") + private String mchid; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[6,32]
+   * 描述:
+   *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + private transient String outTradeNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryV3Request.java new file mode 100644 index 0000000000..9dd1944ba6 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryV3Request.java @@ -0,0 +1,62 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *
+ * 订单查询请求对象
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class WxPayOrderQueryV3Request implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:直连商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  直连商户的商户号,由微信支付生成并下发。
+   *  示例值:1230000109
+   * 
+ */ + @SerializedName(value = "mchid") + private String mchid; + /** + *
+   * 字段名:微信支付订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  微信支付系统生成的订单号
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
+   *  特殊规则:最小字符长度为6
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryV3Request.java new file mode 100644 index 0000000000..d29f41a4c0 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryV3Request.java @@ -0,0 +1,34 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + *
+ * 微信支付-查询单笔退款API
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayRefundQueryV3Request implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
+   *  特殊规则:最小字符长度为6
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundV3Request.java new file mode 100644 index 0000000000..da90306de4 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundV3Request.java @@ -0,0 +1,240 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.google.gson.annotations.SerializedName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +/** + *
+ * 微信支付-申请退款请求参数
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class WxPayRefundV3Request implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+   * 字段名:微信支付订单号
+   * 变量名:transaction_id
+   * 是否必填:与out_order_no二选一
+   * 类型:string[1, 32]
+   * 描述:
+   *  原支付交易对应的微信订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:与transaction_id二选一
+   * 类型:string[1, 32]
+   * 描述:
+   *  原支付交易对应的商户订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + /** + *
+   * 字段名:商户退款单号
+   * 变量名:out_refund_no
+   * 是否必填:是
+   * 类型:string[1, 64]
+   * 描述:
+   *   商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_refund_no") + private String outRefundNo; + /** + *
+   * 字段名:退款原因
+   * 变量名:reason
+   * 是否必填:否
+   * 类型:string[1, 80]
+   * 描述:
+   *  若商户传入,会在下发给用户的退款消息中体现退款原因。
+   *  示例值:商品已售完
+   * 
+ */ + @SerializedName(value = "reason") + private String reason; + /** + *
+   * 字段名:退款结果回调url
+   * 变量名:notify_url
+   * 是否必填:否
+   * 类型:string[8, 256]
+   * 描述:
+   *  异步接收微信支付退款结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 如果参数中传了notify_url,则商户平台上配置的回调地址将不会生效,优先回调当前传的这个地址。
+   *  示例值:https://weixin.qq.com
+   * 
+ */ + @SerializedName(value = "notify_url") + private String notifyUrl; + /** + *
+   * 字段名:订单金额
+   * 变量名:amount
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  订单金额信息
+   * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + /** + *
+   * 字段名:退款商品
+   * 变量名:goods_detail
+   * 是否必填:否
+   * 类型:array
+   * 描述:
+   *  指定商品退款需要传此参数,其他场景无需传递。
+   * 
+ */ + @SerializedName(value = "goods_detail") + private List goodsDetails; + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:退款金额
+     * 变量名:refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款金额,币种的最小单位,只能为整数,不能超过原订单支付金额。
+     *  示例值:888
+     * 
+ */ + @SerializedName(value = "refund") + private Integer refund; + /** + *
+     * 字段名:原订单金额
+     * 变量名:total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  原支付交易的订单总金额,币种的最小单位,只能为整数。
+     *  示例值:888
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:币类型
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1, 16]
+     * 描述:
+     *  符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + } + + @Data + @NoArgsConstructor + public static class GoodsDetail implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:商户侧商品编码
+     * 变量名:merchant_goods_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
+     *  示例值:1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "merchant_goods_id") + private String merchantGoodsId; + /** + *
+     * 字段名:微信侧商品编码
+     * 变量名:wechatpay_goods_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付定义的统一商品编号(没有可不传)。
+     *  示例值:1001
+     * 
+ */ + @SerializedName(value = "wechatpay_goods_id") + private String wechatpayGoodsId; + /** + *
+     * 字段名:商品名称
+     * 变量名:goods_name
+     * 是否必填:否
+     * 类型:string[1,256]
+     * 描述:
+     *  商品的实际名称。
+     *  示例值:iPhone6s 16G
+     * 
+ */ + @SerializedName(value = "goods_name") + private String goodsName; + /** + *
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品单价金额,单位为分。
+     *  示例值:528800
+     * 
+ */ + @SerializedName(value = "unit_price") + private Integer unitPrice; + /** + *
+     * 字段名:商品退款金额
+     * 变量名:refund_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品退款金额,单位为分。
+     *  示例值:528800
+     * 
+ */ + @SerializedName(value = "refund_amount") + private Integer refundAmount; + /** + *
+     * 字段名:商品退货数量
+     * 变量名:refund_quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  单品的退款数量。
+     *  示例值:1
+     * 
+ */ + @SerializedName(value = "refund_quantity") + private Integer refundQuantity; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java new file mode 100644 index 0000000000..c0bf417825 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java @@ -0,0 +1,565 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +/** + *
+ * 统一下单请求参数对象.
+ * 参考文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class WxPayUnifiedOrderV3Request implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:应用ID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  由微信生成的应用ID,全局唯一。请求统一下单接口时请注意APPID的应用属性,例如公众号场景下,需使用应用属性为公众号的APPID
+   *  示例值:wxd678efh567hg6787
+   * 
+ */ + @SerializedName(value = "appid") + protected String appid; + /** + *
+   * 字段名:直连商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  直连商户的商户号,由微信支付生成并下发。
+   *  示例值:1230000109
+   * 
+ */ + @SerializedName(value = "mchid") + protected String mchid; + /** + *
+   * 字段名:商品描述
+   * 变量名:description
+   * 是否必填:是
+   * 类型:string[1,127]
+   * 描述:
+   *  商品描述
+   *  示例值:Image形象店-深圳腾大-QQ公仔
+   * 
+ */ + @SerializedName(value = "description") + protected String description; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[6,32]
+   * 描述:
+   *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + protected String outTradeNo; + /** + *
+   * 字段名:交易结束时间
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型: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秒。
+   *  示例值:2018-06-08T10:34:56+08:00
+   * 
+ */ + @SerializedName(value = "time_expire") + protected String timeExpire; + /** + *
+   * 字段名:附加数据
+   * 变量名:attach
+   * 是否必填:否
+   * 类型:string[1,128]
+   * 描述:
+   *  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
+   *  示例值:自定义数据
+   * 
+ */ + @SerializedName(value = "attach") + protected String attach; + /** + *
+   * 字段名:通知地址
+   * 变量名:notify_url
+   * 是否必填:是
+   * 类型:string[1,256]
+   * 描述:
+   *  通知URL必须为直接可访问的URL,不允许携带查询串,要求必须为https地址。
+   *  格式:URL
+   *  示例值:https://www.weixin.qq.com/wxpay/pay.php
+   * 
+ */ + @SerializedName(value = "notify_url") + private String notifyUrl; + /** + *
+   * 字段名:订单优惠标记
+   * 变量名:goods_tag
+   * 是否必填:否
+   * 类型:string[1,256]
+   * 描述:
+   *  订单优惠标记
+   *  示例值:WXG
+   * 
+ */ + @SerializedName(value = "goods_tag") + private String goodsTag; + /** + *
+   * 字段名:订单金额
+   * 变量名:amount
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  订单金额信息
+   * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + /** + *
+   * 字段名:支付者
+   * 变量名:payer
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  支付者信息
+   * 
+ */ + @SerializedName(value = "payer") + private Payer payer; + /** + *
+   * 字段名:优惠功能
+   * 变量名:detail
+   * 是否必填:否
+   * 类型:object
+   * 描述:
+   *  优惠功能
+   * 
+ */ + @SerializedName(value = "detail") + private Discount detail; + /** + *
+   * 字段名:场景信息
+   * 变量名:scene_info
+   * 是否必填:否
+   * 类型:object
+   * 描述:
+   *  支付场景描述
+   * 
+ */ + @SerializedName(value = "scene_info") + private SceneInfo sceneInfo; + /** + *
+   * 字段名:结算信息
+   * 变量名:settle_info
+   * 是否必填:否
+   * 类型:Object
+   * 描述:结算信息
+   * 
+ */ + @SerializedName(value = "settle_info") + private SettleInfo settleInfo; + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:总金额
+     * 变量名:total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  订单总金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:币类型
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + } + + @Data + @NoArgsConstructor + public static class Payer implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:用户标识
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  用户在直连商户appid下的唯一标识。
+     *  示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * 
+ */ + @SerializedName(value = "openid") + private String openid; + } + + @Data + @NoArgsConstructor + public static class Discount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:订单原价
+     * 变量名:cost_price
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  1、商户侧一张小票订单可能被分多次支付,订单原价用于记录整张小票的交易金额。
+     *  2、当订单原价与支付金额不相等,则不享受优惠。
+     *  3、该字段主要用于防止同一张小票分多次支付,以享受多次优惠的情况,正常支付订单不必上传此参数。
+     *  示例值:608800
+     * 
+ */ + @SerializedName(value = "cost_price") + private Integer costPrice; + /** + *
+     * 字段名:商品小票ID
+     * 变量名:invoice_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  商品小票ID
+     *  示例值:微信123
+     * 
+ */ + @SerializedName(value = "invoice_id") + private String invoiceId; + /** + *
+     * 字段名:单品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  单品列表信息
+     *  条目个数限制:【1,6000】
+     * 
+ */ + @SerializedName(value = "goods_detail") + private List goodsDetails; + } + + @Data + @NoArgsConstructor + public static class GoodsDetail implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:商户侧商品编码
+     * 变量名:merchant_goods_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
+     *  示例值:商品编码
+     * 
+ */ + @SerializedName(value = "merchant_goods_id") + private String merchantGoodsId; + /** + *
+     * 字段名:微信侧商品编码
+     * 变量名:wechatpay_goods_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付定义的统一商品编号(没有可不传)
+     *  示例值:1001
+     * 
+ */ + @SerializedName(value = "wechatpay_goods_id") + private String wechatpayGoodsId; + /** + *
+     * 字段名:商品名称
+     * 变量名:goods_name
+     * 是否必填:否
+     * 类型:string[1,256]
+     * 描述:
+     *  商品的实际名称
+     *  示例值:iPhoneX 256G
+     * 
+ */ + @SerializedName(value = "goods_name") + private String goodsName; + /** + *
+     * 字段名:商品数量
+     * 变量名:quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  用户购买的数量
+     *  示例值:1
+     * 
+ */ + @SerializedName(value = "quantity") + private Integer quantity; + /** + *
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品单价,单位为分
+     *  示例值:828800
+     * 
+ */ + @SerializedName(value = "unit_price") + private Integer unitPrice; + } + + @Data + @NoArgsConstructor + public static class SceneInfo implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:用户终端IP
+     * 变量名:payer_client_ip
+     * 是否必填:是
+     * 类型:string[1,45]
+     * 描述:
+     *  用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。
+     *  示例值:14.23.150.211
+     * 
+ */ + @SerializedName(value = "payer_client_ip") + private String payerClientIp; + /** + *
+     * 字段名:商户端设备号
+     * 变量名:device_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  商户端设备号(门店号或收银设备ID)。
+     *  示例值:013467007045764
+     * 
+ */ + @SerializedName(value = "device_id") + private String deviceId; + /** + *
+     * 字段名:商户门店信息
+     * 变量名:store_info
+     * 是否必填:否
+     * 类型:object
+     * 描述:
+     *  商户门店信息
+     * 
+ */ + @SerializedName(value = "store_info") + private StoreInfo storeInfo; + /** + *
+     * 字段名:H5场景信息
+     * 变量名:h5_info
+     * 是否必填:否(H5支付必填)
+     * 类型:object
+     * 描述:
+     *  H5场景信息
+     * 
+ */ + @SerializedName(value = "h5_info") + private H5Info h5Info; + } + + @Data + @NoArgsConstructor + public static class StoreInfo implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:门店编号
+     * 变量名:id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  商户侧门店编号
+     *  示例值:0001
+     * 
+ */ + @SerializedName(value = "id") + private String id; + /** + *
+     * 字段名:门店名称
+     * 变量名:name
+     * 是否必填:否
+     * 类型:string[1,256]
+     * 描述:
+     *  商户侧门店名称
+     *  示例值:腾讯大厦分店
+     * 
+ */ + @SerializedName(value = "name") + private String name; + /** + *
+     * 字段名:地区编码
+     * 变量名:area_code
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  地区编码,详细请见省市区编号对照表(https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml)。
+     * 示例值:440305
+     * 
+ */ + @SerializedName(value = "area_code") + private String areaCode; + /** + *
+     * 字段名:详细地址
+     * 变量名:address
+     * 是否必填:是
+     * 类型:string[1,512]
+     * 描述:
+     *  详细的商户门店地址
+     *  示例值:广东省深圳市南山区科技中一道10000号
+     * 
+ */ + @SerializedName(value = "address") + private String address; + } + + @Data + @NoArgsConstructor + public static class H5Info implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:场景类型
+     * 变量名:type
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  场景类型
+     *  示例值:iOS, Android, Wap
+     * 
+ */ + @SerializedName(value = "type") + private String type; + /** + *
+     * 字段名:应用名称
+     * 变量名:app_name
+     * 是否必填:否
+     * 类型:string[1,64]
+     * 描述:
+     *  应用名称
+     *  示例值:王者荣耀
+     * 
+ */ + @SerializedName(value = "app_name") + private String appName; + /** + *
+     * 字段名:网站URL
+     * 变量名:app_url
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  网站URL
+     *  示例值:https://pay.qq.com
+     * 
+ */ + @SerializedName(value = "app_url") + private String appUrl; + /** + *
+     * 字段名:iOS平台BundleID
+     * 变量名:bundle_id
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  iOS平台BundleID
+     *  示例值:com.tencent.wzryiOS
+     * 
+ */ + @SerializedName(value = "bundle_id") + private String bundleId; + /** + *
+     * 字段名:Android平台PackageName
+     * 变量名:package_name
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  Android平台PackageName
+     *  示例值:com.tencent.tmgp.sgame
+     * 
+ */ + @SerializedName(value = "package_name") + private String packageName; + } + + @Data + @NoArgsConstructor + public static class SettleInfo implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:是否指定分账
+     * 变量名:profit_sharing
+     * 是否必填:否
+     * 类型:boolean
+     * 描述:
+     *  是否指定分账
+     *  示例值:false
+     * 
+ */ + @SerializedName(value = "profit_sharing") + private Boolean profitSharing; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryV3Result.java new file mode 100644 index 0000000000..ca3ed4c96b --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderQueryV3Result.java @@ -0,0 +1,528 @@ +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; + +/** + *
+ *  查询订单 返回结果对象
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayOrderQueryV3Result implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:应用ID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  直连商户申请的公众号或移动应用appid。
+   *  示例值:wxd678efh567hg6787
+   * 
+ */ + @SerializedName(value = "appid") + private String appid; + /** + *
+   * 字段名:直连商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  直连商户的商户号,由微信支付生成并下发。
+   *  示例值:1230000109
+   * 
+ */ + @SerializedName(value = "mchid") + private String mchid; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[6,32]
+   * 描述:
+   *  商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,详见【商户订单号】。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + /** + *
+   * 字段名:微信支付订单号
+   * 变量名:transaction_id
+   * 是否必填:否
+   * 类型:string[1,32]
+   * 描述:
+   *  微信支付系统生成的订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+   * 字段名:交易类型
+   * 变量名:trade_type
+   * 是否必填:否
+   * 类型:string[1,16]
+   * 描述:
+   *  交易类型,枚举值:
+   *  JSAPI:公众号支付
+   *  NATIVE:扫码支付
+   *  APP:APP支付
+   *  MICROPAY:付款码支付
+   *  MWEB:H5支付
+   *  FACEPAY:刷脸支付
+   *  示例值:MICROPAY
+   * 
+ */ + @SerializedName(value = "trade_type") + private String tradeType; + /** + *
+   * 字段名:交易状态
+   * 变量名:trade_state
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  交易状态,枚举值:
+   *  SUCCESS:支付成功
+   *  REFUND:转入退款
+   *  NOTPAY:未支付
+   *  CLOSED:已关闭
+   *  REVOKED:已撤销(付款码支付)
+   *  USERPAYING:用户支付中(付款码支付)
+   *  PAYERROR:支付失败(其他原因,如银行返回失败)
+   *  ACCEPT:已接收,等待扣款
+   *  示例值:SUCCESS
+   * 
+ */ + @SerializedName(value = "trade_state") + private String tradeState; + /** + *
+   * 字段名:交易状态描述
+   * 变量名:trade_state_desc
+   * 是否必填:是
+   * 类型:string[1,256]
+   * 描述:
+   *  交易状态描述
+   *  示例值:支付成功
+   * 
+ */ + @SerializedName(value = "trade_state_desc") + private String tradeStateDesc; + /** + *
+   * 字段名:付款银行
+   * 变量名:bank_type
+   * 是否必填:否
+   * 类型:string[1,16]
+   * 描述:
+   *  银行类型,采用字符串类型的银行标识。银行标识请参考《银行类型对照表》https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6
+   *  示例值:CMC
+   * 
+ */ + @SerializedName(value = "bank_type") + private String bankType; + /** + *
+   * 字段名:附加数据
+   * 变量名:attach
+   * 是否必填:否
+   * 类型:string[1,128]
+   * 描述:
+   *  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
+   *  示例值:自定义数据
+   * 
+ */ + @SerializedName(value = "attach") + private String attach; + /** + *
+   * 字段名:支付完成时间
+   * 变量名:success_time
+   * 是否必填:否
+   * 类型: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秒。
+   *  示例值:2018-06-08T10:34:56+08:00
+   * 
+ */ + @SerializedName(value = "success_time") + private String successTime; + /** + *
+   * 字段名:支付者
+   * 变量名:payer
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  支付者信息
+   * 
+ */ + private Payer payer; + /** + *
+   * 字段名:订单金额
+   * 变量名:amount
+   * 是否必填:否
+   * 类型:object
+   * 描述:
+   *  订单金额信息,当支付成功时返回该字段。
+   * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + /** + *
+   * 字段名:场景信息
+   * 变量名:scene_info
+   * 是否必填:否
+   * 类型:object
+   * 描述:
+   *  支付场景描述
+   * 
+ */ + @SerializedName(value = "scene_info") + private SceneInfo sceneInfo; + /** + *
+   * 字段名:优惠功能
+   * 变量名:promotion_detail
+   * 是否必填:否
+   * 类型:array
+   * 描述:
+   *  优惠功能,享受优惠时返回该字段。
+   * 
+ */ + @SerializedName(value = "promotion_detail") + private List promotionDetails; + + @Data + @NoArgsConstructor + public static class Payer implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:用户标识
+     * 变量名:openid
+     * 是否必填:是
+     * 类型:string[1,128]
+     * 描述:
+     *  用户在直连商户appid下的唯一标识。
+     *  示例值:oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * 
+ */ + @SerializedName(value = "openid") + private String openid; + } + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:总金额
+     * 变量名:total
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  订单总金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:用户支付金额
+     * 变量名:payer_total
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  用户支付金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "payer_total") + private Integer payerTotal; + /** + *
+     * 字段名:货币类型
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + /** + *
+     * 字段名:用户支付币种
+     * 变量名:payer_currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  用户支付币种
+     *  示例值: CNY
+     * 
+ */ + @SerializedName(value = "payer_currency") + private String payerCurrency; + } + + @Data + @NoArgsConstructor + public static class SceneInfo implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:商户端设备号
+     * 变量名:device_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  商户端设备号(发起扣款请求的商户服务器设备号)。
+     *  示例值:013467007045764
+     * 
+ */ + @SerializedName(value = "device_id") + private String deviceId; + } + + @Data + @NoArgsConstructor + public static class PromotionDetail implements Serializable { + /** + *
+     * 字段名:券ID
+     * 变量名:coupon_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  券ID
+     *  示例值:109519
+     * 
+ */ + @SerializedName(value = "coupon_id") + private String couponId; + /** + *
+     * 字段名:优惠名称
+     * 变量名:name
+     * 是否必填:否
+     * 类型:string[1,64]
+     * 描述:
+     *  优惠名称
+     *  示例值:单品惠-6
+     * 
+ */ + @SerializedName(value = "name") + private String name; + /** + *
+     * 字段名:优惠范围
+     * 变量名:scope
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  GLOBAL:全场代金券
+     *  SINGLE:单品优惠
+     *  示例值:GLOBAL
+     * 
+ */ + @SerializedName(value = "scope") + private String scope; + /** + *
+     * 字段名:优惠类型
+     * 变量名:type
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  CASH:充值
+     *  NOCASH:预充值
+     *  示例值:CASH
+     * 
+ */ + @SerializedName(value = "type") + private String type; + /** + *
+     * 字段名:优惠券面额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  优惠券面额
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "amount") + private Integer amount; + /** + *
+     * 字段名:活动ID
+     * 变量名:stock_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  活动ID
+     *  示例值:931386
+     * 
+ */ + @SerializedName(value = "stock_id") + private String stockId; + /** + *
+     * 字段名:微信出资
+     * 变量名:wechatpay_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  微信出资,单位为分
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "wechatpay_contribute") + private Integer wechatpayContribute; + /** + *
+     * 字段名:商户出资
+     * 变量名:merchant_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  商户出资,单位为分
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "merchant_contribute") + private Integer merchantContribute; + /** + *
+     * 字段名:其他出资
+     * 变量名:other_contribute
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  其他出资,单位为分
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "other_contribute") + private Integer otherContribute; + /** + *
+     * 字段名:优惠币种
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1,16]
+     * 描述:
+     *  CNY:人民币,境内商户号仅支持人民币。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + /** + *
+     * 字段名:单品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  单品列表信息
+     * 
+ */ + @SerializedName(value = "goods_detail") + private List goodsDetails; + } + + @Data + @NoArgsConstructor + public static class GoodsDetail implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:商品编码
+     * 变量名:goods_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  商品编码
+     *  示例值:M1006
+     * 
+ */ + @SerializedName(value = "goods_id") + private String goodsId; + /** + *
+     * 字段名:商品数量
+     * 变量名:quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  用户购买的数量
+     *  示例值:1
+     * 
+ */ + @SerializedName(value = "quantity") + private Integer quantity; + /** + *
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品单价,单位为分
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "unit_price") + private Integer unitPrice; + /** + *
+     * 字段名:商品优惠金额
+     * 变量名:discount_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品优惠金额
+     *  示例值:0
+     * 
+ */ + @SerializedName(value = "discount_amount") + private Integer discountAmount; + /** + *
+     * 字段名:商品备注
+     * 变量名:goods_remark
+     * 是否必填:否
+     * 类型:string[1,128]
+     * 描述:
+     *  商品备注信息
+     *  示例值:商品备注信息
+     * 
+ */ + @SerializedName(value = "goods_remark") + private String goodsRemark; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryV3Result.java new file mode 100644 index 0000000000..7d60d9f28f --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundQueryV3Result.java @@ -0,0 +1,473 @@ +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; + +/** + *
+ * 微信支付-退款查询返回结果
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayRefundQueryV3Result implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:微信支付退款号
+   * 变量名:refund_id
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  微信支付退款号。
+   *  示例值:50000000382019052709732678859
+   * 
+ */ + @SerializedName(value = "refund_id") + private String refundId; + /** + *
+   * 字段名:商户退款单号
+   * 变量名:out_refund_no
+   * 是否必填:是
+   * 类型:string[1, 64]
+   * 描述:
+   *  商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_refund_no") + private String outRefundNo; + /** + *
+   * 字段名:微信支付订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  微信支付交易订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  原支付交易对应的商户订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + /** + *
+   * 字段名:退款渠道
+   * 变量名:channel
+   * 是否必填:否
+   * 类型:string[1, 16]
+   * 描述:
+   *  枚举值:
+   *  ORIGINAL:原路退款
+   *  BALANCE:退回到余额
+   *  OTHER_BALANCE:原账户异常退到其他余额账户
+   *  OTHER_BANKCARD:原银行卡异常退到其他银行卡
+   *  示例值:ORIGINAL
+   * 
+ */ + @SerializedName(value = "channel") + private String channel; + /** + *
+   * 字段名:退款入账账户
+   * 变量名:user_received_account
+   * 是否必填:是
+   * 类型:string[1, 64]
+   * 描述:
+   *  取当前退款单的退款入账方,有以下几种情况:
+   *  1)退回银行卡:{银行名称}{卡类型}{卡尾号}
+   *  2)退回支付用户零钱:支付用户零钱
+   *  3)退还商户:商户基本账户商户结算银行账户
+   *  4)退回支付用户零钱通:支付用户零钱通。
+   *  示例值:招商银行信用卡0403
+   * 
+ */ + @SerializedName(value = "user_received_account") + private String userReceivedAccount; + /** + *
+   * 字段名:退款成功时间
+   * 变量名:success_time
+   * 是否必填:否
+   * 类型: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
+   * 
+ */ + @SerializedName(value = "success_time") + private String successTime; + /** + *
+   * 字段名:退款创建时间
+   * 变量名:create_time
+   * 是否必填:是
+   * 类型: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
+   * 
+ */ + @SerializedName(value = "create_time") + private String createTime; + /** + *
+   * 字段名:退款状态
+   * 变量名:status
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
+   *  枚举值:
+   *  SUCCESS:退款成功
+   *  CLOSED:退款关闭
+   *  PROCESSING:退款处理中
+   *  ABNORMAL:退款异常
+   *  示例值:SUCCESS
+   * 
+ */ + @SerializedName(value = "status") + private String status; + /** + *
+   * 字段名:资金账户
+   * 变量名:funds_account
+   * 是否必填:否
+   * 类型:string[1, 32]
+   * 描述:
+   *  退款所使用资金对应的资金账户类型。 枚举值:
+   *  UNSETTLED : 未结算资金
+   *  AVAILABLE : 可用余额
+   *  UNAVAILABLE : 不可用余额
+   *  OPERATION : 运营户
+   *  示例值:UNSETTLED
+   * 
+ */ + @SerializedName(value = "funds_account") + private String fundsAccount; + /** + *
+   * 字段名:金额信息
+   * 变量名:amount
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  金额详细信息。
+   * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + /** + *
+   * 字段名:优惠退款信息
+   * 变量名:promotion_detail
+   * 是否必填:否
+   * 类型:array
+   * 描述:
+   *  优惠退款信息。
+   * 
+ */ + public List promotionDetails; + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:订单金额
+     * 变量名:total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  订单总金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:退款金额
+     * 变量名:refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款标价金额,单位为分,可以做部分退款。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "refund") + private Integer refund; + /** + *
+     * 字段名:用户支付金额
+     * 变量名:payer_total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  现金支付金额,单位为分,只能为整数。
+     *  示例值:90
+     * 
+ */ + @SerializedName(value = "payer_total") + private Integer payerTotal; + /** + *
+     * 字段名:用户退款金额
+     * 变量名:payer_refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款给用户的金额,不包含所有优惠券金额。
+     *  示例值:90
+     * 
+ */ + @SerializedName(value = "payer_refund") + private Integer payerRefund; + /** + *
+     * 字段名:应结退款金额
+     * 变量名:settlement_refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "settlement_refund") + private Integer settlementRefund; + /** + *
+     * 字段名:用户退款金额
+     * 变量名:settlement_total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "settlement_total") + private Integer settlementTotal; + /** + *
+     * 字段名:优惠退款金额
+     * 变量名:discount_refund
+     * 是否必填:否
+     * 类型:int64
+     * 描述:
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分。
+     *  示例值:10
+     * 
+ */ + @SerializedName(value = "discount_refund") + private Integer discountRefund; + /** + *
+     * 字段名:币类型
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1, 16]
+     * 描述:
+     *  符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + } + + @Data + @NoArgsConstructor + public static class PromotionDetail implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:券ID
+     * 变量名:promotion_id
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  券或者立减优惠id。
+     *  示例值:109519
+     * 
+ */ + @SerializedName(value = "promotion_id") + private String promotionId; + /** + *
+     * 字段名:优惠范围
+     * 变量名:scope
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  枚举值:
+     *  GLOBAL:全场代金券
+     *  SINGLE:单品优惠
+     *  示例值:SINGLE
+     * 
+ */ + @SerializedName(value = "scope") + private String scope; + /** + *
+     * 字段名:优惠类型
+     * 变量名:type
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  枚举值:
+     *  COUPON:代金券,需要走结算资金的充值型代金券
+     *  DISCOUNT:优惠券,不走结算资金的免充值型优惠券
+     *  示例值:DISCOUNT
+     * 
+ */ + @SerializedName(value = "type") + private String type; + /** + *
+     * 字段名:优惠券面额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额 ),单位为分。
+     *  示例值:5
+     * 
+ */ + @SerializedName(value = "amount") + private Integer amount; + /** + *
+     * 字段名:优惠退款金额
+     * 变量名:refund_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为用户支付的现金,说明详见代金券或立减优惠,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "refund_amount") + private Integer refundAmount; + /** + *
+     * 字段名:商品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  优惠商品发生退款时返回商品信息。
+     * 
+ */ + @SerializedName(value = "goods_detail") + private List goodsDetails; + } + + @Data + @NoArgsConstructor + public static class GoodsDetail implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:商户侧商品编码
+     * 变量名:merchant_goods_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
+     *  示例值:1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "merchant_goods_id") + private String merchantGoodsId; + /** + *
+     * 字段名:微信侧商品编码
+     * 变量名:wechatpay_goods_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付定义的统一商品编号(没有可不传)。
+     *  示例值:1001
+     * 
+ */ + @SerializedName(value = "wechatpay_goods_id") + private String wechatpayGoodsId; + /** + *
+     * 字段名:商品名称
+     * 变量名:goods_name
+     * 是否必填:否
+     * 类型:string[1,256]
+     * 描述:
+     *  商品的实际名称。
+     *  示例值:iPhone6s 16G
+     * 
+ */ + @SerializedName(value = "goods_name") + private String goodsName; + /** + *
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品单价金额,单位为分。
+     *  示例值:528800
+     * 
+ */ + @SerializedName(value = "unit_price") + private Integer unitPrice; + /** + *
+     * 字段名:商品退款金额
+     * 变量名:refund_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品退款金额,单位为分。
+     *  示例值:528800
+     * 
+ */ + @SerializedName(value = "refund_amount") + private Integer refundAmount; + /** + *
+     * 字段名:商品退货数量
+     * 变量名:refund_quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  单品的退款数量。
+     *  示例值:1
+     * 
+ */ + @SerializedName(value = "refund_quantity") + private Integer refundQuantity; + } +} + diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundV3Result.java new file mode 100644 index 0000000000..a5712f0c6d --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayRefundV3Result.java @@ -0,0 +1,474 @@ +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; + +/** + *
+ * 微信支付-申请退款返回结果.
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayRefundV3Result implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+   * 字段名:微信退款单号
+   * 变量名:refund_id
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  微信支付退款号。
+   *  示例值:50000000382019052709732678859
+   * 
+ */ + @SerializedName(value = "refund_id") + private String refundId; + /** + *
+   * 字段名:商户退款单号
+   * 变量名:out_refund_no
+   * 是否必填:是
+   * 类型:string[1, 64]
+   * 描述:
+   *  商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_refund_no") + private String outRefundNo; + /** + *
+   * 字段名:微信支付订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  微信支付交易订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + /** + *
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  原支付交易对应的商户订单号。
+   *  示例值:1217752501201407033233368018
+   * 
+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + /** + *
+   * 字段名:退款渠道
+   * 变量名:channel
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  枚举值:
+   *  ORIGINAL:原路退款
+   *  BALANCE:退回到余额
+   *  OTHER_BALANCE:原账户异常退到其他余额账户
+   *  OTHER_BANKCARD:原银行卡异常退到其他银行卡
+   *  示例值:ORIGINAL
+   * 
+ */ + @SerializedName(value = "channel") + private String channel; + /** + *
+   * 字段名:退款入账账户
+   * 变量名:user_received_account
+   * 是否必填:是
+   * 类型:string[1, 64]
+   * 描述:
+   *  取当前退款单的退款入账方,有以下几种情况:
+   *  1)退回银行卡:{银行名称}{卡类型}{卡尾号}
+   *  2)退回支付用户零钱:支付用户零钱
+   *  3)退还商户:商户基本账户商户结算银行账户
+   *  4)退回支付用户零钱通:支付用户零钱通。
+   *  示例值:招商银行信用卡0403
+   * 
+ */ + @SerializedName(value = "user_received_account") + private String userReceivedAccount; + /** + *
+   * 字段名:退款成功时间
+   * 变量名:success_time
+   * 是否必填:是
+   * 类型: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
+   * 
+ */ + @SerializedName(value = "success_time") + private String successTime; + /** + *
+   * 字段名:退款创建时间
+   * 变量名:create_time
+   * 是否必填:是
+   * 类型: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
+   * 
+ */ + @SerializedName(value = "create_time") + private String createTime; + /** + *
+   * 字段名:退款状态
+   * 变量名:status
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
+   *  枚举值:
+   *  SUCCESS:退款成功
+   *  CLOSED:退款关闭
+   *  PROCESSING:退款处理中
+   *  ABNORMAL:退款异常
+   *  示例值:SUCCESS
+   * 
+ */ + @SerializedName(value = "status") + private String status; + /** + *
+   * 字段名:资金账户
+   * 变量名:funds_account
+   * 是否必填:是
+   * 类型:string[1, 32]
+   * 描述:
+   *  退款所使用资金对应的资金账户类型。 枚举值:
+   *  UNSETTLED : 未结算资金
+   *  AVAILABLE : 可用余额
+   *  UNAVAILABLE : 不可用余额
+   *  OPERATION : 运营户
+   *  示例值:UNSETTLED
+   * 
+ */ + @SerializedName(value = "funds_account") + private String fundsAccount; + /** + *
+   * 字段名:金额信息
+   * 变量名:amount
+   * 是否必填:是
+   * 类型:object
+   * 描述:
+   *  金额详细信息。
+   * 
+ */ + @SerializedName(value = "amount") + private Amount amount; + /** + *
+   * 字段名:优惠退款信息
+   * 变量名:promotion_detail
+   * 是否必填:否
+   * 类型:array
+   * 描述:
+   *  优惠退款信息。
+   * 
+ */ + @SerializedName(value = "promotion_detail") + private List promotionDetail; + + @Data + @NoArgsConstructor + public static class Amount implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:订单金额
+     * 变量名:total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  订单总金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "total") + private Integer total; + /** + *
+     * 字段名:退款金额
+     * 变量名:refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款标价金额,单位为分,可以做部分退款。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "refund") + private Integer refund; + /** + *
+     * 字段名:用户支付金额
+     * 变量名:payer_total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  现金支付金额,单位为分,只能为整数。
+     *  示例值:90
+     * 
+ */ + @SerializedName(value = "payer_total") + private Integer payerTotal; + /** + *
+     * 字段名:用户退款金额
+     * 变量名:payer_refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  退款给用户的金额,不包含所有优惠券金额。
+     *  示例值:90
+     * 
+ */ + @SerializedName(value = "payer_refund") + private Integer payerRefund; + /** + *
+     * 字段名:应结退款金额
+     * 变量名:settlement_refund
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "settlement_refund") + private Integer settlementRefund; + /** + *
+     * 字段名:用户退款金额
+     * 变量名:settlement_total
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "settlement_total") + private Integer settlementTotal; + /** + *
+     * 字段名:优惠退款金额
+     * 变量名:discount_refund
+     * 是否必填:否
+     * 类型:int64
+     * 描述:
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分。
+     *  示例值:10
+     * 
+ */ + @SerializedName(value = "discount_refund") + private Integer discountRefund; + /** + *
+     * 字段名:币类型
+     * 变量名:currency
+     * 是否必填:否
+     * 类型:string[1, 16]
+     * 描述:
+     *  符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
+     *  示例值:CNY
+     * 
+ */ + @SerializedName(value = "currency") + private String currency; + } + + @Data + @NoArgsConstructor + public static class PromotionDetail implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+     * 字段名:券ID
+     * 变量名:promotion_id
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  券或者立减优惠id。
+     *  示例值:109519
+     * 
+ */ + @SerializedName(value = "promotion_id") + private String promotionId; + /** + *
+     * 字段名:优惠范围
+     * 变量名:scope
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  枚举值:
+     *  GLOBAL:全场代金券
+     *  SINGLE:单品优惠
+     *  示例值:SINGLE
+     * 
+ */ + @SerializedName(value = "scope") + private String scope; + /** + *
+     * 字段名:优惠类型
+     * 变量名:type
+     * 是否必填:是
+     * 类型:string[1, 32]
+     * 描述:
+     *  枚举值:
+     *  COUPON:代金券,需要走结算资金的充值型代金券
+     *  DISCOUNT:优惠券,不走结算资金的免充值型优惠券
+     *  示例值:DISCOUNT
+     * 
+ */ + @SerializedName(value = "type") + private String type; + /** + *
+     * 字段名:优惠券面额
+     * 变量名:amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额 ),单位为分。
+     *  示例值:5
+     * 
+ */ + @SerializedName(value = "amount") + private Integer amount; + /** + *
+     * 字段名:优惠退款金额
+     * 变量名:refund_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为用户支付的现金,说明详见代金券或立减优惠,单位为分。
+     *  示例值:100
+     * 
+ */ + @SerializedName(value = "refund_amount") + private Integer refundAmount; + /** + *
+     * 字段名:商品列表
+     * 变量名:goods_detail
+     * 是否必填:否
+     * 类型:array
+     * 描述:
+     *  优惠商品发生退款时返回商品信息。
+     * 
+ */ + @SerializedName(value = "goods_detail") + private List goodsDetails; + } + + @Data + @NoArgsConstructor + public static class GoodsDetail implements Serializable { + private static final long serialVersionUID = -1L; + /** + *
+     * 字段名:商户侧商品编码
+     * 变量名:merchant_goods_id
+     * 是否必填:是
+     * 类型:string[1,32]
+     * 描述:
+     *  由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
+     *  示例值:1217752501201407033233368018
+     * 
+ */ + @SerializedName(value = "merchant_goods_id") + private String merchantGoodsId; + /** + *
+     * 字段名:微信侧商品编码
+     * 变量名:wechatpay_goods_id
+     * 是否必填:否
+     * 类型:string[1,32]
+     * 描述:
+     *  微信支付定义的统一商品编号(没有可不传)。
+     *  示例值:1001
+     * 
+ */ + @SerializedName(value = "wechatpay_goods_id") + private String wechatpayGoodsId; + /** + *
+     * 字段名:商品名称
+     * 变量名:goods_name
+     * 是否必填:否
+     * 类型:string[1,256]
+     * 描述:
+     *  商品的实际名称。
+     *  示例值:iPhone6s 16G
+     * 
+ */ + @SerializedName(value = "goods_name") + private String goodsName; + /** + *
+     * 字段名:商品单价
+     * 变量名:unit_price
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品单价金额,单位为分。
+     *  示例值:528800
+     * 
+ */ + @SerializedName(value = "unit_price") + private Integer unitPrice; + /** + *
+     * 字段名:商品退款金额
+     * 变量名:refund_amount
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  商品退款金额,单位为分。
+     *  示例值:528800
+     * 
+ */ + @SerializedName(value = "refund_amount") + private Integer refundAmount; + /** + *
+     * 字段名:商品退货数量
+     * 变量名:refund_quantity
+     * 是否必填:是
+     * 类型:int
+     * 描述:
+     *  单品的退款数量。
+     *  示例值:1
+     * 
+ */ + @SerializedName(value = "refund_quantity") + private Integer refundQuantity; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderV3Result.java new file mode 100644 index 0000000000..58e74196f6 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderV3Result.java @@ -0,0 +1,124 @@ +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; + +/** + *
+ * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"返回的结果
+ * 参考文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml
+ * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
+ * 
+ * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class WxPayUnifiedOrderV3Result implements Serializable { + private static final long serialVersionUID = 1L; + /** + *
+   * 字段名:预支付交易会话标识(APP支付、JSAPI支付 会返回)
+   * 变量名:prepay_id
+   * 是否必填:是
+   * 类型:string[1,64]
+   * 描述:
+   *  预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时
+   *  示例值:wx201410272009395522657a690389285100
+   * 
+ */ + @SerializedName("prepay_id") + private String prepayId; + + /** + *
+   * 字段名:支付跳转链接(H5支付 会返回)
+   * 变量名:h5_url
+   * 是否必填:是
+   * 类型:string[1,512]
+   * 描述:
+   *  h5_url为拉起微信支付收银台的中间页面,可通过访问该url来拉起微信客户端,完成支付,h5_url的有效期为5分钟。
+   *  示例值:https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458241
+   * 
+ */ + @SerializedName("h5_url") + private String h5Url; + + /** + *
+   * 字段名:二维码链接(NATIVE支付 会返回)
+   * 变量名:h5_url
+   * 是否必填:是
+   * 类型:string[1,512]
+   * 描述:
+   *  此URL用于生成支付二维码,然后提供给用户扫码支付。
+   *  注意:code_url并非固定值,使用时按照URL格式转成二维码即可。
+   *  示例值:weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00
+   * 
+ */ + @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 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; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/TradeTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/TradeTypeEnum.java new file mode 100644 index 0000000000..44720d4be5 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/TradeTypeEnum.java @@ -0,0 +1,33 @@ +package com.github.binarywang.wxpay.bean.result.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付方式 + */ +@Getter +@AllArgsConstructor +public enum TradeTypeEnum { + /** + * APP + */ + APP("/v3/pay/transactions/app"), + /** + * JSAPI 或 小程序 + */ + JSAPI("/v3/pay/transactions/jsapi"), + /** + * NATIVE + */ + NATIVE("/v3/pay/transactions/native"), + /** + * H5 + */ + H5("/v3/pay/transactions/h5"); + + /** + * 单独下单url + */ + private final String partnerUrl; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BasePayV3Service.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BasePayV3Service.java new file mode 100644 index 0000000000..dbab9cc288 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/BasePayV3Service.java @@ -0,0 +1,24 @@ +package com.github.binarywang.wxpay.service; + +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.exception.WxPayException; + +/** + *
+ *  微信基础支付v3相关服务类.
+ * 
+ * + * @author thinsstar + */ +public interface BasePayV3Service { + + /** + * 调用统一下单接口,并组装生成支付所需参数对象. + * + * @param 请使用{@link com.github.binarywang.wxpay.bean.order}包下的类 + * @param request 统一下单请求参数 + * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象 + * @throws WxPayException the wx pay exception + */ + T createOrder(WxPayUnifiedOrderV3Request request) throws WxPayException; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 3f5f5973ab..563cf1c529 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -2,11 +2,10 @@ import com.github.binarywang.wxpay.bean.WxPayApiData; import com.github.binarywang.wxpay.bean.coupon.*; -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult; +import com.github.binarywang.wxpay.bean.notify.*; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; @@ -291,6 +290,53 @@ public interface WxPayService { */ WxPayOrderQueryResult queryOrder(WxPayOrderQueryRequest request) throws WxPayException; + /** + *
+   * 查询订单
+   * 详见 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
+   * 商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。查询订单状态可通过微信支付订单号或商户订单号两种方式查询
+   * 注意:
+   *  查询订单可通过微信支付订单号和商户订单号两种方式查询,两种查询方式返回结果相同
+   * 需要调用查询接口的情况:
+   * ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知。
+   * ◆ 调用支付接口后,返回系统错误或未知交易状态情况。
+   * ◆ 调用付款码支付API,返回USERPAYING的状态。
+   * ◆ 调用关单或撤销接口API之前,需确认支付状态。
+   * 接口地址:
+   *  https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}
+   *  https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
+   * 
+ * + * @param transactionId 微信订单号 + * @param outTradeNo 商户系统内部的订单号,当没提供transactionId时需要传这个。 + * @return the wx pay order query result + * @throws WxPayException the wx pay exception + */ + WxPayOrderQueryV3Result queryOrderV3(String transactionId, String outTradeNo) throws WxPayException; + + /** + *
+   * 查询订单
+   * 详见 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
+   * 商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。查询订单状态可通过微信支付订单号或商户订单号两种方式查询
+   * 注意:
+   *  查询订单可通过微信支付订单号和商户订单号两种方式查询,两种查询方式返回结果相同
+   * 需要调用查询接口的情况:
+   * ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知。
+   * ◆ 调用支付接口后,返回系统错误或未知交易状态情况。
+   * ◆ 调用付款码支付API,返回USERPAYING的状态。
+   * ◆ 调用关单或撤销接口API之前,需确认支付状态。
+   * 接口地址:
+   *  https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}
+   *  https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
+   * 
+ * + * @param request 查询订单请求对象 + * @return the wx pay order query result + * @throws WxPayException the wx pay exception + */ + WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) throws WxPayException; + /** *
    * 关闭订单.
@@ -327,6 +373,40 @@ public interface WxPayService {
    */
   WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws WxPayException;
 
+  /**
+   * 
+   * 关闭订单
+   * 应用场景
+   * 以下情况需要调用关单接口:
+   * 1、商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
+   * 2、系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
+   * 注意:关单没有时间限制,建议在订单生成后间隔几分钟(最短5分钟)再调用关单接口,避免出现订单状态同步不及时导致关单失败。
+   * 接口地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
+   * 
+ * + * @param outTradeNo 商户系统内部的订单号 + * @return the wx pay order close result + * @throws WxPayException the wx pay exception + */ + void closeOrderV3(String outTradeNo) throws WxPayException; + + /** + *
+   * 关闭订单
+   * 应用场景
+   * 以下情况需要调用关单接口:
+   * 1、商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
+   * 2、系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
+   * 注意:关单没有时间限制,建议在订单生成后间隔几分钟(最短5分钟)再调用关单接口,避免出现订单状态同步不及时导致关单失败。
+   * 接口地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
+   * 
+ * + * @param request 关闭订单请求对象 + * @return the wx pay order close result + * @throws WxPayException the wx pay exception + */ + void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException; + /** * 调用统一下单接口,并组装生成支付所需参数对象. * @@ -360,6 +440,25 @@ public interface WxPayService { */ WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException; + /** + * 调用统一下单接口,并组装生成支付所需参数对象. + * + * @param 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 + * @param request 统一下单请求参数 + * @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段 + * @throws WxPayException the wx pay exception + */ + T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; + + /** + * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) + * @return the wx pay unified order result + * @throws WxPayException the wx pay exception + */ + WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; + /** * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数. * 详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 @@ -426,6 +525,33 @@ public interface WxPayService { */ WxPayRefundResult refundV2(WxPayRefundRequest request) throws WxPayException; + /** + *
+   * 申请退款API(支持单品).
+   * 详见 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
+   *
+   * 应用场景
+   * 当交易发生之后一年内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付金额退还给买家,微信支付将在收到退款请求并且验证成功之后,将支付款按原路退还至买家账号上。
+   *
+   * 注意:
+   * 1、交易时间超过一年的订单无法提交退款
+   * 2、微信支付退款支持单笔交易分多次退款(不超50次),多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
+   * 3、错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
+   * 4、每个支付订单的部分退款次数不能超过50次
+   * 5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败
+   * 6、申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果
+   * 7、一个月之前的订单申请退款频率限制为:5000/min
+   *
+   * 接口地址
+   * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds
+   * 
+ * + * @param request 请求对象 + * @return 退款操作结果 wx pay refund result + * @throws WxPayException the wx pay exception + */ + WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException; + /** *
    * 微信支付-查询退款.
@@ -486,6 +612,36 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    */
   WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) throws WxPayException;
 
+  /**
+   * 
+   * 微信支付-查询退款
+   * 应用场景:
+   *  提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,建议在提交退款申请后1分钟发起查询退款状态,一般来说零钱支付的退款5分钟内到账,银行卡支付的退款1-3个工作日到账。
+   *  详见 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_10.shtml
+   * 接口链接:https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}
+   * 
+ * + * @param outTradeNo 商户订单号 + * @return 退款信息 wx pay refund query result + * @throws WxPayException the wx pay exception + */ + WxPayRefundQueryV3Result refundQueryV3(String outTradeNo) throws WxPayException; + + /** + *
+   * 微信支付-查询退款
+   * 应用场景:
+   *  提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,建议在提交退款申请后1分钟发起查询退款状态,一般来说零钱支付的退款5分钟内到账,银行卡支付的退款1-3个工作日到账。
+   *  详见 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_10.shtml
+   * 接口链接:https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}
+   * 
+ * + * @param request 微信退款单号 + * @return 退款信息 wx pay refund query result + * @throws WxPayException the wx pay exception + */ + WxPayRefundQueryV3Result refundQueryV3(WxPayRefundQueryV3Request request) throws WxPayException; + /** * 解析支付结果通知. * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 @@ -507,6 +663,17 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri */ WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData, String signType) throws WxPayException; + /** + * 解析支付结果v3通知. + * 详见https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml + * + * @param notifyData 通知数据 + * @param header 通知头部数据,不传则表示不校验头 + * @return the wx pay order notify result + * @throws WxPayException the wx pay exception + */ + WxPayOrderNotifyV3Result parseOrderNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException; + /** * 解析退款结果通知 * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=9 @@ -517,6 +684,17 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri */ WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException; + /** + * 解析退款结果通知 + * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=9 + * + * @param notifyData 通知数据 + * @param header 通知头部数据,不传则表示不校验头 + * @return the wx pay refund notify result + * @throws WxPayException the wx pay exception + */ + WxPayRefundNotifyV3Result parseRefundNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException; + /** * 解析扫码支付回调通知 * 详见https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java index d5b066036a..a369369f19 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java @@ -3,15 +3,14 @@ import com.github.binarywang.utils.qrcode.QrcodeUtils; import com.github.binarywang.wxpay.bean.WxPayApiData; import com.github.binarywang.wxpay.bean.coupon.*; -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult; +import com.github.binarywang.wxpay.bean.notify.*; import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfigHolder; import com.github.binarywang.wxpay.constant.WxPayConstants; @@ -21,9 +20,12 @@ import com.github.binarywang.wxpay.service.*; import com.github.binarywang.wxpay.util.SignUtils; import com.github.binarywang.wxpay.util.XmlConfig; +import com.github.binarywang.wxpay.v3.util.AesUtils; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import jodd.io.ZipUtil; import me.chanjar.weixin.common.error.WxRuntimeException; import org.apache.commons.lang3.StringUtils; @@ -31,10 +33,12 @@ import org.slf4j.LoggerFactory; import java.io.File; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.GeneralSecurityException; import java.util.*; import java.util.zip.ZipException; @@ -52,6 +56,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { private static final String TOTAL_FUND_COUNT = "资金流水总笔数"; + private static final Gson GSON = new GsonBuilder().create(); final Logger log = LoggerFactory.getLogger(this.getClass()); @@ -242,6 +247,13 @@ public WxPayRefundResult refundV2(WxPayRefundRequest request) throws WxPayExcept return result; } + @Override + public WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException { + String url = String.format("%s/v3/refund/domestic/refunds", this.getPayBaseUrl()); + String response = this.postV3(url, GSON.toJson(request)); + return GSON.fromJson(response, WxPayRefundV3Result.class); + } + @Override public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxPayException { @@ -278,6 +290,20 @@ public WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) thr return result; } + @Override + public WxPayRefundQueryV3Result refundQueryV3(String outTradeNo) throws WxPayException { + String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), outTradeNo); + String response = this.getV3(url); + return GSON.fromJson(response, WxPayRefundQueryV3Result.class); + } + + @Override + public WxPayRefundQueryV3Result refundQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { + String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), request.getOutTradeNo()); + String response = this.getV3(url); + return GSON.fromJson(response, WxPayRefundQueryV3Result.class); + } + @Override public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException { return this.parseOrderNotifyResult(xmlData, null); @@ -308,6 +334,44 @@ public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData, String sign } } + /** + * 校验通知签名 + * @param header 通知头信息 + * @param data 通知数据 + * @return true:校验通过 false:校验不通过 + */ + private boolean verifyNotifySign(SignatureHeader header, String data) { + String beforeSign = String.format("%s\n%s\n%s\n", + header.getTimeStamp(), + header.getNonce(), + data); + return this.getConfig().getVerifier().verify(header.getSerial(), + beforeSign.getBytes(StandardCharsets.UTF_8), header.getSignature()); + } + + @Override + public WxPayOrderNotifyV3Result parseOrderNotifyV3Result(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); + WxPayOrderNotifyV3Result.DecryptNotifyResult decryptNotifyResult = GSON.fromJson(result, WxPayOrderNotifyV3Result.DecryptNotifyResult.class); + WxPayOrderNotifyV3Result notifyResult = new WxPayOrderNotifyV3Result(); + 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 { @@ -326,6 +390,29 @@ public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws Wx } } + @Override + public WxPayRefundNotifyV3Result parseRefundNotifyV3Result(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); + WxPayRefundNotifyV3Result.DecryptNotifyResult decryptNotifyResult = GSON.fromJson(result, WxPayRefundNotifyV3Result.DecryptNotifyResult.class); + WxPayRefundNotifyV3Result notifyResult = new WxPayRefundNotifyV3Result(); + notifyResult.setRawData(response); + notifyResult.setResult(decryptNotifyResult); + return notifyResult; + } catch (GeneralSecurityException | IOException e) { + throw new WxPayException("解析报文异常!", e); + } + } + @Override public WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData, String signType) throws WxPayException { try { @@ -372,6 +459,28 @@ public WxPayOrderQueryResult queryOrder(WxPayOrderQueryRequest request) throws W return result; } + @Override + public WxPayOrderQueryV3Result queryOrderV3(String transactionId, String outTradeNo) throws WxPayException { + WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request(); + request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); + request.setTransactionId(StringUtils.trimToNull(transactionId)); + return this.queryOrderV3(request); + } + + @Override + public WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) throws WxPayException { + if (StringUtils.isBlank(request.getMchid())) { + request.setMchid(this.getConfig().getMchId()); + } + String url = String.format("%s/v3/pay/transactions/out-trade-no/%s", this.getPayBaseUrl(), request.getOutTradeNo()); + if (Objects.isNull(request.getOutTradeNo())) { + url = String.format("%s/v3/pay/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId()); + } + String query = String.format("?mchid=%s", request.getMchid()); + String response = this.getV3(url + query); + return GSON.fromJson(response, WxPayOrderQueryV3Result.class); + } + @Override public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { @@ -396,6 +505,25 @@ public WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws W return result; } + @Override + public void closeOrderV3(String outTradeNo) throws WxPayException { + if (StringUtils.isBlank(outTradeNo)) { + throw new WxPayException("out_trade_no不能为空"); + } + WxPayOrderCloseV3Request request = new WxPayOrderCloseV3Request(); + request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); + this.closeOrderV3(request); + } + + @Override + public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException { + if (StringUtils.isBlank(request.getMchid())) { + request.setMchid(this.getConfig().getMchId()); + } + String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo()); + this.postV3(url, GSON.toJson(request)); + } + @Override public T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException { WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); @@ -500,6 +628,25 @@ public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) th return result; } + @Override + public T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException { + WxPayUnifiedOrderV3Result result = this.unifiedOrderV3(tradeType, request); + return result.getPayInfo(tradeType, request.getAppid(), request.getMchid(), this.getConfig().getPrivateKey()); + } + + @Override + public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException { + if (StringUtils.isBlank(request.getAppid())) { + request.setAppid(this.getConfig().getAppId()); + } + if (StringUtils.isBlank(request.getMchid())) { + request.setMchid(this.getConfig().getMchId()); + } + String url = this.getPayBaseUrl() + tradeType.getPartnerUrl(); + String response = this.postV3(url, GSON.toJson(request)); + return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class); + } + @Override @Deprecated public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException { diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java index 779916162c..e984b334fc 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java @@ -9,6 +9,7 @@ import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; import com.github.binarywang.wxpay.constant.WxPayConstants.AccountType; import com.github.binarywang.wxpay.constant.WxPayConstants.BillType; import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; @@ -18,8 +19,11 @@ import com.github.binarywang.wxpay.testbase.ApiTestModule; import com.github.binarywang.wxpay.testbase.XmlWxPayConfig; import com.github.binarywang.wxpay.util.XmlConfig; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.inject.Inject; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.util.RandomUtils; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -704,4 +708,71 @@ public void testQueryExchangeRate() throws WxPayException { System.out.println(result); } + private static final Gson GSON = new GsonBuilder().create(); + + @Test + public void testUnifiedOrderV3() throws WxPayException { + String outTradeNo = RandomUtils.getRandomStr(); + String notifyUrl = "https://api.qq.com/"; + System.out.println("outTradeNo = " + outTradeNo); + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); + request.setOutTradeNo(outTradeNo); + request.setNotifyUrl(notifyUrl); + request.setDescription("test"); + + WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer(); + payer.setOpenid("openid"); + request.setPayer(payer); + + //构建金额信息 + WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount(); + //设置币种信息 + amount.setCurrency("CNY"); + //设置金额 + amount.setTotal(1); + request.setAmount(amount); + + WxPayUnifiedOrderV3Result.JsapiResult result = this.payService.createOrderV3(TradeTypeEnum.JSAPI, request); + + System.out.println(GSON.toJson(result)); + } + + @Test + public void testQueryOrderV3() throws WxPayException { + WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request(); + request.setOutTradeNo("n1ZvYqjAg3D3LUBa"); + WxPayOrderQueryV3Result result = this.payService.queryOrderV3(request); + System.out.println(GSON.toJson(result)); + } + + @Test + public void testCloseOrderV3() throws WxPayException { + WxPayOrderCloseV3Request request = new WxPayOrderCloseV3Request(); + request.setOutTradeNo("n1ZvYqjAg3D3LUBa"); + this.payService.closeOrderV3(request); + } + + @Test + public void testRefundV3() throws WxPayException { + String outRefundNo = RandomUtils.getRandomStr(); + String notifyUrl = "https://api.qq.com/"; + System.out.println("outRefundNo = " + outRefundNo); + WxPayRefundV3Request request = new WxPayRefundV3Request(); + request.setOutTradeNo("n1ZvYqjAg3D3LUBa"); + request.setOutRefundNo(outRefundNo); + request.setNotifyUrl(notifyUrl); + request.setAmount(new WxPayRefundV3Request.Amount().setRefund(100).setTotal(100).setCurrency("CNY")); + WxPayRefundV3Result result = this.payService.refundV3(request); + System.out.println(GSON.toJson(result)); + } + + @Test + public void testRefundQueryV3() throws WxPayException { + WxPayRefundQueryV3Request request = new WxPayRefundQueryV3Request(); +// request.setOutTradeNo("n1ZvYqjAg3D7LUBa"); + request.setOutTradeNo("123456789011"); + WxPayRefundQueryV3Result result = this.payService.refundQueryV3(request); + System.out.println(GSON.toJson(result)); + } + }