🆕 #2130 【微信支付】增加微信支付部分v3接口

This commit is contained in:
thinsstar 2021-05-21 22:07:02 +08:00 committed by GitHub
parent fa5d892176
commit efb2c52011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 3959 additions and 6 deletions

View File

@ -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;
/**
* <pre>
* 字段名通知ID
* 变量名id
* 是否必填
* 类型string[1,36]
* 描述
* 通知的唯一ID
* 示例值EV-2018022511223320873
* </pre>
*/
@SerializedName(value = "id")
private String id;
/**
* <pre>
* 字段名通知创建时间
* 变量名create_time
* 是否必填
* 类型string[1,32]
* 描述
* 通知创建的时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-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
* </pre>
*/
@SerializedName(value = "create_time")
private String createTime;
/**
* <pre>
* 字段名通知类型
* 变量名event_type
* 是否必填
* 类型string[1,32]
* 描述
* 通知的类型
* REFUND.SUCCESS退款成功通知
* REFUND.ABNORMAL退款异常通知
* REFUND.CLOSED退款关闭通知
* 示例值REFUND.SUCCESS
* </pre>
*/
@SerializedName(value = "event_type")
private String eventType;
/**
* <pre>
* 字段名通知简要说明
* 变量名summary
* 是否必填
* 类型string[1,16]
* 描述
* 通知简要说明
* 示例值退款成功
* </pre>
*/
@SerializedName(value = "summary")
private String summary;
/**
* <pre>
* 字段名通知数据类型
* 变量名resource_type
* 是否必填
* 类型string[1,32]
* 描述
* 通知的资源数据类型支付成功通知为encrypt-resource
* 示例值encrypt-resource
* </pre>
*/
@SerializedName(value = "resource_type")
private String resourceType;
/**
* <pre>
* 字段名通知数据
* 变量名resource
* 是否必填
* 类型object
* 描述
* 通知资源数据
* json格式见示例
* </pre>
*/
@SerializedName(value = "resource")
private Resource resource;
@Data
@NoArgsConstructor
public static class Resource implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名加密算法类型
* 变量名algorithm
* 是否必填
* 类型string[1,32]
* 描述
* 对开启结果数据进行加密的加密算法目前只支持AEAD_AES_256_GCM
* 示例值AEAD_AES_256_GCM
* </pre>
*/
@SerializedName(value = "algorithm")
private String algorithm;
/**
* <pre>
* 字段名原始类型
* 变量名original_type
* 是否必填
* 类型string[1,16]
* 描述
* 原始回调类型为transaction
* 示例值transaction
* </pre>
*/
@SerializedName(value = "original_type")
private String originalType;
/**
* <pre>
* 字段名数据密文
* 变量名ciphertext
* 是否必填
* 类型string[1,1048576]
* 描述
* Base64编码后的开启/停用结果数据密文
* 示例值sadsadsadsad
* </pre>
*/
@SerializedName(value = "ciphertext")
private String ciphertext;
/**
* <pre>
* 字段名附加数据
* 变量名associated_data
* 是否必填
* 类型string[1,16]
* 描述
* 附加数据
* 示例值fdasfwqewlkja484w
* </pre>
*/
@SerializedName(value = "associated_data")
private String associatedData;
/**
* <pre>
* 字段名随机串
* 变量名nonce
* 是否必填
* 类型string[1,16]
* 描述
* 加密使用的随机串
* 示例值fdasflkja484w
* </pre>
*/
@SerializedName(value = "nonce")
private String nonce;
}
}

View File

@ -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;
}

View File

@ -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;
/**
* <pre>
* 字段名应用ID
* 变量名appid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户申请的公众号或移动应用appid
* 示例值wxd678efh567hg6787
* </pre>
*/
@SerializedName(value = "appid")
private String appid;
/**
* <pre>
* 字段名商户号
* 变量名mchid
* 是否必填
* 类型string[1,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
* 特殊规则最小字符长度为6
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "mchid")
private String mchid;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[6,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
* 特殊规则最小字符长度为6
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付系统生成的订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名交易类型
* 变量名trade_type
* 是否必填
* 类型string[1,16]
* 描述
* 交易类型枚举值
* JSAPI公众号支付
* NATIVE扫码支付
* APPAPP支付
* MICROPAY付款码支付
* MWEBH5支付
* FACEPAY刷脸支付
* 示例值MICROPAY
* </pre>
*/
@SerializedName(value = "trade_type")
private String tradeType;
/**
* <pre>
* 字段名交易状态
* 变量名trade_state
* 是否必填
* 类型string[1,32]
* 描述
* 交易状态枚举值
* SUCCESS支付成功
* REFUND转入退款
* NOTPAY未支付
* CLOSED已关闭
* REVOKED已撤销付款码支付
* USERPAYING用户支付中付款码支付
* PAYERROR支付失败(其他原因如银行返回失败)
* 示例值SUCCESS
* </pre>
*/
@SerializedName(value = "trade_state")
private String tradeState;
/**
* <pre>
* 字段名交易状态描述
* 变量名trade_state_desc
* 是否必填
* 类型string[1,256]
* 描述
* 交易状态描述
* 示例值支付成功
* </pre>
*/
@SerializedName(value = "trade_state_desc")
private String tradeStateDesc;
/**
* <pre>
* 字段名付款银行
* 变量名bank_type
* 是否必填
* 类型string[1,16]
* 描述
* 银行类型采用字符串类型的银行标识银行标识请参考银行类型对照表https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6
* 示例值CMC
* </pre>
*/
@SerializedName(value = "bank_type")
private String bankType;
/**
* <pre>
* 字段名附加数据
* 变量名attach
* 是否必填
* 类型string[1,128]
* 描述
* 附加数据在查询API和支付通知中原样返回可作为自定义参数使用
* 示例值自定义数据
* </pre>
*/
@SerializedName(value = "attach")
private String attach;
/**
* <pre>
* 字段名支付完成时间
* 变量名success_time
* 是否必填
* 类型string[1,64]
* 描述
* 支付完成时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-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
* </pre>
*/
@SerializedName(value = "success_time")
private String successTime;
/**
* <pre>
* 字段名支付者
* 变量名payer
* 是否必填
* 类型object
* 描述
* 支付者信息
* </pre>
*/
private Payer payer;
/**
* <pre>
* 字段名订单金额
* 变量名amount
* 是否必填
* 类型object
* 描述
* 订单金额信息
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名场景信息
* 变量名scene_info
* 是否必填
* 类型object
* 描述
* 支付场景信息描述
* </pre>
*/
@SerializedName(value = "scene_info")
private SceneInfo sceneInfo;
/**
* <pre>
* 字段名优惠功能
* 变量名promotion_detail
* 是否必填
* 类型array
* 描述
* 优惠功能享受优惠时返回该字段
* </pre>
*/
@SerializedName(value = "promotion_detail")
private List<PromotionDetail> promotionDetails;
}
@Data
@NoArgsConstructor
public static class Payer implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名用户标识
* 变量名openid
* 是否必填
* 类型string[1,128]
* 描述
* 用户在直连商户appid下的唯一标识
* 示例值oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* </pre>
*/
@SerializedName(value = "openid")
private String openid;
}
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名总金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 订单总金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名用户支付金额
* 变量名payer_total
* 是否必填
* 类型int
* 描述
* 用户支付金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "payer_total")
private Integer payerTotal;
/**
* <pre>
* 字段名货币类型
* 变量名currency
* 是否必填
* 类型string[1,16]
* 描述
* CNY人民币境内商户号仅支持人民币
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
/**
* <pre>
* 字段名用户支付币种
* 变量名payer_currency
* 是否必填
* 类型string[1,16]
* 描述
* 用户支付币种
* 示例值 CNY
* </pre>
*/
@SerializedName(value = "payer_currency")
private String payerCurrency;
}
@Data
@NoArgsConstructor
public static class SceneInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名商户端设备号
* 变量名device_id
* 是否必填
* 类型string[1,32]
* 描述
* 终端设备号门店号或收银设备ID
* 示例值013467007045764
* </pre>
*/
@SerializedName(value = "device_id")
private String deviceId;
}
@Data
@NoArgsConstructor
public static class PromotionDetail implements Serializable {
/**
* <pre>
* 字段名券ID
* 变量名coupon_id
* 是否必填
* 类型string[1,32]
* 描述
* 券ID
* 示例值109519
* </pre>
*/
@SerializedName(value = "coupon_id")
private String couponId;
/**
* <pre>
* 字段名优惠名称
* 变量名name
* 是否必填
* 类型string[1,64]
* 描述
* 优惠名称
* 示例值单品惠-6
* </pre>
*/
@SerializedName(value = "name")
private String name;
/**
* <pre>
* 字段名优惠范围
* 变量名scope
* 是否必填
* 类型string[1,32]
* 描述
* GLOBAL全场代金券
* SINGLE单品优惠
* 示例值GLOBAL
* </pre>
*/
@SerializedName(value = "scope")
private String scope;
/**
* <pre>
* 字段名优惠类型
* 变量名type
* 是否必填
* 类型string[1,32]
* 描述
* CASH充值
* NOCASH预充值
* 示例值CASH
* </pre>
*/
@SerializedName(value = "type")
private String type;
/**
* <pre>
* 字段名优惠券面额
* 变量名amount
* 是否必填
* 类型int
* 描述
* 优惠券面额
* 示例值100
* </pre>
*/
@SerializedName(value = "amount")
private Integer amount;
/**
* <pre>
* 字段名活动ID
* 变量名stock_id
* 是否必填
* 类型string[1,32]
* 描述
* 活动ID
* 示例值931386
* </pre>
*/
@SerializedName(value = "stock_id")
private String stockId;
/**
* <pre>
* 字段名微信出资
* 变量名wechatpay_contribute
* 是否必填
* 类型int
* 描述
* 微信出资单位为分
* 示例值0
* </pre>
*/
@SerializedName(value = "wechatpay_contribute")
private Integer wechatpayContribute;
/**
* <pre>
* 字段名商户出资
* 变量名merchant_contribute
* 是否必填
* 类型int
* 描述
* 商户出资单位为分
* 示例值0
* </pre>
*/
@SerializedName(value = "merchant_contribute")
private Integer merchantContribute;
/**
* <pre>
* 字段名其他出资
* 变量名other_contribute
* 是否必填
* 类型int
* 描述
* 其他出资单位为分
* 示例值0
* </pre>
*/
@SerializedName(value = "other_contribute")
private Integer otherContribute;
/**
* <pre>
* 字段名优惠币种
* 变量名currency
* 是否必填
* 类型string[1,16]
* 描述
* CNY人民币境内商户号仅支持人民币
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
/**
* <pre>
* 字段名单品列表
* 变量名goods_detail
* 是否必填
* 类型array
* 描述
* 单品列表信息
* </pre>
*/
@SerializedName(value = "goods_detail")
private List<GoodsDetail> goodsDetails;
}
@Data
@NoArgsConstructor
public static class GoodsDetail implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名商品编码
* 变量名goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 商品编码
* 示例值M1006
* </pre>
*/
@SerializedName(value = "goods_id")
private String goodsId;
/**
* <pre>
* 字段名商品数量
* 变量名quantity
* 是否必填
* 类型int
* 描述
* 用户购买的数量
* 示例值1
* </pre>
*/
@SerializedName(value = "quantity")
private Integer quantity;
/**
* <pre>
* 字段名商品单价
* 变量名unit_price
* 是否必填
* 类型int
* 描述
* 商品单价单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "unit_price")
private Integer unitPrice;
/**
* <pre>
* 字段名商品优惠金额
* 变量名discount_amount
* 是否必填
* 类型int
* 描述
* 商品优惠金额
* 示例值0
* </pre>
*/
@SerializedName(value = "discount_amount")
private Integer discountAmount;
/**
* <pre>
* 字段名商品备注
* 变量名goods_remark
* 是否必填
* 类型string[1,128]
* 描述
* 商品备注信息
* 示例值商品备注信息
* </pre>
*/
@SerializedName(value = "goods_remark")
private String goodsRemark;
}
}

