mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-02-16 05:16:24 +08:00
合并 Develop,发布3.1.0正式版 (#640)
* #519 修复小程序客服消息 URL 被转义的问题 * 优化单元测试提示信息 * 网页授权url增加&connect_redirect=1参数解决两次重定向跳转问题: https://blog.csdn.net/jiangguilong2000/article/details/79416615 * 修复错误的feeToYuan方法名为fenToYuan * #529 EntPayBankRequest增加默认构造函数 * #529 EntPayBankResult中cmmsAmount的数据类型改为Integer * #528 WxMpUser类增加三个属性:subscribe_scene、 qr_scene 和qr_scene_str * 修复代码 * 发布3.0.1.BETA测试版本 * #533 微信刷卡支付请求类增加缺少的三个参数 * #536 企业号模块增加获取企业号应用相关接口 * 定义《企业号应用》的bean * 增加《获取企业号应用》接口实现 * 增加获取测试企业号应用信息测试类 * #535 修复Tomcat 不能正常关闭的问题,增加线程池shutdown相关的操作 * #541 企业号增加实现管理标签的(获取标签成员)接口 * 定义《企业号应用》的bean * 增加《获取企业号应用》接口实现 * 增加获取测试企业号应用信息测试类 * tag service增加获取标签成员方法 http://qydev.weixin.qq.com/wiki/index.php?title=管理标签 * #534 公众号发送模版消息中的小程序path改回pagepath * 发布3.0.2.BETA测试版本 * #547 开放平台模块 componentAccessToken 增加过期自动刷新 * createOrder方法增加H5支付的支持 * #551 文本卡片消息增加btntext字段 * #550 企业微信删除标签成员接口增加部门列表参数 * 清理无用代码 * #530 微信支付申请退款接口结果类增加单个代金券相关参数 ,并根据官方文档整理其他参数 * #531 小程序WxMaMessage类增加小程序卡片消息相关的几个属性 * #520 企业微信网页授权增加使用user_ticket获取成员详情的接口 * 发布3.0.3.BETA测试版本 * 优化代码 * 完善测试 * #559 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * #560 微信开放平台:增加小程序代码模板库管理 * 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * 微信开放平台:增加小程序代码模板库管理 * #562 小程序增加代码管理相关 API * 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * 微信开放平台:增加小程序代码模板库管理 * 小程序:增加代码管理相关 API * #563 小程序增加修改服务器地址、成员管理 API * 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * 微信开放平台:增加小程序代码模板库管理 * 小程序:增加代码管理相关 API * 小程序:增加修改服务器地址、成员管理 API * #565 小程序增加数据分析相关 API * 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * 微信开放平台:增加小程序代码模板库管理 * 小程序:增加代码管理相关 API * 小程序:增加修改服务器地址、成员管理 API * 小程序:增加数据分析相关 API * #567 微信开放平台增加 HTTP proxy 机制 * 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * 微信开放平台:增加小程序代码模板库管理 * 小程序:增加代码管理相关 API * 小程序:增加修改服务器地址、成员管理 API * 小程序:增加数据分析相关 API * 微信开放平台:增加 HTTP proxy 机制 * #568 修复三方平台多次授权时,RefreshToken 没有刷新的问题 * fix 多次授权时,RefreshToken 没有刷新 * null 判断 * 发布3.0.4.BETA测试版本 * fix code * #569 微信支付几个查询关闭对账下载相关接口增加重载方法,以方便客户端指定更多参数 * #578 微信开放平台增加 WxMaUserService 的实现 * 微信开放平台:1. WxOpenInRedisConfigStorage 支持 JedisPool/JedisSentinelPool 等 Pool<Jedis> 的子类;2. WxOpenInRedisConfigStorage 增加 keyPrefix 以支持可配置的前缀; * 微信开放平台:增加小程序代码模板库管理 * 小程序:增加代码管理相关 API * 小程序:增加修改服务器地址、成员管理 API * 小程序:增加数据分析相关 API * 微信开放平台:增加 HTTP proxy 机制 * 微信开放平台:增加 WxMaUserService 的实现 * 修复小程序码的相关方法命名:WxCode->WxaCode, WxCodeLimit -> WxaCodeUnlimit * #556 日志信息中如果含有secret值的,将其值隐藏掉 * #585 小程序二维码支持is_hyaline参数生成透明背景二维码 * 发布3.0.5.BETA测试版本 * #584 修复企业付款到银行卡接口签名失败的问题 * 简化代码 * #586 微信支付 WxPayConfig增加支持byte数组方式设置证书 * #581 增加微信公众号错误信息枚举类WxMpErrorMsg,并提供方法,方便根据错误代码查询错误信息内容 * #555 修复微信支付服务商模式支付验证签名失败的问题 * #521 微信支付回调通知类WxPayOrderNotifyResult增加version参数 * #583 企业微信新增人员接口新增字段to_invite * #583 企业微信通讯录管理增加邀请成员接口 * #587 企业微信几个接口增加个人二维码字段 * 修复字符 * 修复单元测试 * 发布3.0.6.BETA测试版本 * 重构WxError相关代码,自动根据代码补充错误中文说明 * 优化微信支付代码 * #584 修复企业付款queryEntPay签名失败问题 * #591 文件上传接口不自动关闭inputStream,由调用方自己控制 * #595 优化WxPayException * 发布3.0.7.BETA测试版本 * 更新pom * 优化代码 * #615 公众号客服消息添加 "发送小程序卡片" 类型 * 优化XStreamTransformer * 微信支付模块jodd-http修改scope * 发布3.0.8.BETA测试版本 * #623 群发接口增加clientmsgid * add author for some files * clean code * 重构规范RequestExecuter代码 * #532 实现微信AI开放接口的三个接口:语音上传、查询识别结果和微信翻译功能 * 发布3.0.9.BETA测试版本 * #516 增加获取Wi-Fi门店列表接口 * #629 修复WxPayOrderNotifyResult解析xml报错问题 * #639 修复小程序代码模版库管理 access_token key 错误 * 发布3.1.0正式版本
This commit is contained in:
@@ -3,9 +3,11 @@ package com.github.binarywang.wxpay.bean.entpay;
|
||||
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import me.chanjar.weixin.common.annotation.Required;
|
||||
|
||||
/**
|
||||
@@ -18,6 +20,8 @@ import me.chanjar.weixin.common.annotation.Required;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@XStreamAlias("xml")
|
||||
public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
@@ -30,6 +34,7 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
* 示例值:1212121221227
|
||||
* 类型:string(32)
|
||||
* 描述:商户订单号,需保持唯一(只允许数字[0~9]或字母[A~Z]和[a~z],最短8位,最长32位)
|
||||
* </pre>
|
||||
*/
|
||||
@Required
|
||||
@XStreamAlias("partner_trade_no")
|
||||
@@ -44,7 +49,7 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
* 示例值:8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f
|
||||
* 类型:string(64)
|
||||
* 描述:收款方银行卡号(采用标准RSA算法,公钥由微信侧提供),详见获取RSA加密公钥API
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Required
|
||||
@XStreamAlias("enc_bank_no")
|
||||
@@ -59,6 +64,7 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
* 示例值:ca775af5f841bdf424b2e6eb86a6e21e
|
||||
* 类型:string(64)
|
||||
* 描述:收款方用户名(采用标准RSA算法,公钥由微信侧提供)详见获取RSA加密公钥API
|
||||
* </pre>
|
||||
*/
|
||||
@Required
|
||||
@XStreamAlias("enc_true_name")
|
||||
@@ -72,6 +78,7 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
* 示例值:1001
|
||||
* 类型:string(64)
|
||||
* 描述:银行卡所在开户行编号,详见银行编号列表
|
||||
* </pre>
|
||||
*/
|
||||
@Required
|
||||
@XStreamAlias("bank_code")
|
||||
@@ -85,6 +92,7 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
* 示例值:100000
|
||||
* 类型:int
|
||||
* 描述:付款金额:RMB分(支付总额,不含手续费) 注:大于0的整数
|
||||
* </pre>
|
||||
*/
|
||||
@Required
|
||||
@XStreamAlias("amount")
|
||||
@@ -98,6 +106,7 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
* 示例值:理财
|
||||
* 类型:string
|
||||
* 描述:企业付款到银行卡付款说明,即订单备注(UTF8编码,允许100个字符以内)
|
||||
* </pre>
|
||||
*/
|
||||
@Required
|
||||
@XStreamAlias("desc")
|
||||
@@ -105,7 +114,11 @@ public class EntPayBankRequest extends BaseWxPayRequest {
|
||||
|
||||
@Override
|
||||
protected void checkConstraints() throws WxPayException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ignoreSignType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,6 +46,6 @@ public class EntPayBankResult extends BaseWxPayResult {
|
||||
* RMB:分
|
||||
*/
|
||||
@XStreamAlias("cmms_amt")
|
||||
private String cmmsAmount;
|
||||
private Integer cmmsAmount;
|
||||
|
||||
}
|
||||
|
||||
@@ -47,4 +47,8 @@ public class EntPayQueryRequest extends BaseWxPayRequest {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ignoreSignType() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,6 +271,18 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult {
|
||||
@XStreamAlias("time_end")
|
||||
private String timeEnd;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:接口版本号.
|
||||
* 变量名:version
|
||||
* 类型:String(32)
|
||||
* 示例值:1.0
|
||||
* 更多信息,详见文档:https://pay.weixin.qq.com/wiki/doc/api/danpin.php?chapter=9_101&index=1
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("version")
|
||||
private String version;
|
||||
|
||||
public static WxPayOrderNotifyResult fromXML(String xmlString) {
|
||||
XStream xstream = XStreamInitializer.getInstance();
|
||||
xstream.processAnnotations(WxPayOrderNotifyResult.class);
|
||||
|
||||
@@ -20,7 +20,7 @@ public class WxPayMpOrderResult {
|
||||
private String timeStamp;
|
||||
private String nonceStr;
|
||||
/**
|
||||
* 由于package为java保留关键字,因此改为packageValue
|
||||
* 由于package为java保留关键字,因此改为packageValue.
|
||||
*/
|
||||
@XStreamAlias("package")
|
||||
private String packageValue;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.binarywang.wxpay.bean.order;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信H5支付统一下单后发起支付拼接所需参数实现类.
|
||||
* Created by Binary Wang on 2018-4-21.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class WxPayMwebOrderResult {
|
||||
@XStreamAlias("mwebUrl")
|
||||
private String mwebUrl;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.binarywang.wxpay.bean.order;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -12,7 +13,7 @@ import lombok.Data;
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class WxPayNativeOrderResult {
|
||||
private String codeUrl;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.github.binarywang.wxpay.util.SignUtils;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.BeanUtils;
|
||||
import me.chanjar.weixin.common.util.ToStringUtils;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
|
||||
@@ -153,6 +153,33 @@ public class WxPayMicropayRequest extends BaseWxPayRequest {
|
||||
@XStreamAlias("limit_pay")
|
||||
private String limitPay;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:交易起始时间.
|
||||
* 变量名:time_start
|
||||
* 是否必填:否
|
||||
* 类型:String(14)
|
||||
* 示例值:20091225091010
|
||||
* 描述:订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("time_start")
|
||||
private String timeStart;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:交易结束时间.
|
||||
* 变量名:time_expire
|
||||
* 是否必填:否
|
||||
* 类型:String(14)
|
||||
* 示例值:20091227091010
|
||||
* 描述:订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
|
||||
* 注意:最短失效时间间隔必须大于5分钟
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("time_expire")
|
||||
private String timeExpire;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:授权码.
|
||||
@@ -167,6 +194,23 @@ public class WxPayMicropayRequest extends BaseWxPayRequest {
|
||||
@XStreamAlias("auth_code")
|
||||
private String authCode;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:场景信息.
|
||||
* 变量名:scene_info
|
||||
* 是否必填:否
|
||||
* 类型:String(256)
|
||||
* 示例值:{"store_info" : {
|
||||
* "id": "SZTX001",
|
||||
* "name": "腾大餐厅",
|
||||
* "area_code": "440305",
|
||||
* "address": "科技园中一路腾讯大厦" }}
|
||||
* 描述:该字段用于上报场景信息,目前支持上报实际门店信息。该字段为JSON对象数据,对象格式为{"store_info":{"id": "门店ID","name": "名称","area_code": "编码","address": "地址" }}
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("scene_info")
|
||||
private String sceneInfo;
|
||||
|
||||
@Override
|
||||
protected void checkConstraints() {
|
||||
//do nothing
|
||||
|
||||
@@ -113,10 +113,10 @@ public abstract class BaseWxPayResult implements Serializable {
|
||||
/**
|
||||
* 将单位分转换成单位圆.
|
||||
*
|
||||
* @param fee 将要被转换为元的分的数值
|
||||
* @param fen 将要被转换为元的分的数值
|
||||
*/
|
||||
public static String feeToYuan(Integer fee) {
|
||||
return new BigDecimal(Double.valueOf(fee) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
|
||||
public static String fenToYuan(Integer fen) {
|
||||
return new BigDecimal(Double.valueOf(fen) / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.github.binarywang.wxpay.bean.result;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
|
||||
/**
|
||||
* 企业付款查询返回结果
|
||||
* 请使用{@link EntPayQueryResult}
|
||||
*/
|
||||
@XStreamAlias("xml")
|
||||
@Deprecated
|
||||
public class WxEntPayQueryResult extends EntPayQueryResult {
|
||||
public static WxEntPayQueryResult createFrom(EntPayQueryResult entPayQueryResult) {
|
||||
WxEntPayQueryResult result = new WxEntPayQueryResult();
|
||||
try {
|
||||
BeanUtils.copyProperties(result, entPayQueryResult);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.github.binarywang.wxpay.bean.result;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
|
||||
/**
|
||||
* 企业付款返回结果
|
||||
* 请使用{@link EntPayResult}
|
||||
*/
|
||||
@XStreamAlias("xml")
|
||||
@Deprecated
|
||||
public class WxEntPayResult extends EntPayResult {
|
||||
public static WxEntPayResult createFrom(EntPayResult entPayResult) {
|
||||
WxEntPayResult result = new WxEntPayResult();
|
||||
try {
|
||||
BeanUtils.copyProperties(result, entPayResult);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.github.binarywang.wxpay.bean.result;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 退款代金券信息.
|
||||
* Created by BinaryWang on 2018/4/21.
|
||||
* </pre>
|
||||
*
|
||||
* @author Binary Wang
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WxPayRefundCouponInfo {
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:退款代金券ID.
|
||||
* 变量名:coupon_refund_id_$n_$m
|
||||
* 是否必填:否
|
||||
* 类型:String(20)
|
||||
* 示例值:10000
|
||||
* 描述:退款代金券ID, $n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_id")
|
||||
private String couponRefundId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:单个退款代金券支付金额.
|
||||
* 变量名:coupon_refund_fee_$n_$m
|
||||
* 是否必填:否
|
||||
* 类型:Int
|
||||
* 示例值:100
|
||||
* 描述:单个退款代金券支付金额, $n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
private Integer couponRefundFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:代金券类型.
|
||||
* 变量名:coupon_type_$n_$m
|
||||
* 是否必填:否
|
||||
* 类型:String(8)
|
||||
* 示例值:CASH
|
||||
* 描述:CASH--充值代金券 , NO_CASH---非充值代金券。
|
||||
* 开通免充值券功能,并且订单使用了优惠券后有返回(取值:CASH、NO_CASH)。
|
||||
* $n为下标,$m为下标,从0开始编号,举例:coupon_type_$0_$1
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_type")
|
||||
private String couponType;
|
||||
|
||||
}
|
||||
@@ -151,10 +151,10 @@ public class WxPayRefundQueryResult extends BaseWxPayResult {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<RefundRecord.RefundCoupon> coupons = Lists.newArrayList();
|
||||
List<WxPayRefundCouponInfo> coupons = Lists.newArrayList();
|
||||
for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) {
|
||||
coupons.add(
|
||||
new RefundRecord.RefundCoupon(
|
||||
new WxPayRefundCouponInfo(
|
||||
this.getXmlValue("xml/coupon_refund_id_" + i + "_" + j),
|
||||
this.getXmlValueAsInt("xml/coupon_refund_fee_" + i + "_" + j),
|
||||
this.getXmlValue("xml/coupon_type_" + i + "_" + j)
|
||||
@@ -277,7 +277,7 @@ public class WxPayRefundQueryResult extends BaseWxPayResult {
|
||||
@XStreamAlias("coupon_refund_count")
|
||||
private Integer couponRefundCount;
|
||||
|
||||
private List<RefundCoupon> refundCoupons;
|
||||
private List<WxPayRefundCouponInfo> refundCoupons;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -323,54 +323,6 @@ public class WxPayRefundQueryResult extends BaseWxPayResult {
|
||||
@XStreamAlias("refund_success_time")
|
||||
private String refundSuccessTime;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class RefundCoupon {
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:退款代金券ID.
|
||||
* 变量名:coupon_refund_id_$n_$m
|
||||
* 是否必填:否
|
||||
* 类型:String(20)
|
||||
* 示例值:10000
|
||||
* 描述:退款代金券ID, $n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_id")
|
||||
private String couponRefundId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:单个退款代金券支付金额.
|
||||
* 变量名:coupon_refund_fee_$n_$m
|
||||
* 是否必填:否
|
||||
* 类型:Int
|
||||
* 示例值:100
|
||||
* 描述:单个退款代金券支付金额, $n为下标,$m为下标,从0开始编号
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
private Integer couponRefundFee;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:代金券类型.
|
||||
* 变量名:coupon_type_$n_$m
|
||||
* 是否必填:否
|
||||
* 类型:String(8)
|
||||
* 示例值:CASH
|
||||
* 描述:CASH--充值代金券 , NO_CASH---非充值代金券。
|
||||
* 开通免充值券功能,并且订单使用了优惠券后有返回(取值:CASH、NO_CASH)。
|
||||
* $n为下标,$m为下标,从0开始编号,举例:coupon_type_$0_$1
|
||||
* </pre>
|
||||
*/
|
||||
@XStreamAlias("coupon_type")
|
||||
private String couponType;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +1,122 @@
|
||||
package com.github.binarywang.wxpay.bean.result;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信支付-申请退款返回结果
|
||||
* 微信支付-申请退款返回结果.
|
||||
* https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
|
||||
* </pre>
|
||||
*
|
||||
* @author liukaitj
|
||||
* @author liukaitj & Binary Wang
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@NoArgsConstructor
|
||||
@XStreamAlias("xml")
|
||||
public class WxPayRefundResult extends BaseWxPayResult implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@XStreamAlias("device_info")
|
||||
private String deviceInfo;
|
||||
|
||||
private static final long serialVersionUID = -3392333879907788033L;
|
||||
/**
|
||||
* 微信订单号.
|
||||
*/
|
||||
@XStreamAlias("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* 商户订单号.
|
||||
*/
|
||||
@XStreamAlias("out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 商户退款单号.
|
||||
*/
|
||||
@XStreamAlias("out_refund_no")
|
||||
private String outRefundNo;
|
||||
|
||||
/**
|
||||
* 微信退款单号.
|
||||
*/
|
||||
@XStreamAlias("refund_id")
|
||||
private String refundId;
|
||||
|
||||
@XStreamAlias("refund_channel")
|
||||
private String refundChannel;
|
||||
|
||||
/**
|
||||
* 退款金额.
|
||||
*/
|
||||
@XStreamAlias("refund_fee")
|
||||
private String refundFee;
|
||||
private Integer refundFee;
|
||||
|
||||
/**
|
||||
* 应结退款金额.
|
||||
*/
|
||||
@XStreamAlias("settlement_refund_fee")
|
||||
private Integer settlementRefundFee;
|
||||
|
||||
/**
|
||||
* 标价金额.
|
||||
*/
|
||||
@XStreamAlias("total_fee")
|
||||
private String totalFee;
|
||||
private Integer totalFee;
|
||||
|
||||
/**
|
||||
* 应结订单金额.
|
||||
*/
|
||||
@XStreamAlias("settlement_total_fee")
|
||||
private Integer settlementTotalFee;
|
||||
|
||||
/**
|
||||
* 标价币种.
|
||||
*/
|
||||
@XStreamAlias("fee_type")
|
||||
private String feeType;
|
||||
|
||||
/**
|
||||
* 现金支付金额.
|
||||
*/
|
||||
@XStreamAlias("cash_fee")
|
||||
private String cashFee;
|
||||
private Integer cashFee;
|
||||
|
||||
/**
|
||||
* 现金支付币种.
|
||||
*/
|
||||
@XStreamAlias("cash_fee_type")
|
||||
private String cashFeeType;
|
||||
|
||||
/**
|
||||
* 现金退款金额.
|
||||
*/
|
||||
@XStreamAlias("cash_refund_fee")
|
||||
private String cashRefundFee;
|
||||
|
||||
@XStreamAlias("coupon_refund_fee")
|
||||
private String couponRefundFee;
|
||||
|
||||
/**
|
||||
* 退款代金券使用数量.
|
||||
*/
|
||||
@XStreamAlias("coupon_refund_count")
|
||||
private String couponRefundCount;
|
||||
private Integer couponRefundCount;
|
||||
|
||||
@XStreamAlias("coupon_refund_id")
|
||||
private String couponRefundId;
|
||||
private List<WxPayRefundCouponInfo> refundCoupons;
|
||||
|
||||
/**
|
||||
* 组装生成退款代金券信息.
|
||||
*/
|
||||
public void composeRefundCoupons() {
|
||||
List<WxPayRefundCouponInfo> coupons = Lists.newArrayList();
|
||||
for (int i = 0; i < this.getCouponRefundCount(); i++) {
|
||||
coupons.add(
|
||||
new WxPayRefundCouponInfo(
|
||||
this.getXmlValue("xml/coupon_refund_id_" + i),
|
||||
this.getXmlValueAsInt("xml/coupon_refund_fee_" + i),
|
||||
this.getXmlValue("xml/coupon_type_" + i)
|
||||
)
|
||||
);
|
||||
}
|
||||
this.setRefundCoupons(coupons);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,213 +1,137 @@
|
||||
package com.github.binarywang.wxpay.config;
|
||||
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信支付配置
|
||||
*
|
||||
* @author Binary Wang (https://github.com/binarywang)
|
||||
*/
|
||||
@Data
|
||||
public class WxPayConfig {
|
||||
|
||||
/**
|
||||
* http请求连接超时时间
|
||||
* http请求连接超时时间.
|
||||
*/
|
||||
private int httpConnectionTimeout = 5000;
|
||||
|
||||
/**
|
||||
* http请求数据读取等待时间
|
||||
* http请求数据读取等待时间.
|
||||
*/
|
||||
private int httpTimeout = 10000;
|
||||
|
||||
/**
|
||||
* 公众号appid.
|
||||
*/
|
||||
private String appId;
|
||||
/**
|
||||
* 服务商模式下的子商户公众账号ID.
|
||||
*/
|
||||
private String subAppId;
|
||||
/**
|
||||
* 商户号.
|
||||
*/
|
||||
private String mchId;
|
||||
/**
|
||||
* 商户密钥.
|
||||
*/
|
||||
private String mchKey;
|
||||
/**
|
||||
* 服务商模式下的子商户号.
|
||||
*/
|
||||
private String subMchId;
|
||||
/**
|
||||
* 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数.
|
||||
*/
|
||||
private String notifyUrl;
|
||||
private String tradeType;
|
||||
private String signType;
|
||||
private SSLContext sslContext;
|
||||
private String keyPath;
|
||||
private boolean useSandboxEnv = false;
|
||||
private String httpProxyHost;
|
||||
private Integer httpProxyPort;
|
||||
private String httpProxyUsername;
|
||||
private String httpProxyPassword;
|
||||
|
||||
public String getKeyPath() {
|
||||
return keyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置证书
|
||||
*
|
||||
* @param keyPath apiclient_cert.p12的文件的绝对路径
|
||||
*/
|
||||
public void setKeyPath(String keyPath) {
|
||||
this.keyPath = keyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
public String getMchId() {
|
||||
return this.mchId;
|
||||
}
|
||||
|
||||
public void setMchId(String mchId) {
|
||||
this.mchId = mchId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户密钥
|
||||
*/
|
||||
public String getMchKey() {
|
||||
return this.mchKey;
|
||||
}
|
||||
|
||||
public void setMchKey(String mchKey) {
|
||||
this.mchKey = mchKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 公众号appid
|
||||
*/
|
||||
public String getAppId() {
|
||||
return this.appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务商模式下的子商户公众账号ID
|
||||
*/
|
||||
public String getSubAppId() {
|
||||
return this.subAppId;
|
||||
}
|
||||
|
||||
public void setSubAppId(String subAppId) {
|
||||
this.subAppId = subAppId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务商模式下的子商户号
|
||||
*/
|
||||
public String getSubMchId() {
|
||||
return this.subMchId;
|
||||
}
|
||||
|
||||
public void setSubMchId(String subMchId) {
|
||||
this.subMchId = subMchId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数。
|
||||
*/
|
||||
public String getNotifyUrl() {
|
||||
return this.notifyUrl;
|
||||
}
|
||||
|
||||
public void setNotifyUrl(String notifyUrl) {
|
||||
this.notifyUrl = notifyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易类型
|
||||
* 交易类型.
|
||||
* <pre>
|
||||
* JSAPI--公众号支付
|
||||
* NATIVE--原生扫码支付
|
||||
* APP--app支付
|
||||
* </pre>
|
||||
*/
|
||||
public String getTradeType() {
|
||||
return this.tradeType;
|
||||
}
|
||||
|
||||
public void setTradeType(String tradeType) {
|
||||
this.tradeType = tradeType;
|
||||
}
|
||||
|
||||
private String tradeType;
|
||||
/**
|
||||
* 签名方式
|
||||
* 签名方式.
|
||||
* 有两种HMAC_SHA256 和MD5
|
||||
*
|
||||
* @see com.github.binarywang.wxpay.constant.WxPayConstants.SignType
|
||||
*/
|
||||
public String getSignType() {
|
||||
return this.signType;
|
||||
}
|
||||
|
||||
public void setSignType(String signType) {
|
||||
this.signType = signType;
|
||||
}
|
||||
|
||||
public SSLContext getSslContext() {
|
||||
return this.sslContext;
|
||||
}
|
||||
|
||||
public void setSslContext(SSLContext sslContext) {
|
||||
this.sslContext = sslContext;
|
||||
}
|
||||
private String signType;
|
||||
private SSLContext sslContext;
|
||||
/**
|
||||
* p12证书文件的绝对路径或者以classpath:开头的类路径.
|
||||
*/
|
||||
private String keyPath;
|
||||
|
||||
/**
|
||||
* 微信支付是否使用仿真测试环境
|
||||
* p12证书文件内容的字节数组.
|
||||
*/
|
||||
private byte[] keyContent;
|
||||
/**
|
||||
* 微信支付是否使用仿真测试环境.
|
||||
* 默认不使用
|
||||
*/
|
||||
public boolean useSandbox() {
|
||||
return this.useSandboxEnv;
|
||||
}
|
||||
private boolean useSandboxEnv = false;
|
||||
private String httpProxyHost;
|
||||
private Integer httpProxyPort;
|
||||
private String httpProxyUsername;
|
||||
private String httpProxyPassword;
|
||||
|
||||
/**
|
||||
* 设置是否使用沙箱仿真测试环境
|
||||
* 初始化ssl.
|
||||
*/
|
||||
public void setUseSandboxEnv(boolean useSandboxEnv) {
|
||||
this.useSandboxEnv = useSandboxEnv;
|
||||
}
|
||||
|
||||
public SSLContext initSSLContext() throws WxPayException {
|
||||
if (StringUtils.isBlank(this.getMchId())) {
|
||||
throw new WxPayException("请确保商户号mchId已设置");
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(this.getKeyPath())) {
|
||||
throw new WxPayException("请确保证书文件地址keyPath已配置");
|
||||
}
|
||||
|
||||
InputStream inputStream;
|
||||
final String prefix = "classpath:";
|
||||
String fileHasProblemMsg = "证书文件【" + this.getKeyPath() + "】有问题,请核实!";
|
||||
String fileNotFoundMsg = "证书文件【" + this.getKeyPath() + "】不存在,请核实!";
|
||||
if (this.getKeyPath().startsWith(prefix)) {
|
||||
String path = StringUtils.removeFirst(this.getKeyPath(), prefix);
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
inputStream = WxPayConfig.class.getResourceAsStream(path);
|
||||
if (inputStream == null) {
|
||||
throw new WxPayException(fileNotFoundMsg);
|
||||
}
|
||||
if (this.keyContent != null) {
|
||||
inputStream = new ByteArrayInputStream(this.keyContent);
|
||||
} else {
|
||||
try {
|
||||
File file = new File(this.getKeyPath());
|
||||
if (!file.exists()) {
|
||||
if (StringUtils.isBlank(this.getKeyPath())) {
|
||||
throw new WxPayException("请确保证书文件地址keyPath已配置");
|
||||
}
|
||||
|
||||
final String prefix = "classpath:";
|
||||
String fileHasProblemMsg = "证书文件【" + this.getKeyPath() + "】有问题,请核实!";
|
||||
String fileNotFoundMsg = "证书文件【" + this.getKeyPath() + "】不存在,请核实!";
|
||||
if (this.getKeyPath().startsWith(prefix)) {
|
||||
String path = StringUtils.removeFirst(this.getKeyPath(), prefix);
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
inputStream = WxPayConfig.class.getResourceAsStream(path);
|
||||
if (inputStream == null) {
|
||||
throw new WxPayException(fileNotFoundMsg);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
File file = new File(this.getKeyPath());
|
||||
if (!file.exists()) {
|
||||
throw new WxPayException(fileNotFoundMsg);
|
||||
}
|
||||
|
||||
inputStream = new FileInputStream(file);
|
||||
} catch (IOException e) {
|
||||
throw new WxPayException(fileHasProblemMsg, e);
|
||||
inputStream = new FileInputStream(file);
|
||||
} catch (IOException e) {
|
||||
throw new WxPayException(fileHasProblemMsg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,63 +142,10 @@ public class WxPayConfig {
|
||||
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
|
||||
return this.sslContext;
|
||||
} catch (Exception e) {
|
||||
throw new WxPayException(fileHasProblemMsg, e);
|
||||
throw new WxPayException("证书文件有问题,请核实!", e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* http请求连接超时时间
|
||||
*/
|
||||
public int getHttpConnectionTimeout() {
|
||||
return this.httpConnectionTimeout;
|
||||
}
|
||||
|
||||
public void setHttpConnectionTimeout(int httpConnectionTimeout) {
|
||||
this.httpConnectionTimeout = httpConnectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* http请求数据读取等待时间
|
||||
*/
|
||||
public int getHttpTimeout() {
|
||||
return this.httpTimeout;
|
||||
}
|
||||
|
||||
public void setHttpTimeout(int httpTimeout) {
|
||||
this.httpTimeout = httpTimeout;
|
||||
}
|
||||
|
||||
public String getHttpProxyHost() {
|
||||
return httpProxyHost;
|
||||
}
|
||||
|
||||
public void setHttpProxyHost(String httpProxyHost) {
|
||||
this.httpProxyHost = httpProxyHost;
|
||||
}
|
||||
|
||||
public Integer getHttpProxyPort() {
|
||||
return httpProxyPort;
|
||||
}
|
||||
|
||||
public void setHttpProxyPort(Integer httpProxyPort) {
|
||||
this.httpProxyPort = httpProxyPort;
|
||||
}
|
||||
|
||||
public String getHttpProxyUsername() {
|
||||
return httpProxyUsername;
|
||||
}
|
||||
|
||||
public void setHttpProxyUsername(String httpProxyUsername) {
|
||||
this.httpProxyUsername = httpProxyUsername;
|
||||
}
|
||||
|
||||
public String getHttpProxyPassword() {
|
||||
return httpProxyPassword;
|
||||
}
|
||||
|
||||
public void setHttpProxyPassword(String httpProxyPassword) {
|
||||
this.httpProxyPassword = httpProxyPassword;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.github.binarywang.wxpay.converter;
|
||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyCoupon;
|
||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
@@ -21,6 +22,9 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author aimilin
|
||||
*/
|
||||
public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter {
|
||||
|
||||
public WxPayOrderNotifyResultConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
|
||||
@@ -72,26 +76,26 @@ public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter
|
||||
fields.addAll(Arrays.asList(obj.getClass().getSuperclass().getDeclaredFields()));
|
||||
Map<String, Field> fieldMap = getFieldMap(fields);
|
||||
|
||||
List<WxPayOrderNotifyCoupon> coupons = new ArrayList<>(10);
|
||||
Map<Integer, WxPayOrderNotifyCoupon> coupons = Maps.newTreeMap();
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
if (fieldMap.containsKey(reader.getNodeName())) {
|
||||
Field field = fieldMap.get(reader.getNodeName());
|
||||
setFieldValue(context, obj, field);
|
||||
this.setFieldValue(context, obj, field);
|
||||
} else if (StringUtils.startsWith(reader.getNodeName(), "coupon_id_")) {
|
||||
String id = (String) context.convertAnother(obj, String.class);
|
||||
getIndex(coupons, reader.getNodeName()).setCouponId(id);
|
||||
this.getElement(coupons, reader.getNodeName()).setCouponId(id);
|
||||
} else if (StringUtils.startsWith(reader.getNodeName(), "coupon_type_")) {
|
||||
String type = (String) context.convertAnother(obj, String.class);
|
||||
getIndex(coupons, reader.getNodeName()).setCouponType(type);
|
||||
this.getElement(coupons, reader.getNodeName()).setCouponType(type);
|
||||
} else if (StringUtils.startsWith(reader.getNodeName(), "coupon_fee_")) {
|
||||
Integer fee = (Integer) context.convertAnother(obj, Integer.class);
|
||||
getIndex(coupons, reader.getNodeName()).setCouponFee(fee);
|
||||
this.getElement(coupons, reader.getNodeName()).setCouponFee(fee);
|
||||
}
|
||||
reader.moveUp();
|
||||
}
|
||||
|
||||
obj.setCouponList(coupons);
|
||||
obj.setCouponList(Lists.newArrayList(coupons.values()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -102,12 +106,12 @@ public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter
|
||||
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), obj.getClass());
|
||||
pd.getWriteMethod().invoke(obj, val);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Field> getFieldMap(List<Field> fields) {
|
||||
Map<String, Field> fieldMap = Maps.uniqueIndex(fields, new Function<Field, String>() {
|
||||
return Maps.uniqueIndex(fields, new Function<Field, String>() {
|
||||
@Override
|
||||
public String apply(Field field) {
|
||||
if (field.isAnnotationPresent(XStreamAlias.class)) {
|
||||
@@ -116,14 +120,14 @@ public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter
|
||||
return field.getName();
|
||||
}
|
||||
});
|
||||
return fieldMap;
|
||||
}
|
||||
|
||||
private WxPayOrderNotifyCoupon getIndex(List<WxPayOrderNotifyCoupon> coupons, String nodeName) {
|
||||
Integer index = Integer.valueOf(StringUtils.substring(nodeName, nodeName.lastIndexOf("_") + 1));
|
||||
if (index >= coupons.size() || coupons.get(index) == null) {
|
||||
coupons.add(index, new WxPayOrderNotifyCoupon());
|
||||
private WxPayOrderNotifyCoupon getElement(Map<Integer, WxPayOrderNotifyCoupon> coupons, String nodeName) {
|
||||
Integer index = Integer.valueOf(StringUtils.substringAfterLast(nodeName, "_"));
|
||||
if (coupons.get(index) == null) {
|
||||
coupons.put(index, new WxPayOrderNotifyCoupon());
|
||||
}
|
||||
|
||||
return coupons.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,41 +2,52 @@ package com.github.binarywang.wxpay.exception;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
|
||||
import com.google.common.base.Joiner;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信支付异常结果类
|
||||
* Created by Binary Wang on 2017-6-6.
|
||||
* </pre>
|
||||
*
|
||||
* @author BinaryWang
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class WxPayException extends Exception {
|
||||
private static final long serialVersionUID = 2214381471513460742L;
|
||||
|
||||
/**
|
||||
* 自定义错误讯息.
|
||||
*/
|
||||
private String customErrorMsg;
|
||||
/**
|
||||
* 返回状态码
|
||||
* 返回状态码.
|
||||
*/
|
||||
private String returnCode;
|
||||
/**
|
||||
* 返回信息
|
||||
* 返回信息.
|
||||
*/
|
||||
private String returnMsg;
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
* 业务结果.
|
||||
*/
|
||||
private String resultCode;
|
||||
|
||||
/**
|
||||
* 错误代码
|
||||
* 错误代码.
|
||||
*/
|
||||
private String errCode;
|
||||
|
||||
/**
|
||||
* 错误代码描述
|
||||
* 错误代码描述.
|
||||
*/
|
||||
private String errCodeDes;
|
||||
|
||||
/**
|
||||
* 微信支付返回的结果xml字符串
|
||||
* 微信支付返回的结果xml字符串.
|
||||
*/
|
||||
private String xmlString;
|
||||
|
||||
@@ -60,6 +71,9 @@ public class WxPayException extends Exception {
|
||||
xmlString = builder.xmlString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过BaseWxPayResult生成异常对象.
|
||||
*/
|
||||
public static WxPayException from(BaseWxPayResult payBaseResult) {
|
||||
return WxPayException.newBuilder()
|
||||
.xmlString(payBaseResult.getXmlString())
|
||||
@@ -71,30 +85,6 @@ public class WxPayException extends Exception {
|
||||
.build();
|
||||
}
|
||||
|
||||
public String getXmlString() {
|
||||
return this.xmlString;
|
||||
}
|
||||
|
||||
public String getReturnCode() {
|
||||
return this.returnCode;
|
||||
}
|
||||
|
||||
public String getReturnMsg() {
|
||||
return this.returnMsg;
|
||||
}
|
||||
|
||||
public String getResultCode() {
|
||||
return this.resultCode;
|
||||
}
|
||||
|
||||
public String getErrCode() {
|
||||
return this.errCode;
|
||||
}
|
||||
|
||||
public String getErrCodeDes() {
|
||||
return this.errCodeDes;
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
@@ -145,14 +135,14 @@ public class WxPayException extends Exception {
|
||||
}
|
||||
|
||||
public String buildErrorMsg() {
|
||||
return Joiner.on(",").skipNulls().join(new String[]{
|
||||
return Joiner.on(",").skipNulls().join(
|
||||
returnCode == null ? null : String.format("返回代码:[%s]", returnCode),
|
||||
returnMsg == null ? null : String.format("返回信息:[%s]", returnMsg),
|
||||
resultCode == null ? null : String.format("结果代码:[%s]", resultCode),
|
||||
errCode == null ? null : String.format("错误代码:[%s]", errCode),
|
||||
errCodeDes == null ? null : String.format("错误详情:[%s]", errCodeDes),
|
||||
xmlString == null ? null : "微信返回的原始报文:\n" + xmlString,
|
||||
});
|
||||
xmlString == null ? null : "微信返回的原始报文:\n" + xmlString
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,19 @@
|
||||
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.request.*;
|
||||
import com.github.binarywang.wxpay.bean.result.*;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.WxPayApiData;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryResult;
|
||||
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.request.WxPayAuthcode2OpenidRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayReportRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayBillResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信支付相关接口.
|
||||
@@ -98,6 +77,23 @@ public interface WxPayService {
|
||||
*/
|
||||
WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询订单(适合于需要自定义子商户号和子商户appid的情形).
|
||||
* 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
|
||||
* 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
|
||||
* 需要调用查询接口的情况:
|
||||
* ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
|
||||
* ◆ 调用支付接口后,返回系统错误或未知交易状态情况;
|
||||
* ◆ 调用被扫支付API,返回USERPAYING的状态;
|
||||
* ◆ 调用关单或撤销接口API之前,需确认支付状态;
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/orderquery
|
||||
* </pre>
|
||||
*
|
||||
* @param request 查询订单请求对象
|
||||
*/
|
||||
WxPayOrderQueryResult queryOrder(WxPayOrderQueryRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 关闭订单.
|
||||
@@ -114,6 +110,22 @@ public interface WxPayService {
|
||||
*/
|
||||
WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 关闭订单(适合于需要自定义子商户号和子商户appid的情形).
|
||||
* 应用场景
|
||||
* 以下情况需要调用关单接口:
|
||||
* 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
|
||||
* 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
|
||||
* 注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/closeorder
|
||||
* 是否需要证书: 不需要。
|
||||
* </pre>
|
||||
*
|
||||
* @param request 关闭订单请求对象
|
||||
*/
|
||||
WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 调用统一下单接口,并组装生成支付所需参数对象.
|
||||
*
|
||||
@@ -185,11 +197,19 @@ public interface WxPayService {
|
||||
throws WxPayException;
|
||||
|
||||
/**
|
||||
* @see WxPayService#parseOrderNotifyResult(String).
|
||||
* @deprecated use {@link WxPayService#parseOrderNotifyResult(String)} instead
|
||||
* <pre>
|
||||
* 微信支付-查询退款(适合于需要自定义子商户号和子商户appid的情形).
|
||||
* 应用场景:
|
||||
* 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,
|
||||
* 银行卡支付的退款3个工作日后重新查询退款状态。
|
||||
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
|
||||
* 接口链接:https://api.mch.weixin.qq.com/pay/refundquery
|
||||
* </pre>
|
||||
*
|
||||
* @param request 微信退款单号
|
||||
* @return 退款信息
|
||||
*/
|
||||
@Deprecated
|
||||
WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException;
|
||||
WxPayRefundQueryResult refundQuery(WxPayRefundQueryRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 解析支付结果通知.
|
||||
@@ -315,6 +335,24 @@ public interface WxPayService {
|
||||
*/
|
||||
WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 下载对账单(适合于需要自定义子商户号和子商户appid的情形).
|
||||
* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
|
||||
* 注意:
|
||||
* 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;
|
||||
* 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
|
||||
* 3、对账单中涉及金额的字段单位为“元”。
|
||||
* 4、对账单接口只能下载三个月以内的账单。
|
||||
* 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill
|
||||
* 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param request 下载对账单请求
|
||||
* @return 保存到本地的临时文件
|
||||
*/
|
||||
WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 提交刷卡支付.
|
||||
|
||||
@@ -1,67 +1,17 @@
|
||||
package com.github.binarywang.wxpay.service.impl;
|
||||
|
||||
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.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.binarywang.utils.qrcode.QrcodeUtils;
|
||||
import com.github.binarywang.wxpay.bean.WxPayApiData;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryResult;
|
||||
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.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.WxPayAuthcode2OpenidRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayDefaultRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayDownloadBillRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayQueryCommentRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayRedpackQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayReportRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
|
||||
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayAuthcode2OpenidResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayBillBaseResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayBillResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayCommonResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPaySandboxSignKeyResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayShorturlResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
|
||||
import com.github.binarywang.wxpay.bean.request.*;
|
||||
import com.github.binarywang.wxpay.bean.result.*;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants.BillType;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
|
||||
@@ -73,6 +23,17 @@ import com.github.binarywang.wxpay.util.SignUtils;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Maps;
|
||||
import jodd.io.ZipUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT;
|
||||
import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType;
|
||||
@@ -116,7 +77,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
|
||||
@Override
|
||||
public String getPayBaseUrl() {
|
||||
if (this.getConfig().useSandbox()) {
|
||||
if (this.getConfig().isUseSandboxEnv()) {
|
||||
return PAY_BASE_URL + "/sandboxnew";
|
||||
}
|
||||
|
||||
@@ -130,6 +91,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
String url = this.getPayBaseUrl() + "/secapi/pay/refund";
|
||||
String responseContent = this.post(url, request.toXML(), true);
|
||||
WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class);
|
||||
result.composeRefundCoupons();
|
||||
result.checkResult(this, request.getSignType(), true);
|
||||
return result;
|
||||
}
|
||||
@@ -143,6 +105,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
|
||||
request.setRefundId(StringUtils.trimToNull(refundId));
|
||||
|
||||
return this.refundQuery(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayRefundQueryResult refundQuery(WxPayRefundQueryRequest request) throws WxPayException {
|
||||
request.checkAndSign(this.getConfig());
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/refundquery";
|
||||
@@ -153,12 +120,6 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException {
|
||||
return this.parseOrderNotifyResult(xmlData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException {
|
||||
try {
|
||||
@@ -193,7 +154,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
public WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData) throws WxPayException {
|
||||
try {
|
||||
log.debug("扫码支付回调通知请求参数:{}", xmlData);
|
||||
WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData,WxScanPayNotifyResult.class);
|
||||
WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class);
|
||||
log.debug("扫码支付回调通知解析后的对象:{}", result);
|
||||
result.checkResult(this, this.getConfig().getSignType(), false);
|
||||
return result;
|
||||
@@ -241,6 +202,12 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
|
||||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||
request.setTransactionId(StringUtils.trimToNull(transactionId));
|
||||
|
||||
return this.queryOrder(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayOrderQueryResult queryOrder(WxPayOrderQueryRequest request) throws WxPayException {
|
||||
request.checkAndSign(this.getConfig());
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/orderquery";
|
||||
@@ -263,6 +230,12 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
|
||||
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
|
||||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||
|
||||
return this.closeOrder(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws WxPayException {
|
||||
request.checkAndSign(this.getConfig());
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/closeorder";
|
||||
@@ -278,25 +251,37 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
|
||||
String prepayId = unifiedOrderResult.getPrepayId();
|
||||
if (StringUtils.isBlank(prepayId)) {
|
||||
throw new RuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。",
|
||||
throw new WxPayException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。",
|
||||
unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
|
||||
}
|
||||
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
String nonceStr = String.valueOf(System.currentTimeMillis());
|
||||
switch (request.getTradeType()) {
|
||||
case TradeType.MWEB: {
|
||||
return (T) new WxPayMwebOrderResult(unifiedOrderResult.getMwebUrl());
|
||||
}
|
||||
|
||||
case TradeType.NATIVE: {
|
||||
return (T) WxPayNativeOrderResult.builder()
|
||||
.codeUrl(unifiedOrderResult.getCodeURL())
|
||||
.build();
|
||||
return (T) new WxPayNativeOrderResult(unifiedOrderResult.getCodeURL());
|
||||
}
|
||||
|
||||
case TradeType.APP: {
|
||||
// APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数
|
||||
String appId = this.getConfig().getAppId();
|
||||
Map<String, String> configMap = new HashMap<>();
|
||||
String appId = unifiedOrderResult.getAppid();
|
||||
if (StringUtils.isNotEmpty(unifiedOrderResult.getSubAppId())) {
|
||||
appId = unifiedOrderResult.getSubAppId();
|
||||
}
|
||||
|
||||
Map<String, String> configMap = new HashMap<>(8);
|
||||
// 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改
|
||||
String partnerId = getConfig().getMchId();
|
||||
String partnerId;
|
||||
if (StringUtils.isEmpty(request.getMchId())) {
|
||||
partnerId = this.getConfig().getMchId();
|
||||
} else {
|
||||
partnerId = request.getMchId();
|
||||
}
|
||||
|
||||
configMap.put("prepayid", prepayId);
|
||||
configMap.put("partnerid", partnerId);
|
||||
String packageValue = "Sign=WXPay";
|
||||
@@ -305,7 +290,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
configMap.put("noncestr", nonceStr);
|
||||
configMap.put("appid", appId);
|
||||
|
||||
return (T) WxPayAppOrderResult.builder()
|
||||
final WxPayAppOrderResult result = WxPayAppOrderResult.builder()
|
||||
.sign(SignUtils.createSign(configMap, null, this.getConfig().getMchKey(), false))
|
||||
.prepayId(prepayId)
|
||||
.partnerId(partnerId)
|
||||
@@ -314,25 +299,25 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
.timeStamp(timestamp)
|
||||
.nonceStr(nonceStr)
|
||||
.build();
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
case TradeType.JSAPI: {
|
||||
String signType = SignType.MD5;
|
||||
String appid = unifiedOrderResult.getAppid();
|
||||
if (StringUtils.isNotEmpty(unifiedOrderResult.getSubAppId())) {
|
||||
appid = unifiedOrderResult.getSubAppId();
|
||||
}
|
||||
|
||||
WxPayMpOrderResult payResult = WxPayMpOrderResult.builder()
|
||||
.appId(unifiedOrderResult.getAppid())
|
||||
.appId(appid)
|
||||
.timeStamp(timestamp)
|
||||
.nonceStr(nonceStr)
|
||||
.packageValue("prepay_id=" + prepayId)
|
||||
.signType(signType)
|
||||
.build();
|
||||
|
||||
payResult.setPaySign(
|
||||
SignUtils.createSign(
|
||||
payResult,
|
||||
signType,
|
||||
this.getConfig().getMchKey(),
|
||||
false)
|
||||
);
|
||||
payResult.setPaySign(SignUtils.createSign(payResult, signType, this.getConfig().getMchKey(), false));
|
||||
return (T) payResult;
|
||||
}
|
||||
|
||||
@@ -417,14 +402,15 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
params.put("appid", this.getConfig().getAppId());
|
||||
params.put("mch_id", this.getConfig().getMchId());
|
||||
params.put("product_id", productId);
|
||||
params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));//这里需要秒,10位数字
|
||||
//这里需要秒,10位数字
|
||||
params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
|
||||
|
||||
String sign = SignUtils.createSign(params, null, this.getConfig().getMchKey(), false);
|
||||
params.put("sign", sign);
|
||||
|
||||
for (String key : params.keySet()) {
|
||||
codeUrl.append(key + "=" + params.get(key) + "&");
|
||||
codeUrl.append(key).append("=").append(params.get(key)).append("&");
|
||||
}
|
||||
|
||||
String content = codeUrl.toString().substring(0, codeUrl.length() - 1);
|
||||
@@ -467,12 +453,17 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
request.setTarType(tarType);
|
||||
request.setDeviceInfo(deviceInfo);
|
||||
|
||||
return this.downloadBill(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException {
|
||||
request.checkAndSign(this.getConfig());
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/downloadbill";
|
||||
|
||||
String responseContent;
|
||||
if (TarType.GZIP.equals(tarType)) {
|
||||
if (TarType.GZIP.equals(request.getTarType())) {
|
||||
responseContent = this.handleGzipBill(url, request.toXML());
|
||||
} else {
|
||||
responseContent = this.post(url, request.toXML(), false);
|
||||
@@ -481,7 +472,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.handleBill(billType, responseContent);
|
||||
return this.handleBill(request.getBillType(), responseContent);
|
||||
}
|
||||
|
||||
private WxPayBillResult handleBill(String billType, String responseContent) {
|
||||
@@ -509,9 +500,10 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
this.log.error("解压zip文件出错", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
this.log.error("解析对账单文件时出错", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.github.binarywang.wxpay.service.impl;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.WxPayApiData;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import jodd.util.Base64;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
@@ -19,9 +20,9 @@ import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import com.github.binarywang.wxpay.bean.WxPayApiData;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import jodd.util.Base64;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
@@ -37,8 +38,8 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
try {
|
||||
HttpClientBuilder httpClientBuilder = createHttpClientBuilder(useKey);
|
||||
HttpPost httpPost = this.createHttpPost(url, requestStr);
|
||||
try (CloseableHttpClient httpclient = httpClientBuilder.build()) {
|
||||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
|
||||
try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
final byte[] bytes = EntityUtils.toByteArray(response.getEntity());
|
||||
final String responseData = Base64.encodeToString(bytes);
|
||||
this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据(Base64编码后)】:{}", url, requestStr, responseData);
|
||||
@@ -60,8 +61,8 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
try {
|
||||
HttpClientBuilder httpClientBuilder = this.createHttpClientBuilder(useKey);
|
||||
HttpPost httpPost = this.createHttpPost(url, requestStr);
|
||||
try (CloseableHttpClient httpclient = httpClientBuilder.build()) {
|
||||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
|
||||
try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString);
|
||||
wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
|
||||
@@ -90,7 +91,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
private HttpClientBuilder createHttpClientBuilder(boolean useKey) throws WxPayException {
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom();
|
||||
if (useKey) {
|
||||
this.setKey(httpClientBuilder);
|
||||
this.initSSLContext(httpClientBuilder);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(this.getConfig().getHttpProxyHost())
|
||||
@@ -118,15 +119,15 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
return httpPost;
|
||||
}
|
||||
|
||||
private void setKey(HttpClientBuilder httpClientBuilder) throws WxPayException {
|
||||
private void initSSLContext(HttpClientBuilder httpClientBuilder) throws WxPayException {
|
||||
SSLContext sslContext = this.getConfig().getSslContext();
|
||||
if (null == sslContext) {
|
||||
sslContext = this.getConfig().initSSLContext();
|
||||
}
|
||||
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
|
||||
SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
|
||||
new String[]{"TLSv1"}, null, new DefaultHostnameVerifier());
|
||||
httpClientBuilder.setSSLSocketFactory(sslsf);
|
||||
httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.testng.annotations.*;
|
||||
*/
|
||||
public class WxPayOrderNotifyResultTest {
|
||||
@Test
|
||||
public void testFromXML() throws Exception {
|
||||
public void testFromXML() {
|
||||
String xmlString = "<xml>\n" +
|
||||
" <appid><![CDATA[wx2421b1c4370ec43b]]></appid>\n" +
|
||||
" <attach><![CDATA[支付测试]]></attach>\n" +
|
||||
@@ -32,12 +32,12 @@ public class WxPayOrderNotifyResultTest {
|
||||
" <trade_type><![CDATA[JSAPI]]></trade_type>\n" +
|
||||
" <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>\n" +
|
||||
" <coupon_count>2</coupon_count>\n" +
|
||||
" <coupon_type_0><![CDATA[CASH]]></coupon_type_0>\n" +
|
||||
" <coupon_id_0>10000</coupon_id_0>\n" +
|
||||
" <coupon_fee_0>100</coupon_fee_0>\n" +
|
||||
" <coupon_type_1><![CDATA[NO_CASH]]></coupon_type_1>\n" +
|
||||
" <coupon_id_1>10001</coupon_id_1>\n" +
|
||||
" <coupon_fee_1>200</coupon_fee_1>\n" +
|
||||
" <coupon_type_0><![CDATA[CASH]]></coupon_type_0>\n" +
|
||||
" <coupon_id_0>10000</coupon_id_0>\n" +
|
||||
" <coupon_fee_0>100</coupon_fee_0>\n" +
|
||||
"</xml>";
|
||||
|
||||
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlString);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.github.binarywang.wxpay.bean.result;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Created by BinaryWang on 2018/4/22.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class WxPayRefundResultTest {
|
||||
|
||||
@Test
|
||||
public void testComposeRefundCoupons() {
|
||||
/*
|
||||
该xml字符串来自于官方文档示例,稍加改造,加上代金卷
|
||||
refund_channel 是个什么鬼,官方文档只字不提
|
||||
*/
|
||||
String xmlString = "<xml>\n" +
|
||||
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
|
||||
" <return_msg><![CDATA[OK]]></return_msg>\n" +
|
||||
" <appid><![CDATA[wx2421b1c4370ec43b]]></appid>\n" +
|
||||
" <mch_id><![CDATA[10000100]]></mch_id>\n" +
|
||||
" <nonce_str><![CDATA[NfsMFbUFpdbEhPXP]]></nonce_str>\n" +
|
||||
" <sign><![CDATA[B7274EB9F8925EB93100DD2085FA56C0]]></sign>\n" +
|
||||
" <result_code><![CDATA[SUCCESS]]></result_code>\n" +
|
||||
" <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>\n" +
|
||||
" <out_trade_no><![CDATA[1415757673]]></out_trade_no>\n" +
|
||||
" <out_refund_no><![CDATA[1415701182]]></out_refund_no>\n" +
|
||||
" <refund_id><![CDATA[2008450740201411110000174436]]></refund_id>\n" +
|
||||
" <refund_channel><![CDATA[]]></refund_channel>\n" +
|
||||
" <coupon_refund_fee>1</coupon_refund_fee>\n" +
|
||||
" <coupon_refund_count>1</coupon_refund_count>\n" +
|
||||
" <coupon_refund_id_0>123</coupon_refund_id_0>\n" +
|
||||
" <coupon_refund_fee_0>1</coupon_refund_fee_0>\n" +
|
||||
" <coupon_type_0><![CDATA[CASH]]></coupon_type_0>\n" +
|
||||
" <refund_fee>2</refund_fee> \n" +
|
||||
"</xml>";
|
||||
|
||||
WxPayRefundResult result = WxPayRefundResult.fromXML(xmlString, WxPayRefundResult.class);
|
||||
result.composeRefundCoupons();
|
||||
|
||||
assertThat(result.getRefundCoupons()).isNotEmpty();
|
||||
assertThat(result.getRefundCoupons().get(0).getCouponRefundId()).isEqualTo("123");
|
||||
assertThat(result.getRefundCoupons().get(0).getCouponType()).isEqualTo("CASH");
|
||||
assertThat(result.getRefundCoupons().get(0).getCouponRefundFee()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
@@ -230,6 +230,10 @@ public class BaseWxPayServiceImplTest {
|
||||
request.setActName("abc");
|
||||
request.setClientIp("aaa");
|
||||
request.setMchBillNo("aaaa");
|
||||
request.setWishing("what");
|
||||
request.setSendName("111");
|
||||
request.setTotalAmount(1);
|
||||
request.setTotalNum(1);
|
||||
request.setReOpenid(((XmlWxPayConfig) this.payService.getConfig()).getOpenid());
|
||||
WxPaySendRedpackResult redpackResult = this.payService.sendRedpack(request);
|
||||
this.logger.info(redpackResult.toString());
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.github.binarywang.wxpay.testbase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
||||
@@ -8,17 +14,15 @@ import com.google.inject.Module;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ApiTestModule implements Module {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
private static final String TEST_CONFIG_XML = "test-config.xml";
|
||||
|
||||
@Override
|
||||
public void configure(Binder binder) {
|
||||
try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(TEST_CONFIG_XML)) {
|
||||
if (inputStream == null) {
|
||||
throw new RuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到");
|
||||
throw new RuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
|
||||
}
|
||||
|
||||
XmlWxPayConfig config = this.fromXml(XmlWxPayConfig.class, inputStream);
|
||||
@@ -28,8 +32,9 @@ public class ApiTestModule implements Module {
|
||||
binder.bind(WxPayService.class).toInstance(wxService);
|
||||
binder.bind(WxPayConfig.class).toInstance(config);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
this.log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -16,9 +16,9 @@ public class XmlWxPayConfig extends WxPayConfig {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSandbox() {
|
||||
public boolean isUseSandboxEnv() {
|
||||
//沙箱环境不成熟,有问题无法使用,暂时屏蔽掉
|
||||
// return true;
|
||||
//return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user