View File

@ -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;
/**
* <pre>
* 字段名直连商户号
* 变量名mchid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户的商户号由微信支付生成并下发
* 示例值1900000100
* </pre>
*/
@SerializedName(value = "mchid")
private String mchid;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[1,32]
* 描述
* 返回的商户订单号
* 示例值 1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付订单号
* 示例值 1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名商户退款单号
* 变量名out_refund_no
* 是否必填
* 类型string[1,64]
* 描述
* 商户退款单号
* 示例值 1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_refund_no")
private String outRefundNo;
/**
* <pre>
* 字段名微信支付退款号
* 变量名refund_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信退款单号
* 示例值 1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "refund_id")
private String refundId;
/**
* <pre>
* 字段名退款状态
* 变量名refund_status
* 是否必填
* 类型string[1,16]
* 描述
* 退款状态枚举值
* SUCCESS退款成功
* CLOSE退款关闭
* ABNORMAL退款异常退款到银行发现用户的卡作废或者冻结了导致原路退款银行卡失败可前往商户平台>交易中心手动处理此笔退款
* 示例值SUCCESS
* </pre>
*/
@SerializedName(value = "refund_status")
private String refundStatus;
/**
* <pre>
* 字段名退款成功时间
* 变量名success_time
* 是否必填
* 类型string[1,64]
* 描述
* 1退款成功时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-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
* </pre>
*/
@SerializedName(value = "success_time")
private String successTime;
/**
* <pre>
* 字段名退款入账账户
* 变量名user_received_account
* 是否必填
* 类型string[1,64]
* 描述
* 取当前退款单的退款入账方
* 1退回银行卡{银行名称}{卡类型}{卡尾号}
* 2退回支付用户零钱: 支付用户零钱
* 3退还商户: 商户基本账户商户结算银行账户
* 4退回支付用户零钱通支付用户零钱通
* 示例值招商银行信用卡0403
* </pre>
*/
@SerializedName(value = "user_received_account")
private String userReceivedAccount;
/**
* <pre>
* 字段名金额信息
* 变量名amount
* 是否必填
* 类型object
* 描述
* 金额信息
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
}
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
/**
* <pre>
* 字段名订单金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 订单总金额单位为分只能为整数详见支付金额
* 示例值999
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名退款金额
* 变量名refund
* 是否必填
* 类型int
* 描述
* 退款金额币种的最小单位只能为整数不能超过原订单支付金额如果有使用券后台会按比例退
* 示例值999
* </pre>
*/
@SerializedName(value = "refund")
private String refund;
/**
* <pre>
* 字段名用户支付金额
* 变量名payer_total
* 是否必填
* 类型int
* 描述
* 用户实际支付金额单位为分只能为整数详见支付金额
* 示例值999
* </pre>
*/
@SerializedName(value = "payer_total")
private Integer payerTotal;
/**
* <pre>
* 字段名用户退款金额
* 变量名payer_refund
* 是否必填
* 类型int
* 描述
* 退款给用户的金额不包含所有优惠券金额
* 示例值999
* </pre>
*/
@SerializedName(value = "payer_refund")
private String payerRefund;
}
}

View File

@ -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;
/**
* <pre>
* 关闭订单请求对象类
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class WxPayOrderCloseV3Request implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名直连商户号
* 变量名mchid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户的商户号由微信支付生成并下发
* 示例值1230000109
* </pre>
*/
@SerializedName(value = "mchid")
private String mchid;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[6,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
* 示例值1217752501201407033233368018
* </pre>
*/
private transient String outTradeNo;
}

View File

@ -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;
/**
* <pre>
* 订单查询请求对象
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class WxPayOrderQueryV3Request implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名直连商户号
* 变量名mchid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户的商户号由微信支付生成并下发
* 示例值1230000109
* </pre>
*/
@SerializedName(value = "mchid")
private String mchid;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付系统生成的订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[1,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
* 特殊规则最小字符长度为6
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
}

View File

@ -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;
/**
* <pre>
* 微信支付-查询单笔退款API
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
public class WxPayRefundQueryV3Request implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[1,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
* 特殊规则最小字符长度为6
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
}

View File

@ -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;
/**
* <pre>
* 微信支付-申请退款请求参数
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class WxPayRefundV3Request implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填与out_order_no二选一
* 类型string[1, 32]
* 描述
* 原支付交易对应的微信订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填与transaction_id二选一
* 类型string[1, 32]
* 描述
* 原支付交易对应的商户订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名商户退款单号
* 变量名out_refund_no
* 是否必填
* 类型string[1, 64]
* 描述
* 商户系统内部的退款单号商户系统内部唯一只能是数字大小写字母_-|*@ 同一退款单号多次请求只退一笔
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_refund_no")
private String outRefundNo;
/**
* <pre>
* 字段名退款原因
* 变量名reason
* 是否必填
* 类型string[1, 80]
* 描述
* 若商户传入会在下发给用户的退款消息中体现退款原因
* 示例值商品已售完
* </pre>
*/
@SerializedName(value = "reason")
private String reason;
/**
* <pre>
* 字段名退款结果回调url
* 变量名notify_url
* 是否必填
* 类型string[8, 256]
* 描述
* 异步接收微信支付退款结果通知的回调地址通知url必须为外网可访问的url不能携带参数 如果参数中传了notify_url则商户平台上配置的回调地址将不会生效优先回调当前传的这个地址
* 示例值https://weixin.qq.com
* </pre>
*/
@SerializedName(value = "notify_url")
private String notifyUrl;
/**
* <pre>
* 字段名订单金额
* 变量名amount
* 是否必填
* 类型object
* 描述
* 订单金额信息
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名退款商品
* 变量名goods_detail
* 是否必填
* 类型array
* 描述
* 指定商品退款需要传此参数其他场景无需传递
* </pre>
*/
@SerializedName(value = "goods_detail")
private List<GoodsDetail> goodsDetails;
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名退款金额
* 变量名refund
* 是否必填
* 类型int
* 描述
* 退款金额币种的最小单位只能为整数不能超过原订单支付金额
* 示例值888
* </pre>
*/
@SerializedName(value = "refund")
private Integer refund;
/**
* <pre>
* 字段名原订单金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 原支付交易的订单总金额币种的最小单位只能为整数
* 示例值888
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名币类型
* 变量名currency
* 是否必填
* 类型string[1, 16]
* 描述
* 符合ISO 4217标准的三位字母代码目前只支持人民币CNY
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
}
@Data
@NoArgsConstructor
public static class GoodsDetail implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名商户侧商品编码
* 变量名merchant_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 由半角的大小写字母数字中划线下划线中的一种或几种组成
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "merchant_goods_id")
private String merchantGoodsId;
/**
* <pre>
* 字段名微信侧商品编码
* 变量名wechatpay_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付定义的统一商品编号没有可不传
* 示例值1001
* </pre>
*/
@SerializedName(value = "wechatpay_goods_id")
private String wechatpayGoodsId;
/**
* <pre>
* 字段名商品名称
* 变量名goods_name
* 是否必填
* 类型string[1,256]
* 描述
* 商品的实际名称
* 示例值iPhone6s 16G
* </pre>
*/
@SerializedName(value = "goods_name")
private String goodsName;
/**
* <pre>
* 字段名商品单价
* 变量名unit_price
* 是否必填
* 类型int
* 描述
* 商品单价金额单位为分
* 示例值528800
* </pre>
*/
@SerializedName(value = "unit_price")
private Integer unitPrice;
/**
* <pre>
* 字段名商品退款金额
* 变量名refund_amount
* 是否必填
* 类型int
* 描述
* 商品退款金额单位为分
* 示例值528800
* </pre>
*/
@SerializedName(value = "refund_amount")
private Integer refundAmount;
/**
* <pre>
* 字段名商品退货数量
* 变量名refund_quantity
* 是否必填
* 类型int
* 描述
* 单品的退款数量
* 示例值1
* </pre>
*/
@SerializedName(value = "refund_quantity")
private Integer refundQuantity;
}
}

View File

@ -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;
/**
* <pre>
* 统一下单请求参数对象.
* 参考文档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
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class WxPayUnifiedOrderV3Request implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名应用ID
* 变量名appid
* 是否必填
* 类型string[1,32]
* 描述
* 由微信生成的应用ID全局唯一请求统一下单接口时请注意APPID的应用属性例如公众号场景下需使用应用属性为公众号的APPID
* 示例值wxd678efh567hg6787
* </pre>
*/
@SerializedName(value = "appid")
protected String appid;
/**
* <pre>
* 字段名直连商户号
* 变量名mchid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户的商户号由微信支付生成并下发
* 示例值1230000109
* </pre>
*/
@SerializedName(value = "mchid")
protected String mchid;
/**
* <pre>
* 字段名商品描述
* 变量名description
* 是否必填
* 类型string[1,127]
* 描述
* 商品描述
* 示例值Image形象店-深圳腾大-QQ公仔
* </pre>
*/
@SerializedName(value = "description")
protected String description;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[6,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
protected String outTradeNo;
/**
* <pre>
* 字段名交易结束时间
* 变量名out_trade_no
* 是否必填
* 类型string[1,64]
* 描述
* 订单失效时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-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
* </pre>
*/
@SerializedName(value = "time_expire")
protected String timeExpire;
/**
* <pre>
* 字段名附加数据
* 变量名attach
* 是否必填
* 类型string[1,128]
* 描述
* 附加数据在查询API和支付通知中原样返回可作为自定义参数使用
* 示例值自定义数据
* </pre>
*/
@SerializedName(value = "attach")
protected String attach;
/**
* <pre>
* 字段名通知地址
* 变量名notify_url
* 是否必填
* 类型string[1,256]
* 描述
* 通知URL必须为直接可访问的URL不允许携带查询串要求必须为https地址
* 格式URL
* 示例值https://www.weixin.qq.com/wxpay/pay.php
* </pre>
*/
@SerializedName(value = "notify_url")
private String notifyUrl;
/**
* <pre>
* 字段名订单优惠标记
* 变量名goods_tag
* 是否必填
* 类型string[1,256]
* 描述
* 订单优惠标记
* 示例值WXG
* </pre>
*/
@SerializedName(value = "goods_tag")
private String goodsTag;
/**
* <pre>
* 字段名订单金额
* 变量名amount
* 是否必填
* 类型object
* 描述
* 订单金额信息
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名支付者
* 变量名payer
* 是否必填
* 类型object
* 描述
* 支付者信息
* </pre>
*/
@SerializedName(value = "payer")
private Payer payer;
/**
* <pre>
* 字段名优惠功能
* 变量名detail
* 是否必填
* 类型object
* 描述
* 优惠功能
* </pre>
*/
@SerializedName(value = "detail")
private Discount detail;
/**
* <pre>
* 字段名场景信息
* 变量名scene_info
* 是否必填
* 类型object
* 描述
* 支付场景描述
* </pre>
*/
@SerializedName(value = "scene_info")
private SceneInfo sceneInfo;
/**
* <pre>
* 字段名结算信息
* 变量名settle_info
* 是否必填
* 类型Object
* 描述结算信息
* </pre>
*/
@SerializedName(value = "settle_info")
private SettleInfo settleInfo;
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名总金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 订单总金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名币类型
* 变量名currency
* 是否必填
* 类型string[1,16]
* 描述
* CNY人民币境内商户号仅支持人民币
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
}
@Data
@NoArgsConstructor
public static class Payer implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名用户标识
* 变量名openid
* 是否必填
* 类型string[1,128]
* 描述
* 用户在直连商户appid下的唯一标识
* 示例值oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* </pre>
*/
@SerializedName(value = "openid")
private String openid;
}
@Data
@NoArgsConstructor
public static class Discount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名订单原价
* 变量名cost_price
* 是否必填
* 类型int
* 描述
* 1商户侧一张小票订单可能被分多次支付订单原价用于记录整张小票的交易金额
* 2当订单原价与支付金额不相等则不享受优惠
* 3该字段主要用于防止同一张小票分多次支付以享受多次优惠的情况正常支付订单不必上传此参数
* 示例值608800
* </pre>
*/
@SerializedName(value = "cost_price")
private Integer costPrice;
/**
* <pre>
* 字段名商品小票ID
* 变量名invoice_id
* 是否必填
* 类型string[1,32]
* 描述
* 商品小票ID
* 示例值微信123
* </pre>
*/
@SerializedName(value = "invoice_id")
private String invoiceId;
/**
* <pre>
* 字段名单品列表
* 变量名goods_detail
* 是否必填
* 类型array
* 描述
* 单品列表信息
* 条目个数限制16000
* </pre>
*/
@SerializedName(value = "goods_detail")
private List<GoodsDetail> goodsDetails;
}
@Data
@NoArgsConstructor
public static class GoodsDetail implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名商户侧商品编码
* 变量名merchant_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 由半角的大小写字母数字中划线下划线中的一种或几种组成
* 示例值商品编码
* </pre>
*/
@SerializedName(value = "merchant_goods_id")
private String merchantGoodsId;
/**
* <pre>
* 字段名微信侧商品编码
* 变量名wechatpay_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付定义的统一商品编号没有可不传
* 示例值1001
* </pre>
*/
@SerializedName(value = "wechatpay_goods_id")
private String wechatpayGoodsId;
/**
* <pre>
* 字段名商品名称
* 变量名goods_name
* 是否必填
* 类型string[1,256]
* 描述
* 商品的实际名称
* 示例值iPhoneX 256G
* </pre>
*/
@SerializedName(value = "goods_name")
private String goodsName;
/**
* <pre>
* 字段名商品数量
* 变量名quantity
* 是否必填
* 类型int
* 描述
* 用户购买的数量
* 示例值1
* </pre>
*/
@SerializedName(value = "quantity")
private Integer quantity;
/**
* <pre>
* 字段名商品单价
* 变量名unit_price
* 是否必填
* 类型int
* 描述
* 商品单价单位为分
* 示例值828800
* </pre>
*/
@SerializedName(value = "unit_price")
private Integer unitPrice;
}
@Data
@NoArgsConstructor
public static class SceneInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名用户终端IP
* 变量名payer_client_ip
* 是否必填
* 类型string[1,45]
* 描述
* 用户的客户端IP支持IPv4和IPv6两种格式的IP地址
* 示例值14.23.150.211
* </pre>
*/
@SerializedName(value = "payer_client_ip")
private String payerClientIp;
/**
* <pre>
* 字段名商户端设备号
* 变量名device_id
* 是否必填
* 类型string[1,32]
* 描述
* 商户端设备号门店号或收银设备ID
* 示例值013467007045764
* </pre>
*/
@SerializedName(value = "device_id")
private String deviceId;
/**
* <pre>
* 字段名商户门店信息
* 变量名store_info
* 是否必填
* 类型object
* 描述
* 商户门店信息
* </pre>
*/
@SerializedName(value = "store_info")
private StoreInfo storeInfo;
/**
* <pre>
* 字段名H5场景信息
* 变量名h5_info
* 是否必填(H5支付必填)
* 类型object
* 描述
* H5场景信息
* </pre>
*/
@SerializedName(value = "h5_info")
private H5Info h5Info;
}
@Data
@NoArgsConstructor
public static class StoreInfo implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名门店编号
* 变量名id
* 是否必填
* 类型string[1,32]
* 描述
* 商户侧门店编号
* 示例值0001
* </pre>
*/
@SerializedName(value = "id")
private String id;
/**
* <pre>
* 字段名门店名称
* 变量名name
* 是否必填
* 类型string[1,256]
* 描述
* 商户侧门店名称
* 示例值腾讯大厦分店
* </pre>
*/
@SerializedName(value = "name")
private String name;
/**
* <pre>
* 字段名地区编码
* 变量名area_code
* 是否必填
* 类型string[1,32]
* 描述
* 地区编码详细请见省市区编号对照表(https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml)
* 示例值440305
* </pre>
*/
@SerializedName(value = "area_code")
private String areaCode;
/**
* <pre>
* 字段名详细地址
* 变量名address
* 是否必填
* 类型string[1,512]
* 描述
* 详细的商户门店地址
* 示例值广东省深圳市南山区科技中一道10000号
* </pre>
*/
@SerializedName(value = "address")
private String address;
}
@Data
@NoArgsConstructor
public static class H5Info implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名场景类型
* 变量名type
* 是否必填
* 类型string[1,32]
* 描述
* 场景类型
* 示例值iOS, Android, Wap
* </pre>
*/
@SerializedName(value = "type")
private String type;
/**
* <pre>
* 字段名应用名称
* 变量名app_name
* 是否必填
* 类型string[1,64]
* 描述
* 应用名称
* 示例值王者荣耀
* </pre>
*/
@SerializedName(value = "app_name")
private String appName;
/**
* <pre>
* 字段名网站URL
* 变量名app_url
* 是否必填
* 类型string[1,128]
* 描述
* 网站URL
* 示例值https://pay.qq.com
* </pre>
*/
@SerializedName(value = "app_url")
private String appUrl;
/**
* <pre>
* 字段名iOS平台BundleID
* 变量名bundle_id
* 是否必填
* 类型string[1,128]
* 描述
* iOS平台BundleID
* 示例值com.tencent.wzryiOS
* </pre>
*/
@SerializedName(value = "bundle_id")
private String bundleId;
/**
* <pre>
* 字段名Android平台PackageName
* 变量名package_name
* 是否必填
* 类型string[1,128]
* 描述
* Android平台PackageName
* 示例值com.tencent.tmgp.sgame
* </pre>
*/
@SerializedName(value = "package_name")
private String packageName;
}
@Data
@NoArgsConstructor
public static class SettleInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名是否指定分账
* 变量名profit_sharing
* 是否必填
* 类型boolean
* 描述
* 是否指定分账
* 示例值false
* </pre>
*/
@SerializedName(value = "profit_sharing")
private Boolean profitSharing;
}
}

View File

@ -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;
/**
* <pre>
* 查询订单 返回结果对象
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
public class WxPayOrderQueryV3Result implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名应用ID
* 变量名appid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户申请的公众号或移动应用appid
* 示例值wxd678efh567hg6787
* </pre>
*/
@SerializedName(value = "appid")
private String appid;
/**
* <pre>
* 字段名直连商户号
* 变量名mchid
* 是否必填
* 类型string[1,32]
* 描述
* 直连商户的商户号由微信支付生成并下发
* 示例值1230000109
* </pre>
*/
@SerializedName(value = "mchid")
private String mchid;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[6,32]
* 描述
* 商户系统内部订单号只能是数字大小写字母_-*且在同一个商户号下唯一详见商户订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付系统生成的订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名交易类型
* 变量名trade_type
* 是否必填
* 类型string[1,16]
* 描述
* 交易类型枚举值
* JSAPI公众号支付
* NATIVE扫码支付
* APPAPP支付
* MICROPAY付款码支付
* MWEBH5支付
* FACEPAY刷脸支付
* 示例值MICROPAY
* </pre>
*/
@SerializedName(value = "trade_type")
private String tradeType;
/**
* <pre>
* 字段名交易状态
* 变量名trade_state
* 是否必填
* 类型string[1,32]
* 描述
* 交易状态枚举值
* SUCCESS支付成功
* REFUND转入退款
* NOTPAY未支付
* CLOSED已关闭
* REVOKED已撤销付款码支付
* USERPAYING用户支付中付款码支付
* PAYERROR支付失败(其他原因如银行返回失败)
* ACCEPT已接收等待扣款
* 示例值SUCCESS
* </pre>
*/
@SerializedName(value = "trade_state")
private String tradeState;
/**
* <pre>
* 字段名交易状态描述
* 变量名trade_state_desc
* 是否必填
* 类型string[1,256]
* 描述
* 交易状态描述
* 示例值支付成功
* </pre>
*/
@SerializedName(value = "trade_state_desc")
private String tradeStateDesc;
/**
* <pre>
* 字段名付款银行
* 变量名bank_type
* 是否必填
* 类型string[1,16]
* 描述
* 银行类型采用字符串类型的银行标识银行标识请参考银行类型对照表https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6
* 示例值CMC
* </pre>
*/
@SerializedName(value = "bank_type")
private String bankType;
/**
* <pre>
* 字段名附加数据
* 变量名attach
* 是否必填
* 类型string[1,128]
* 描述
* 附加数据在查询API和支付通知中原样返回可作为自定义参数使用
* 示例值自定义数据
* </pre>
*/
@SerializedName(value = "attach")
private String attach;
/**
* <pre>
* 字段名支付完成时间
* 变量名success_time
* 是否必填
* 类型string[1,64]
* 描述
* 支付完成时间遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-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
* </pre>
*/
@SerializedName(value = "success_time")
private String successTime;
/**
* <pre>
* 字段名支付者
* 变量名payer
* 是否必填
* 类型object
* 描述
* 支付者信息
* </pre>
*/
private Payer payer;
/**
* <pre>
* 字段名订单金额
* 变量名amount
* 是否必填
* 类型object
* 描述
* 订单金额信息当支付成功时返回该字段
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名场景信息
* 变量名scene_info
* 是否必填
* 类型object
* 描述
* 支付场景描述
* </pre>
*/
@SerializedName(value = "scene_info")
private SceneInfo sceneInfo;
/**
* <pre>
* 字段名优惠功能
* 变量名promotion_detail
* 是否必填
* 类型array
* 描述
* 优惠功能享受优惠时返回该字段
* </pre>
*/
@SerializedName(value = "promotion_detail")
private List<PromotionDetail> promotionDetails;
@Data
@NoArgsConstructor
public static class Payer implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名用户标识
* 变量名openid
* 是否必填
* 类型string[1,128]
* 描述
* 用户在直连商户appid下的唯一标识
* 示例值oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
* </pre>
*/
@SerializedName(value = "openid")
private String openid;
}
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名总金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 订单总金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名用户支付金额
* 变量名payer_total
* 是否必填
* 类型int
* 描述
* 用户支付金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "payer_total")
private Integer payerTotal;
/**
* <pre>
* 字段名货币类型
* 变量名currency
* 是否必填
* 类型string[1,16]
* 描述
* CNY人民币境内商户号仅支持人民币
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
/**
* <pre>
* 字段名用户支付币种
* 变量名payer_currency
* 是否必填
* 类型string[1,16]
* 描述
* 用户支付币种
* 示例值 CNY
* </pre>
*/
@SerializedName(value = "payer_currency")
private String payerCurrency;
}
@Data
@NoArgsConstructor
public static class SceneInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名商户端设备号
* 变量名device_id
* 是否必填
* 类型string[1,32]
* 描述
* 商户端设备号发起扣款请求的商户服务器设备号
* 示例值013467007045764
* </pre>
*/
@SerializedName(value = "device_id")
private String deviceId;
}
@Data
@NoArgsConstructor
public static class PromotionDetail implements Serializable {
/**
* <pre>
* 字段名券ID
* 变量名coupon_id
* 是否必填
* 类型string[1,32]
* 描述
* 券ID
* 示例值109519
* </pre>
*/
@SerializedName(value = "coupon_id")
private String couponId;
/**
* <pre>
* 字段名优惠名称
* 变量名name
* 是否必填
* 类型string[1,64]
* 描述
* 优惠名称
* 示例值单品惠-6
* </pre>
*/
@SerializedName(value = "name")
private String name;
/**
* <pre>
* 字段名优惠范围
* 变量名scope
* 是否必填
* 类型string[1,32]
* 描述
* GLOBAL全场代金券
* SINGLE单品优惠
* 示例值GLOBAL
* </pre>
*/
@SerializedName(value = "scope")
private String scope;
/**
* <pre>
* 字段名优惠类型
* 变量名type
* 是否必填
* 类型string[1,32]
* 描述
* CASH充值
* NOCASH预充值
* 示例值CASH
* </pre>
*/
@SerializedName(value = "type")
private String type;
/**
* <pre>
* 字段名优惠券面额
* 变量名amount
* 是否必填
* 类型int
* 描述
* 优惠券面额
* 示例值100
* </pre>
*/
@SerializedName(value = "amount")
private Integer amount;
/**
* <pre>
* 字段名活动ID
* 变量名stock_id
* 是否必填
* 类型string[1,32]
* 描述
* 活动ID
* 示例值931386
* </pre>
*/
@SerializedName(value = "stock_id")
private String stockId;
/**
* <pre>
* 字段名微信出资
* 变量名wechatpay_contribute
* 是否必填
* 类型int
* 描述
* 微信出资单位为分
* 示例值0
* </pre>
*/
@SerializedName(value = "wechatpay_contribute")
private Integer wechatpayContribute;
/**
* <pre>
* 字段名商户出资
* 变量名merchant_contribute
* 是否必填
* 类型int
* 描述
* 商户出资单位为分
* 示例值0
* </pre>
*/
@SerializedName(value = "merchant_contribute")
private Integer merchantContribute;
/**
* <pre>
* 字段名其他出资
* 变量名other_contribute
* 是否必填
* 类型int
* 描述
* 其他出资单位为分
* 示例值0
* </pre>
*/
@SerializedName(value = "other_contribute")
private Integer otherContribute;
/**
* <pre>
* 字段名优惠币种
* 变量名currency
* 是否必填
* 类型string[1,16]
* 描述
* CNY人民币境内商户号仅支持人民币
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
/**
* <pre>
* 字段名单品列表
* 变量名goods_detail
* 是否必填
* 类型array
* 描述
* 单品列表信息
* </pre>
*/
@SerializedName(value = "goods_detail")
private List<GoodsDetail> goodsDetails;
}
@Data
@NoArgsConstructor
public static class GoodsDetail implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名商品编码
* 变量名goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 商品编码
* 示例值M1006
* </pre>
*/
@SerializedName(value = "goods_id")
private String goodsId;
/**
* <pre>
* 字段名商品数量
* 变量名quantity
* 是否必填
* 类型int
* 描述
* 用户购买的数量
* 示例值1
* </pre>
*/
@SerializedName(value = "quantity")
private Integer quantity;
/**
* <pre>
* 字段名商品单价
* 变量名unit_price
* 是否必填
* 类型int
* 描述
* 商品单价单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "unit_price")
private Integer unitPrice;
/**
* <pre>
* 字段名商品优惠金额
* 变量名discount_amount
* 是否必填
* 类型int
* 描述
* 商品优惠金额
* 示例值0
* </pre>
*/
@SerializedName(value = "discount_amount")
private Integer discountAmount;
/**
* <pre>
* 字段名商品备注
* 变量名goods_remark
* 是否必填
* 类型string[1,128]
* 描述
* 商品备注信息
* 示例值商品备注信息
* </pre>
*/
@SerializedName(value = "goods_remark")
private String goodsRemark;
}
}

View File

@ -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;
/**
* <pre>
* 微信支付-退款查询返回结果
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
public class WxPayRefundQueryV3Result implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名微信支付退款号
* 变量名refund_id
* 是否必填
* 类型string[1, 32]
* 描述
* 微信支付退款号
* 示例值50000000382019052709732678859
* </pre>
*/
@SerializedName(value = "refund_id")
private String refundId;
/**
* <pre>
* 字段名商户退款单号
* 变量名out_refund_no
* 是否必填
* 类型string[1, 64]
* 描述
* 商户系统内部的退款单号商户系统内部唯一只能是数字大小写字母_-|*@ 同一退款单号多次请求只退一笔
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_refund_no")
private String outRefundNo;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填
* 类型string[1, 32]
* 描述
* 微信支付交易订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[1, 32]
* 描述
* 原支付交易对应的商户订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名退款渠道
* 变量名channel
* 是否必填
* 类型string[1, 16]
* 描述
* 枚举值
* ORIGINAL原路退款
* BALANCE退回到余额
* OTHER_BALANCE原账户异常退到其他余额账户
* OTHER_BANKCARD原银行卡异常退到其他银行卡
* 示例值ORIGINAL
* </pre>
*/
@SerializedName(value = "channel")
private String channel;
/**
* <pre>
* 字段名退款入账账户
* 变量名user_received_account
* 是否必填
* 类型string[1, 64]
* 描述
* 取当前退款单的退款入账方有以下几种情况
* 1退回银行卡{银行名称}{卡类型}{卡尾号}
* 2退回支付用户零钱支付用户零钱
* 3退还商户商户基本账户商户结算银行账户
* 4退回支付用户零钱通支付用户零钱通
* 示例值招商银行信用卡0403
* </pre>
*/
@SerializedName(value = "user_received_account")
private String userReceivedAccount;
/**
* <pre>
* 字段名退款成功时间
* 变量名success_time
* 是否必填
* 类型string[1, 64]
* 描述
* 退款成功时间当退款状态为退款成功时有返回遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-MM-DD表示年月日T出现在字符串中表示time元素的开头HH:mm:ss表示时分秒TIMEZONE表示时区+08:00表示东八区时间领先UTC 8小时即北京时间例如2015-05-20T13:29:35+08:00表示北京时间2015年5月20日13点29分35秒
* 示例值2020-12-01T16:18:12+08:00
* </pre>
*/
@SerializedName(value = "success_time")
private String successTime;
/**
* <pre>
* 字段名退款创建时间
* 变量名create_time
* 是否必填
* 类型string[1, 64]
* 描述
* 退款受理时间 遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-MM-DD表示年月日T出现在字符串中表示time元素的开头HH:mm:ss表示时分秒TIMEZONE表示时区+08:00表示东八区时间领先UTC 8小时即北京时间例如2015-05-20T13:29:35+08:00表示北京时间2015年5月20日13点29分35秒
* 示例值2020-12-01T16:18:12+08:00
* </pre>
*/
@SerializedName(value = "create_time")
private String createTime;
/**
* <pre>
* 字段名退款状态
* 变量名status
* 是否必填
* 类型string[1, 32]
* 描述
* 退款到银行发现用户的卡作废或者冻结了导致原路退款银行卡失败可前往商户平台-交易中心手动处理此笔退款
* 枚举值
* SUCCESS退款成功
* CLOSED退款关闭
* PROCESSING退款处理中
* ABNORMAL退款异常
* 示例值SUCCESS
* </pre>
*/
@SerializedName(value = "status")
private String status;
/**
* <pre>
* 字段名资金账户
* 变量名funds_account
* 是否必填
* 类型string[1, 32]
* 描述
* 退款所使用资金对应的资金账户类型 枚举值
* UNSETTLED : 未结算资金
* AVAILABLE : 可用余额
* UNAVAILABLE : 不可用余额
* OPERATION : 运营户
* 示例值UNSETTLED
* </pre>
*/
@SerializedName(value = "funds_account")
private String fundsAccount;
/**
* <pre>
* 字段名金额信息
* 变量名amount
* 是否必填
* 类型object
* 描述
* 金额详细信息
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名优惠退款信息
* 变量名promotion_detail
* 是否必填
* 类型array
* 描述
* 优惠退款信息
* </pre>
*/
public List<PromotionDetail> promotionDetails;
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名订单金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 订单总金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名退款金额
* 变量名refund
* 是否必填
* 类型int
* 描述
* 退款标价金额单位为分可以做部分退款
* 示例值100
* </pre>
*/
@SerializedName(value = "refund")
private Integer refund;
/**
* <pre>
* 字段名用户支付金额
* 变量名payer_total
* 是否必填
* 类型int
* 描述
* 现金支付金额单位为分只能为整数
* 示例值90
* </pre>
*/
@SerializedName(value = "payer_total")
private Integer payerTotal;
/**
* <pre>
* 字段名用户退款金额
* 变量名payer_refund
* 是否必填
* 类型int
* 描述
* 退款给用户的金额不包含所有优惠券金额
* 示例值90
* </pre>
*/
@SerializedName(value = "payer_refund")
private Integer payerRefund;
/**
* <pre>
* 字段名应结退款金额
* 变量名settlement_refund
* 是否必填
* 类型int
* 描述
* 去掉非充值代金券退款金额后的退款金额单位为分退款金额=申请退款金额-非充值代金券退款金额退款金额<=申请退款金额
* 示例值100
* </pre>
*/
@SerializedName(value = "settlement_refund")
private Integer settlementRefund;
/**
* <pre>
* 字段名用户退款金额
* 变量名settlement_total
* 是否必填
* 类型int
* 描述
* 应结订单金额=订单金额-免充值代金券金额应结订单金额<=订单金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "settlement_total")
private Integer settlementTotal;
/**
* <pre>
* 字段名优惠退款金额
* 变量名discount_refund
* 是否必填
* 类型int64
* 描述
* 优惠退款金额<=退款金额退款金额-代金券或立减优惠退款金额为现金说明详见代金券或立减优惠单位为分
* 示例值10
* </pre>
*/
@SerializedName(value = "discount_refund")
private Integer discountRefund;
/**
* <pre>
* 字段名币类型
* 变量名currency
* 是否必填
* 类型string[1, 16]
* 描述
* 符合ISO 4217标准的三位字母代码目前只支持人民币CNY
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
}
@Data
@NoArgsConstructor
public static class PromotionDetail implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名券ID
* 变量名promotion_id
* 是否必填
* 类型string[1, 32]
* 描述
* 券或者立减优惠id
* 示例值109519
* </pre>
*/
@SerializedName(value = "promotion_id")
private String promotionId;
/**
* <pre>
* 字段名优惠范围
* 变量名scope
* 是否必填
* 类型string[1, 32]
* 描述
* 枚举值
* GLOBAL全场代金券
* SINGLE单品优惠
* 示例值SINGLE
* </pre>
*/
@SerializedName(value = "scope")
private String scope;
/**
* <pre>
* 字段名优惠类型
* 变量名type
* 是否必填
* 类型string[1, 32]
* 描述
* 枚举值
* COUPON代金券需要走结算资金的充值型代金券
* DISCOUNT优惠券不走结算资金的免充值型优惠券
* 示例值DISCOUNT
* </pre>
*/
@SerializedName(value = "type")
private String type;
/**
* <pre>
* 字段名优惠券面额
* 变量名amount
* 是否必填
* 类型int
* 描述
* 用户享受优惠的金额优惠券面额=微信出资金额+商家出资金额+其他出资方金额 单位为分
* 示例值5
* </pre>
*/
@SerializedName(value = "amount")
private Integer amount;
/**
* <pre>
* 字段名优惠退款金额
* 变量名refund_amount
* 是否必填
* 类型int
* 描述
* 优惠退款金额<=退款金额退款金额-代金券或立减优惠退款金额为用户支付的现金说明详见代金券或立减优惠单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "refund_amount")
private Integer refundAmount;
/**
* <pre>
* 字段名商品列表
* 变量名goods_detail
* 是否必填
* 类型array
* 描述
* 优惠商品发生退款时返回商品信息
* </pre>
*/
@SerializedName(value = "goods_detail")
private List<GoodsDetail> goodsDetails;
}
@Data
@NoArgsConstructor
public static class GoodsDetail implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名商户侧商品编码
* 变量名merchant_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 由半角的大小写字母数字中划线下划线中的一种或几种组成
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "merchant_goods_id")
private String merchantGoodsId;
/**
* <pre>
* 字段名微信侧商品编码
* 变量名wechatpay_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付定义的统一商品编号没有可不传
* 示例值1001
* </pre>
*/
@SerializedName(value = "wechatpay_goods_id")
private String wechatpayGoodsId;
/**
* <pre>
* 字段名商品名称
* 变量名goods_name
* 是否必填
* 类型string[1,256]
* 描述
* 商品的实际名称
* 示例值iPhone6s 16G
* </pre>
*/
@SerializedName(value = "goods_name")
private String goodsName;
/**
* <pre>
* 字段名商品单价
* 变量名unit_price
* 是否必填
* 类型int
* 描述
* 商品单价金额单位为分
* 示例值528800
* </pre>
*/
@SerializedName(value = "unit_price")
private Integer unitPrice;
/**
* <pre>
* 字段名商品退款金额
* 变量名refund_amount
* 是否必填
* 类型int
* 描述
* 商品退款金额单位为分
* 示例值528800
* </pre>
*/
@SerializedName(value = "refund_amount")
private Integer refundAmount;
/**
* <pre>
* 字段名商品退货数量
* 变量名refund_quantity
* 是否必填
* 类型int
* 描述
* 单品的退款数量
* 示例值1
* </pre>
*/
@SerializedName(value = "refund_quantity")
private Integer refundQuantity;
}
}

View File

@ -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;
/**
* <pre>
* 微信支付-申请退款返回结果.
* https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
public class WxPayRefundV3Result implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名微信退款单号
* 变量名refund_id
* 是否必填
* 类型string[1, 32]
* 描述
* 微信支付退款号
* 示例值50000000382019052709732678859
* </pre>
*/
@SerializedName(value = "refund_id")
private String refundId;
/**
* <pre>
* 字段名商户退款单号
* 变量名out_refund_no
* 是否必填
* 类型string[1, 64]
* 描述
* 商户系统内部的退款单号商户系统内部唯一只能是数字大小写字母_-|*@ 同一退款单号多次请求只退一笔
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_refund_no")
private String outRefundNo;
/**
* <pre>
* 字段名微信支付订单号
* 变量名transaction_id
* 是否必填
* 类型string[1, 32]
* 描述
* 微信支付交易订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "transaction_id")
private String transactionId;
/**
* <pre>
* 字段名商户订单号
* 变量名out_trade_no
* 是否必填
* 类型string[1, 32]
* 描述
* 原支付交易对应的商户订单号
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "out_trade_no")
private String outTradeNo;
/**
* <pre>
* 字段名退款渠道
* 变量名channel
* 是否必填
* 类型string[1, 32]
* 描述
* 枚举值
* ORIGINAL原路退款
* BALANCE退回到余额
* OTHER_BALANCE原账户异常退到其他余额账户
* OTHER_BANKCARD原银行卡异常退到其他银行卡
* 示例值ORIGINAL
* </pre>
*/
@SerializedName(value = "channel")
private String channel;
/**
* <pre>
* 字段名退款入账账户
* 变量名user_received_account
* 是否必填
* 类型string[1, 64]
* 描述
* 取当前退款单的退款入账方有以下几种情况
* 1退回银行卡{银行名称}{卡类型}{卡尾号}
* 2退回支付用户零钱支付用户零钱
* 3退还商户商户基本账户商户结算银行账户
* 4退回支付用户零钱通支付用户零钱通
* 示例值招商银行信用卡0403
* </pre>
*/
@SerializedName(value = "user_received_account")
private String userReceivedAccount;
/**
* <pre>
* 字段名退款成功时间
* 变量名success_time
* 是否必填
* 类型string[1, 64]
* 描述
* 退款成功时间当退款状态为退款成功时有返回遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-MM-DD表示年月日T出现在字符串中表示time元素的开头HH:mm:ss表示时分秒TIMEZONE表示时区+08:00表示东八区时间领先UTC 8小时即北京时间例如2015-05-20T13:29:35+08:00表示北京时间2015年5月20日13点29分35秒
* 示例值2020-12-01T16:18:12+08:00
* </pre>
*/
@SerializedName(value = "success_time")
private String successTime;
/**
* <pre>
* 字段名退款创建时间
* 变量名create_time
* 是否必填
* 类型string[1, 64]
* 描述
* 退款受理时间 遵循rfc3339标准格式格式为YYYY-MM-DDTHH:mm:ss+TIMEZONEYYYY-MM-DD表示年月日T出现在字符串中表示time元素的开头HH:mm:ss表示时分秒TIMEZONE表示时区+08:00表示东八区时间领先UTC 8小时即北京时间例如2015-05-20T13:29:35+08:00表示北京时间2015年5月20日13点29分35秒
* 示例值2020-12-01T16:18:12+08:00
* </pre>
*/
@SerializedName(value = "create_time")
private String createTime;
/**
* <pre>
* 字段名退款状态
* 变量名status
* 是否必填
* 类型string[1, 32]
* 描述
* 退款到银行发现用户的卡作废或者冻结了导致原路退款银行卡失败可前往商户平台-交易中心手动处理此笔退款
* 枚举值
* SUCCESS退款成功
* CLOSED退款关闭
* PROCESSING退款处理中
* ABNORMAL退款异常
* 示例值SUCCESS
* </pre>
*/
@SerializedName(value = "status")
private String status;
/**
* <pre>
* 字段名资金账户
* 变量名funds_account
* 是否必填
* 类型string[1, 32]
* 描述
* 退款所使用资金对应的资金账户类型 枚举值
* UNSETTLED : 未结算资金
* AVAILABLE : 可用余额
* UNAVAILABLE : 不可用余额
* OPERATION : 运营户
* 示例值UNSETTLED
* </pre>
*/
@SerializedName(value = "funds_account")
private String fundsAccount;
/**
* <pre>
* 字段名金额信息
* 变量名amount
* 是否必填
* 类型object
* 描述
* 金额详细信息
* </pre>
*/
@SerializedName(value = "amount")
private Amount amount;
/**
* <pre>
* 字段名优惠退款信息
* 变量名promotion_detail
* 是否必填
* 类型array
* 描述
* 优惠退款信息
* </pre>
*/
@SerializedName(value = "promotion_detail")
private List<PromotionDetail> promotionDetail;
@Data
@NoArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名订单金额
* 变量名total
* 是否必填
* 类型int
* 描述
* 订单总金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "total")
private Integer total;
/**
* <pre>
* 字段名退款金额
* 变量名refund
* 是否必填
* 类型int
* 描述
* 退款标价金额单位为分可以做部分退款
* 示例值100
* </pre>
*/
@SerializedName(value = "refund")
private Integer refund;
/**
* <pre>
* 字段名用户支付金额
* 变量名payer_total
* 是否必填
* 类型int
* 描述
* 现金支付金额单位为分只能为整数
* 示例值90
* </pre>
*/
@SerializedName(value = "payer_total")
private Integer payerTotal;
/**
* <pre>
* 字段名用户退款金额
* 变量名payer_refund
* 是否必填
* 类型int
* 描述
* 退款给用户的金额不包含所有优惠券金额
* 示例值90
* </pre>
*/
@SerializedName(value = "payer_refund")
private Integer payerRefund;
/**
* <pre>
* 字段名应结退款金额
* 变量名settlement_refund
* 是否必填
* 类型int
* 描述
* 去掉非充值代金券退款金额后的退款金额单位为分退款金额=申请退款金额-非充值代金券退款金额退款金额<=申请退款金额
* 示例值100
* </pre>
*/
@SerializedName(value = "settlement_refund")
private Integer settlementRefund;
/**
* <pre>
* 字段名用户退款金额
* 变量名settlement_total
* 是否必填
* 类型int
* 描述
* 应结订单金额=订单金额-免充值代金券金额应结订单金额<=订单金额单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "settlement_total")
private Integer settlementTotal;
/**
* <pre>
* 字段名优惠退款金额
* 变量名discount_refund
* 是否必填
* 类型int64
* 描述
* 优惠退款金额<=退款金额退款金额-代金券或立减优惠退款金额为现金说明详见代金券或立减优惠单位为分
* 示例值10
* </pre>
*/
@SerializedName(value = "discount_refund")
private Integer discountRefund;
/**
* <pre>
* 字段名币类型
* 变量名currency
* 是否必填
* 类型string[1, 16]
* 描述
* 符合ISO 4217标准的三位字母代码目前只支持人民币CNY
* 示例值CNY
* </pre>
*/
@SerializedName(value = "currency")
private String currency;
}
@Data
@NoArgsConstructor
public static class PromotionDetail implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名券ID
* 变量名promotion_id
* 是否必填
* 类型string[1, 32]
* 描述
* 券或者立减优惠id
* 示例值109519
* </pre>
*/
@SerializedName(value = "promotion_id")
private String promotionId;
/**
* <pre>
* 字段名优惠范围
* 变量名scope
* 是否必填
* 类型string[1, 32]
* 描述
* 枚举值
* GLOBAL全场代金券
* SINGLE单品优惠
* 示例值SINGLE
* </pre>
*/
@SerializedName(value = "scope")
private String scope;
/**
* <pre>
* 字段名优惠类型
* 变量名type
* 是否必填
* 类型string[1, 32]
* 描述
* 枚举值
* COUPON代金券需要走结算资金的充值型代金券
* DISCOUNT优惠券不走结算资金的免充值型优惠券
* 示例值DISCOUNT
* </pre>
*/
@SerializedName(value = "type")
private String type;
/**
* <pre>
* 字段名优惠券面额
* 变量名amount
* 是否必填
* 类型int
* 描述
* 用户享受优惠的金额优惠券面额=微信出资金额+商家出资金额+其他出资方金额 单位为分
* 示例值5
* </pre>
*/
@SerializedName(value = "amount")
private Integer amount;
/**
* <pre>
* 字段名优惠退款金额
* 变量名refund_amount
* 是否必填
* 类型int
* 描述
* 优惠退款金额<=退款金额退款金额-代金券或立减优惠退款金额为用户支付的现金说明详见代金券或立减优惠单位为分
* 示例值100
* </pre>
*/
@SerializedName(value = "refund_amount")
private Integer refundAmount;
/**
* <pre>
* 字段名商品列表
* 变量名goods_detail
* 是否必填
* 类型array
* 描述
* 优惠商品发生退款时返回商品信息
* </pre>
*/
@SerializedName(value = "goods_detail")
private List<GoodsDetail> goodsDetails;
}
@Data
@NoArgsConstructor
public static class GoodsDetail implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名商户侧商品编码
* 变量名merchant_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 由半角的大小写字母数字中划线下划线中的一种或几种组成
* 示例值1217752501201407033233368018
* </pre>
*/
@SerializedName(value = "merchant_goods_id")
private String merchantGoodsId;
/**
* <pre>
* 字段名微信侧商品编码
* 变量名wechatpay_goods_id
* 是否必填
* 类型string[1,32]
* 描述
* 微信支付定义的统一商品编号没有可不传
* 示例值1001
* </pre>
*/
@SerializedName(value = "wechatpay_goods_id")
private String wechatpayGoodsId;
/**
* <pre>
* 字段名商品名称
* 变量名goods_name
* 是否必填
* 类型string[1,256]
* 描述
* 商品的实际名称
* 示例值iPhone6s 16G
* </pre>
*/
@SerializedName(value = "goods_name")
private String goodsName;
/**
* <pre>
* 字段名商品单价
* 变量名unit_price
* 是否必填
* 类型int
* 描述
* 商品单价金额单位为分
* 示例值528800
* </pre>
*/
@SerializedName(value = "unit_price")
private Integer unitPrice;
/**
* <pre>
* 字段名商品退款金额
* 变量名refund_amount
* 是否必填
* 类型int
* 描述
* 商品退款金额单位为分
* 示例值528800
* </pre>
*/
@SerializedName(value = "refund_amount")
private Integer refundAmount;
/**
* <pre>
* 字段名商品退货数量
* 变量名refund_quantity
* 是否必填
* 类型int
* 描述
* 单品的退款数量
* 示例值1
* </pre>
*/
@SerializedName(value = "refund_quantity")
private Integer refundQuantity;
}
}

View File

@ -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;
/**
* <pre>
* 在发起微信支付前需要调用统一下单接口获取"预支付交易会话标识"返回的结果
* 参考文档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
* </pre>
*
* @author thinsstar
*/
@Data
@NoArgsConstructor
public class WxPayUnifiedOrderV3Result implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <pre>
* 字段名预支付交易会话标识APP支付JSAPI支付 会返回
* 变量名prepay_id
* 是否必填
* 类型string[1,64]
* 描述
* 预支付交易会话标识用于后续接口调用中使用该值有效期为2小时
* 示例值wx201410272009395522657a690389285100
* </pre>
*/
@SerializedName("prepay_id")
private String prepayId;
/**
* <pre>
* 字段名支付跳转链接H5支付 会返回
* 变量名h5_url
* 是否必填
* 类型string[1,512]
* 描述
* h5_url为拉起微信支付收银台的中间页面可通过访问该url来拉起微信客户端完成支付h5_url的有效期为5分钟
* 示例值https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx2016121516420242444321ca0631331346&package=1405458241
* </pre>
*/
@SerializedName("h5_url")
private String h5Url;
/**
* <pre>
* 字段名二维码链接NATIVE支付 会返回
* 变量名h5_url
* 是否必填
* 类型string[1,512]
* 描述
* 此URL用于生成支付二维码然后提供给用户扫码支付
* 注意code_url并非固定值使用时按照URL格式转成二维码即可
* 示例值weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00
* </pre>
*/
@SerializedName("code_url")
private String codeUrl;
@Data
@Accessors(chain = true)
public static class JsapiResult implements Serializable {
private String appId;
private String timeStamp;
private String nonceStr;
private String packageValue;
private String signType;
private String paySign;
private String getSignStr() {
return String.format("%s\n%s\n%s\n%s\n", appId, timeStamp, nonceStr, packageValue);
}
}
@Data
@Accessors(chain = true)
public static class AppResult implements Serializable {
private String appid;
private String partnerid;
private String prepayid;
private String packageValue;
private String noncestr;
private String timestamp;
}
public <T> T getPayInfo(TradeTypeEnum tradeType, String appId, String mchId, PrivateKey privateKey) {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = SignUtils.genRandomStr();
switch (tradeType) {
case JSAPI:
JsapiResult jsapiResult = new JsapiResult();
jsapiResult.setAppId(appId).setTimeStamp(timestamp)
.setPackageValue("prepay_id=" + this.prepayId).setNonceStr(nonceStr)
//签名类型默认为RSA仅支持RSA
.setSignType("RSA").setPaySign(SignUtils.sign(jsapiResult.getSignStr(), privateKey));
return (T) jsapiResult;
case H5:
return (T) this.h5Url;
case APP:
AppResult appResult = new AppResult();
appResult.setAppid(appId).setPrepayid(this.prepayId).setPartnerid(mchId)
.setNoncestr(nonceStr).setTimestamp(timestamp)
//暂填写固定值Sign=WXPay
.setPackageValue("Sign=WXPay");
return (T) appResult;
case NATIVE:
return (T) this.codeUrl;
}
return null;
}
}

View File

@ -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;
}

View File

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

View File

@ -2,11 +2,10 @@ package com.github.binarywang.wxpay.service;
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;
/**
* <pre>
* 查询订单
* 详见 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}
* </pre>
*
* @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;
/**
* <pre>
* 查询订单
* 详见 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}
* </pre>
*
* @param request 查询订单请求对象
* @return the wx pay order query result
* @throws WxPayException the wx pay exception
*/
WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) throws WxPayException;
/**
* <pre>
* 关闭订单.
@ -327,6 +373,40 @@ public interface WxPayService {
*/
WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws WxPayException;
/**
* <pre>
* 关闭订单
* 应用场景
* 以下情况需要调用关单接口
* 1商户订单支付失败需要生成新单号重新发起支付要对原订单号调用关单避免重复支付
* 2系统下单后用户支付超时系统退出不再受理避免用户继续请调用关单接口
* 注意关单没有时间限制建议在订单生成后间隔几分钟最短5分钟再调用关单接口避免出现订单状态同步不及时导致关单失败
* 接口地址https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
* </pre>
*
* @param outTradeNo 商户系统内部的订单号
* @return the wx pay order close result
* @throws WxPayException the wx pay exception
*/
void closeOrderV3(String outTradeNo) throws WxPayException;
/**
* <pre>
* 关闭订单
* 应用场景
* 以下情况需要调用关单接口
* 1商户订单支付失败需要生成新单号重新发起支付要对原订单号调用关单避免重复支付
* 2系统下单后用户支付超时系统退出不再受理避免用户继续请调用关单接口
* 注意关单没有时间限制建议在订单生成后间隔几分钟最短5分钟再调用关单接口避免出现订单状态同步不及时导致关单失败
* 接口地址https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
* </pre>
*
* @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 <T> 请使用{@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> T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException;
/**
* 在发起微信支付前需要调用统一下单接口获取"预支付交易会话标识"
*
* @param request 请求对象注意一些参数如appidmchid等不用设置方法内会自动从配置对象中获取到前提是对应配置中已经设置
* @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;
/**
* <pre>
* 申请退款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
* </pre>
*
* @param request 请求对象
* @return 退款操作结果 wx pay refund result
* @throws WxPayException the wx pay exception
*/
WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException;
/**
* <pre>
* 微信支付-查询退款.
@ -486,6 +612,36 @@ public interface WxPayService {
*/
WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) throws WxPayException;
/**
* <pre>
* 微信支付-查询退款
* 应用场景
* 提交退款申请后通过调用该接口查询退款状态退款有一定延时建议在提交退款申请后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}
* </pre>
*
* @param outTradeNo 商户订单号
* @return 退款信息 wx pay refund query result
* @throws WxPayException the wx pay exception
*/
WxPayRefundQueryV3Result refundQueryV3(String outTradeNo) throws WxPayException;
/**
* <pre>
* 微信支付-查询退款
* 应用场景
* 提交退款申请后通过调用该接口查询退款状态退款有一定延时建议在提交退款申请后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}
* </pre>
*
* @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 @@ public interface WxPayService {
*/
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 @@ public interface WxPayService {
*/
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

View File

@ -3,15 +3,14 @@ package com.github.binarywang.wxpay.service.impl;
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.exception.WxPayException;
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.Logger;
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 @@ import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType;
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 abstract class BaseWxPayServiceImpl implements WxPayService {
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 abstract class BaseWxPayServiceImpl implements WxPayService {
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 abstract class BaseWxPayServiceImpl implements WxPayService {
}
}
/**
* 校验通知签名
* @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 abstract class BaseWxPayServiceImpl implements WxPayService {
}
}
@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 abstract class BaseWxPayServiceImpl implements WxPayService {
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 abstract class BaseWxPayServiceImpl implements WxPayService {
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> T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
@ -500,6 +628,25 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
return result;
}
@Override
public <T> 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<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException {

View File

@ -9,6 +9,7 @@ import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
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.service.WxPayService;
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 class BaseWxPayServiceImplTest {
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));
}
}