| @@ -2,7 +2,6 @@ package me.chanjar.weixin.mp.api; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult; | |||||
| import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | ||||
| @@ -13,8 +12,9 @@ import java.io.File; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| /** | /** | ||||
| * 微信支付相关接口 | |||||
| * Created by Binary Wang on 2016/7/28. | |||||
| * 微信支付相关接口 | |||||
| * Created by Binary Wang on 2016/7/28. | |||||
| * | |||||
| * @author binarywang (https://github.com/binarywang) | * @author binarywang (https://github.com/binarywang) | ||||
| */ | */ | ||||
| public interface WxMpPayService { | public interface WxMpPayService { | ||||
| @@ -24,14 +24,15 @@ public interface WxMpPayService { | |||||
| * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2) | * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2) | ||||
| * 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。 | * 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。 | ||||
| * 需要调用查询接口的情况: | * 需要调用查询接口的情况: | ||||
| ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; | |||||
| ◆ 调用支付接口后,返回系统错误或未知交易状态情况; | |||||
| ◆ 调用被扫支付API,返回USERPAYING的状态; | |||||
| ◆ 调用关单或撤销接口API之前,需确认支付状态; | |||||
| * ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; | |||||
| * ◆ 调用支付接口后,返回系统错误或未知交易状态情况; | |||||
| * ◆ 调用被扫支付API,返回USERPAYING的状态; | |||||
| * ◆ 调用关单或撤销接口API之前,需确认支付状态; | |||||
| * 接口地址:https://api.mch.weixin.qq.com/pay/orderquery | * 接口地址:https://api.mch.weixin.qq.com/pay/orderquery | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param transactionId 微信支付分配的商户号 | * @param transactionId 微信支付分配的商户号 | ||||
| * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 | |||||
| * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 | |||||
| * @throws WxErrorException | * @throws WxErrorException | ||||
| */ | */ | ||||
| WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; | WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException; | ||||
| @@ -47,6 +48,7 @@ public interface WxMpPayService { | |||||
| * 接口地址:https://api.mch.weixin.qq.com/pay/closeorder | * 接口地址:https://api.mch.weixin.qq.com/pay/closeorder | ||||
| * 是否需要证书: 不需要。 | * 是否需要证书: 不需要。 | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 | * @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。 | ||||
| * @throws WxErrorException | * @throws WxErrorException | ||||
| */ | */ | ||||
| @@ -56,15 +58,16 @@ public interface WxMpPayService { | |||||
| * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) | * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) | ||||
| * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" | * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" | ||||
| * 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder | * 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder | ||||
| * @throws WxErrorException | |||||
| * @param request 请求对象 | |||||
| * | * | ||||
| * @param request 请求对象 | |||||
| * @throws WxErrorException | |||||
| */ | */ | ||||
| WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException; | WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException; | ||||
| /** | /** | ||||
| * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数 | * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数 | ||||
| * 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN | * 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN | ||||
| * | |||||
| * @param request 请求对象 | * @param request 请求对象 | ||||
| */ | */ | ||||
| Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException; | Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException; | ||||
| @@ -75,16 +78,33 @@ public interface WxMpPayService { | |||||
| * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 | * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4 | ||||
| * 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund | * 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param request 请求对象 | * @param request 请求对象 | ||||
| * @param keyFile 证书文件对象 | |||||
| * @param keyFile 证书文件对象 | |||||
| * @return 退款操作结果 | * @return 退款操作结果 | ||||
| */ | */ | ||||
| WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) throws WxErrorException; | WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) throws WxErrorException; | ||||
| /** | |||||
| * <pre> | |||||
| * 微信支付-查询退款 | |||||
| * 应用场景: | |||||
| * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款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 transactionId 微信订单号 | |||||
| * @param outTradeNo 商户订单号 | |||||
| * @param outRefundNo 商户退款单号 | |||||
| * @param refundId 微信退款单号 | |||||
| * @return 退款信息 | |||||
| */ | |||||
| WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxErrorException; | |||||
| /** | /** | ||||
| * 读取支付结果通知 | * 读取支付结果通知 | ||||
| * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 | * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7 | ||||
| * | |||||
| */ | */ | ||||
| WxPayJsSDKCallback getJSSDKCallbackData(String xmlData) throws WxErrorException; | WxPayJsSDKCallback getJSSDKCallbackData(String xmlData) throws WxErrorException; | ||||
| @@ -93,7 +113,6 @@ public interface WxMpPayService { | |||||
| * 计算Map键值对是否和签名相符, | * 计算Map键值对是否和签名相符, | ||||
| * 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串 | * 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串 | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| */ | */ | ||||
| boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature); | boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature); | ||||
| @@ -104,8 +123,9 @@ public interface WxMpPayService { | |||||
| * 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3 | * 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3 | ||||
| * 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4 | * 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4 | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param request 请求对象 | * @param request 请求对象 | ||||
| * @param keyFile 证书文件对象 | |||||
| * @param keyFile 证书文件对象 | |||||
| */ | */ | ||||
| WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) throws WxErrorException; | WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) throws WxErrorException; | ||||
| @@ -118,8 +138,9 @@ public interface WxMpPayService { | |||||
| * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 | * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 | ||||
| * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers | * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param request 请求对象 | * @param request 请求对象 | ||||
| * @param keyFile 证书文件对象 | |||||
| * @param keyFile 证书文件对象 | |||||
| */ | */ | ||||
| WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException; | WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException; | ||||
| @@ -130,8 +151,9 @@ public interface WxMpPayService { | |||||
| * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3 | * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3 | ||||
| * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo | * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param partnerTradeNo 商户订单号 | * @param partnerTradeNo 商户订单号 | ||||
| * @param keyFile 证书文件对象 | |||||
| * @param keyFile 证书文件对象 | |||||
| */ | */ | ||||
| WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException; | WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException; | ||||
| @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||||
| import me.chanjar.weixin.mp.api.WxMpPayService; | import me.chanjar.weixin.mp.api.WxMpPayService; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult; | |||||
| import me.chanjar.weixin.mp.bean.pay.request.*; | import me.chanjar.weixin.mp.bean.pay.request.*; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.*; | import me.chanjar.weixin.mp.bean.pay.result.*; | ||||
| import org.apache.commons.codec.digest.DigestUtils; | import org.apache.commons.codec.digest.DigestUtils; | ||||
| @@ -42,13 +41,11 @@ import java.util.*; | |||||
| */ | */ | ||||
| public class WxMpPayServiceImpl implements WxMpPayService { | public class WxMpPayServiceImpl implements WxMpPayService { | ||||
| protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||||
| private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | ||||
| private static final String[] TRADE_TYPES = new String[]{"JSAPI","NATIVE", "APP"}; | |||||
| private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS", | |||||
| private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"}; | |||||
| private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS", | |||||
| "REFUND_SOURCE_UNSETTLED_FUNDS"}; | "REFUND_SOURCE_UNSETTLED_FUNDS"}; | ||||
| protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||||
| private WxMpService wxMpService; | private WxMpService wxMpService; | ||||
| public WxMpPayServiceImpl(WxMpService wxMpService) { | public WxMpPayServiceImpl(WxMpService wxMpService) { | ||||
| @@ -57,7 +54,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| @Override | @Override | ||||
| public WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) | public WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) | ||||
| throws WxErrorException { | |||||
| throws WxErrorException { | |||||
| checkParameters(request); | checkParameters(request); | ||||
| XStream xstream = XStreamInitializer.getInstance(); | XStream xstream = XStreamInitializer.getInstance(); | ||||
| @@ -67,7 +64,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId()); | request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId()); | ||||
| String partnerId = this.wxMpService.getWxMpConfigStorage().getPartnerId(); | String partnerId = this.wxMpService.getWxMpConfigStorage().getPartnerId(); | ||||
| request.setMchId(partnerId); | request.setMchId(partnerId); | ||||
| request.setNonceStr( System.currentTimeMillis() + ""); | |||||
| request.setNonceStr(System.currentTimeMillis() + ""); | |||||
| request.setOpUserId(partnerId); | request.setOpUserId(partnerId); | ||||
| String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | ||||
| request.setSign(sign); | request.setSign(sign); | ||||
| @@ -79,11 +76,45 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| return result; | return result; | ||||
| } | } | ||||
| @Override | |||||
| public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxErrorException { | |||||
| if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo) && StringUtils.isBlank(outRefundNo) && StringUtils.isBlank(refundId)) || | |||||
| (StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo) && StringUtils.isNotBlank(outRefundNo) && StringUtils.isNotBlank(refundId))) { | |||||
| throw new IllegalArgumentException("transaction_id , out_trade_no,out_refund_no, refund_id 必须四选一"); | |||||
| } | |||||
| XStream xstream = XStreamInitializer.getInstance(); | |||||
| xstream.processAnnotations(WxPayRefundQueryRequest.class); | |||||
| xstream.processAnnotations(WxPayRefundQueryResult.class); | |||||
| WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); | |||||
| request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); | |||||
| request.setTransactionId(StringUtils.trimToNull(transactionId)); | |||||
| request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); | |||||
| request.setRefundId(StringUtils.trimToNull(refundId)); | |||||
| request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId()); | |||||
| request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); | |||||
| request.setNonceStr(System.currentTimeMillis() + ""); | |||||
| String sign = this.createSign(BeanUtils.xmlBean2Map(request), | |||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | |||||
| request.setSign(sign); | |||||
| String url = PAY_BASE_URL + "/pay/refundquery"; | |||||
| String responseContent = this.executeRequest(url, xstream.toXML(request)); | |||||
| WxPayRefundQueryResult result = (WxPayRefundQueryResult) xstream.fromXML(responseContent); | |||||
| result.composeRefundRecords(responseContent); | |||||
| this.checkResult(result); | |||||
| return result; | |||||
| } | |||||
| private void checkResult(WxPayBaseResult result) throws WxErrorException { | private void checkResult(WxPayBaseResult result) throws WxErrorException { | ||||
| if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode()) | if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode()) | ||||
| || !"SUCCESS".equalsIgnoreCase(result.getResultCode())) { | || !"SUCCESS".equalsIgnoreCase(result.getResultCode())) { | ||||
| throw new WxErrorException(WxError.newBuilder().setErrorCode(-1) | throw new WxErrorException(WxError.newBuilder().setErrorCode(-1) | ||||
| .setErrorMsg("返回代码:" + result.getReturnCode() + ", 返回信息: " | |||||
| .setErrorMsg("返回代码: " + result.getReturnCode() + ", 返回信息: " | |||||
| + result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: " | + result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: " | ||||
| + result.getErrCode() + ", 错误详情: " + result.getErrCodeDes()) | + result.getErrCode() + ", 错误详情: " + result.getErrCodeDes()) | ||||
| .build()); | .build()); | ||||
| @@ -94,7 +125,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| BeanUtils.checkRequiredFields(request); | BeanUtils.checkRequiredFields(request); | ||||
| if (StringUtils.isNotBlank(request.getRefundAccount())) { | if (StringUtils.isNotBlank(request.getRefundAccount())) { | ||||
| if(!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())){ | |||||
| if (!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())) { | |||||
| throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) + "其中之一"); | throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) + "其中之一"); | ||||
| } | } | ||||
| } | } | ||||
| @@ -118,14 +149,14 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| @Override | @Override | ||||
| public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, | public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, | ||||
| String signature) { | |||||
| String signature) { | |||||
| return signature.equals(this.createSign(kvm, | return signature.equals(this.createSign(kvm, | ||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey())); | |||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey())); | |||||
| } | } | ||||
| @Override | @Override | ||||
| public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) | public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) | ||||
| throws WxErrorException { | |||||
| throws WxErrorException { | |||||
| XStream xstream = XStreamInitializer.getInstance(); | XStream xstream = XStreamInitializer.getInstance(); | ||||
| xstream.processAnnotations(WxPaySendRedpackRequest.class); | xstream.processAnnotations(WxPaySendRedpackRequest.class); | ||||
| xstream.processAnnotations(WxPaySendRedpackResult.class); | xstream.processAnnotations(WxPaySendRedpackResult.class); | ||||
| @@ -136,7 +167,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| request.setNonceStr(System.currentTimeMillis() + ""); | request.setNonceStr(System.currentTimeMillis() + ""); | ||||
| String sign = this.createSign(BeanUtils.xmlBean2Map(request), | String sign = this.createSign(BeanUtils.xmlBean2Map(request), | ||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | |||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | |||||
| request.setSign(sign); | request.setSign(sign); | ||||
| String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack"; | String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack"; | ||||
| @@ -147,15 +178,16 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), mchId); | String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), mchId); | ||||
| WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream | WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream | ||||
| .fromXML(responseContent); | |||||
| .fromXML(responseContent); | |||||
| this.checkResult(result); | this.checkResult(result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| /** | /** | ||||
| * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3) | * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3) | ||||
| * | |||||
| * @param packageParams 原始参数 | * @param packageParams 原始参数 | ||||
| * @param signKey 加密Key(即 商户Key) | |||||
| * @param signKey 加密Key(即 商户Key) | |||||
| * @return 签名字符串 | * @return 签名字符串 | ||||
| */ | */ | ||||
| private String createSign(Map<String, String> packageParams, String signKey) { | private String createSign(Map<String, String> packageParams, String signKey) { | ||||
| @@ -165,7 +197,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| for (String key : sortedMap.keySet()) { | for (String key : sortedMap.keySet()) { | ||||
| String value = packageParams.get(key); | String value = packageParams.get(key); | ||||
| if (null != value && !"".equals(value) && !"sign".equals(key) | if (null != value && !"".equals(value) && !"sign".equals(key) | ||||
| && !"key".equals(key)) { | |||||
| && !"key".equals(key)) { | |||||
| toSign.append(key + "=" + value + "&"); | toSign.append(key + "=" + value + "&"); | ||||
| } | } | ||||
| } | } | ||||
| @@ -237,7 +269,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| @Override | @Override | ||||
| public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) | public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) | ||||
| throws WxErrorException { | |||||
| throws WxErrorException { | |||||
| checkParameters(request); | checkParameters(request); | ||||
| XStream xstream = XStreamInitializer.getInstance(); | XStream xstream = XStreamInitializer.getInstance(); | ||||
| @@ -249,14 +281,14 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| request.setNonceStr(System.currentTimeMillis() + ""); | request.setNonceStr(System.currentTimeMillis() + ""); | ||||
| String sign = this.createSign(BeanUtils.xmlBean2Map(request), | String sign = this.createSign(BeanUtils.xmlBean2Map(request), | ||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | |||||
| this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | |||||
| request.setSign(sign); | request.setSign(sign); | ||||
| String url = PAY_BASE_URL + "/pay/unifiedorder"; | String url = PAY_BASE_URL + "/pay/unifiedorder"; | ||||
| String responseContent = this.executeRequest(url, xstream.toXML(request)); | String responseContent = this.executeRequest(url, xstream.toXML(request)); | ||||
| WxPayUnifiedOrderResult result = (WxPayUnifiedOrderResult) xstream | WxPayUnifiedOrderResult result = (WxPayUnifiedOrderResult) xstream | ||||
| .fromXML(responseContent); | |||||
| .fromXML(responseContent); | |||||
| this.checkResult(result); | this.checkResult(result); | ||||
| return result; | return result; | ||||
| } | } | ||||
| @@ -264,7 +296,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException { | private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException { | ||||
| BeanUtils.checkRequiredFields(request); | BeanUtils.checkRequiredFields(request); | ||||
| if (! ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) { | |||||
| if (!ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) { | |||||
| throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一"); | throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一"); | ||||
| } | } | ||||
| @@ -283,7 +315,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| String prepayId = unifiedOrderResult.getPrepayId(); | String prepayId = unifiedOrderResult.getPrepayId(); | ||||
| if (StringUtils.isBlank(prepayId)) { | if (StringUtils.isBlank(prepayId)) { | ||||
| throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).", | throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).", | ||||
| unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes())); | |||||
| unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes())); | |||||
| } | } | ||||
| Map<String, String> payInfo = new HashMap<>(); | Map<String, String> payInfo = new HashMap<>(); | ||||
| @@ -347,7 +379,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| return result; | return result; | ||||
| } | } | ||||
| private String executeRequest( String url, String requestStr) throws WxErrorException { | |||||
| private String executeRequest(String url, String requestStr) throws WxErrorException { | |||||
| HttpPost httpPost = new HttpPost(url); | HttpPost httpPost = new HttpPost(url); | ||||
| if (this.wxMpService.getHttpProxy() != null) { | if (this.wxMpService.getHttpProxy() != null) { | ||||
| httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build()); | httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build()); | ||||
| @@ -358,25 +390,25 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| try (CloseableHttpResponse response = httpclient.execute(httpPost)) { | try (CloseableHttpResponse response = httpclient.execute(httpPost)) { | ||||
| String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); | String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); | ||||
| this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",url, requestStr, result); | |||||
| this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); | |||||
| return result; | return result; | ||||
| } | } | ||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage()); | this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage()); | ||||
| throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e); | throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e); | ||||
| }finally { | |||||
| } finally { | |||||
| httpPost.releaseConnection(); | httpPost.releaseConnection(); | ||||
| } | } | ||||
| } | } | ||||
| private String executeRequestWithKeyFile( String url, File keyFile, String requestStr, String mchId) throws WxErrorException { | |||||
| private String executeRequestWithKeyFile(String url, File keyFile, String requestStr, String mchId) throws WxErrorException { | |||||
| try (FileInputStream inputStream = new FileInputStream(keyFile)) { | try (FileInputStream inputStream = new FileInputStream(keyFile)) { | ||||
| KeyStore keyStore = KeyStore.getInstance("PKCS12"); | KeyStore keyStore = KeyStore.getInstance("PKCS12"); | ||||
| keyStore.load(inputStream, mchId.toCharArray()); | keyStore.load(inputStream, mchId.toCharArray()); | ||||
| SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build(); | SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build(); | ||||
| SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, | |||||
| new DefaultHostnameVerifier()); | |||||
| SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, | |||||
| new DefaultHostnameVerifier()); | |||||
| HttpPost httpPost = new HttpPost(url); | HttpPost httpPost = new HttpPost(url); | ||||
| if (this.wxMpService.getHttpProxy() != null) { | if (this.wxMpService.getHttpProxy() != null) { | ||||
| @@ -387,10 +419,10 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
| httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1"))); | httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1"))); | ||||
| try (CloseableHttpResponse response = httpclient.execute(httpPost)) { | try (CloseableHttpResponse response = httpclient.execute(httpPost)) { | ||||
| String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); | String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); | ||||
| this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",url, requestStr, result); | |||||
| this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); | |||||
| return result; | return result; | ||||
| } | } | ||||
| }finally { | |||||
| } finally { | |||||
| httpPost.releaseConnection(); | httpPost.releaseConnection(); | ||||
| } | } | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| @@ -0,0 +1,135 @@ | |||||
| package me.chanjar.weixin.mp.bean.pay.request; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| /** | |||||
| * <pre> | |||||
| * Created by Binary Wang on 2016-11-24. | |||||
| * @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("xml") | |||||
| public class WxPayRefundQueryRequest extends WxPayBaseRequest { | |||||
| /** | |||||
| * <pre> | |||||
| * 设备号 | |||||
| * device_info | |||||
| * 否 | |||||
| * String(32) | |||||
| * 013467007045764 | |||||
| * 商户自定义的终端设备号,如门店编号、设备的ID等 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("device_info") | |||||
| private String deviceInfo; | |||||
| /** | |||||
| * <pre> | |||||
| * 签名类型 | |||||
| * sign_type | |||||
| * 否 | |||||
| * String(32) | |||||
| * HMAC-SHA256 | |||||
| * 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("sign_type") | |||||
| private String signType; | |||||
| //************以下四选一************ | |||||
| /** | |||||
| * <pre> | |||||
| * 微信订单号 | |||||
| * transaction_id | |||||
| * String(32) | |||||
| * 1217752501201407033233368018 | |||||
| * 微信订单号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("transaction_id") | |||||
| private String transactionId; | |||||
| /** | |||||
| * <pre> | |||||
| * 商户订单号 | |||||
| * out_trade_no | |||||
| * String(32) | |||||
| * 1217752501201407033233368018 | |||||
| * 商户系统内部的订单号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("out_trade_no") | |||||
| private String outTradeNo; | |||||
| /** | |||||
| * <pre> | |||||
| * 商户退款单号 | |||||
| * out_refund_no | |||||
| * String(32) | |||||
| * 1217752501201407033233368018 | |||||
| * 商户侧传给微信的退款单号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("out_refund_no") | |||||
| private String outRefundNo; | |||||
| /** | |||||
| * <pre> | |||||
| * 微信退款单号 | |||||
| * refund_id | |||||
| * String(28) | |||||
| * 1217752501201407033233368018 | |||||
| * 微信生成的退款单号,在申请退款接口有返回 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_id") | |||||
| private String refundId; | |||||
| public String getDeviceInfo() { | |||||
| return deviceInfo; | |||||
| } | |||||
| public void setDeviceInfo(String deviceInfo) { | |||||
| this.deviceInfo = deviceInfo; | |||||
| } | |||||
| public String getSignType() { | |||||
| return signType; | |||||
| } | |||||
| public void setSignType(String signType) { | |||||
| this.signType = signType; | |||||
| } | |||||
| public String getTransactionId() { | |||||
| return transactionId; | |||||
| } | |||||
| public void setTransactionId(String transactionId) { | |||||
| this.transactionId = transactionId; | |||||
| } | |||||
| public String getOutTradeNo() { | |||||
| return outTradeNo; | |||||
| } | |||||
| public void setOutTradeNo(String outTradeNo) { | |||||
| this.outTradeNo = outTradeNo; | |||||
| } | |||||
| public String getOutRefundNo() { | |||||
| return outRefundNo; | |||||
| } | |||||
| public void setOutRefundNo(String outRefundNo) { | |||||
| this.outRefundNo = outRefundNo; | |||||
| } | |||||
| public String getRefundId() { | |||||
| return refundId; | |||||
| } | |||||
| public void setRefundId(String refundId) { | |||||
| this.refundId = refundId; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,488 @@ | |||||
| package me.chanjar.weixin.mp.bean.pay.result; | |||||
| import com.google.common.collect.Lists; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| import java.util.List; | |||||
| /** | |||||
| * <pre> | |||||
| * Created by Binary Wang on 2016-11-24. | |||||
| * @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("xml") | |||||
| public class WxPayRefundQueryResult extends WxPayBaseResult { | |||||
| /** | |||||
| * <pre> | |||||
| * 设备号 | |||||
| * device_info | |||||
| * 否 | |||||
| * String(32) | |||||
| * 013467007045764 | |||||
| * 终端设备号 | |||||
| */ | |||||
| @XStreamAlias("device_info") | |||||
| private String deviceInfo; | |||||
| /** | |||||
| * <pre> | |||||
| * 微信订单号 | |||||
| * transaction_id | |||||
| * 是 | |||||
| * String(32) | |||||
| * 1217752501201407033233368018 | |||||
| * 微信订单号 | |||||
| */ | |||||
| @XStreamAlias("transaction_id") | |||||
| private String transactionId; | |||||
| /** | |||||
| * <pre> | |||||
| * 商户订单号 | |||||
| * out_trade_no | |||||
| * 是 | |||||
| * String(32) | |||||
| * 1217752501201407033233368018 | |||||
| * 商户系统内部的订单号 | |||||
| */ | |||||
| @XStreamAlias("out_trade_no") | |||||
| private String outTradeNo; | |||||
| /** | |||||
| * <pre> | |||||
| * 订单金额 | |||||
| * total_fee | |||||
| * 是 | |||||
| * Int | |||||
| * 100 | |||||
| * 订单总金额,单位为分,只能为整数,详见支付金额 | |||||
| */ | |||||
| @XStreamAlias("total_fee") | |||||
| private Integer totalFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 应结订单金额 | |||||
| * settlement_total_fee | |||||
| * 否 | |||||
| * Int | |||||
| * 100 | |||||
| * 应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。 | |||||
| */ | |||||
| @XStreamAlias("settlement_total_fee") | |||||
| private Integer settlementTotalFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 货币种类 | |||||
| * fee_type | |||||
| * 否 | |||||
| * String(8) | |||||
| * CNY | |||||
| * 订单金额货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 | |||||
| */ | |||||
| @XStreamAlias("fee_type") | |||||
| private String feeType; | |||||
| /** | |||||
| * <pre> | |||||
| * 现金支付金额 | |||||
| * cash_fee | |||||
| * 是 | |||||
| * Int | |||||
| * 100 | |||||
| * 现金支付金额,单位为分,只能为整数,详见支付金额 | |||||
| */ | |||||
| @XStreamAlias("cash_fee") | |||||
| private Integer cashFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款笔数 | |||||
| * refund_count | |||||
| * 是 | |||||
| * Int | |||||
| * 1 | |||||
| * 退款记录数 | |||||
| */ | |||||
| @XStreamAlias("refund_count") | |||||
| private Integer refundCount; | |||||
| private List<RefundRecord> refundRecords; | |||||
| public String getDeviceInfo() { | |||||
| return deviceInfo; | |||||
| } | |||||
| public void setDeviceInfo(String deviceInfo) { | |||||
| this.deviceInfo = deviceInfo; | |||||
| } | |||||
| public String getTransactionId() { | |||||
| return transactionId; | |||||
| } | |||||
| public void setTransactionId(String transactionId) { | |||||
| this.transactionId = transactionId; | |||||
| } | |||||
| public String getOutTradeNo() { | |||||
| return outTradeNo; | |||||
| } | |||||
| public void setOutTradeNo(String outTradeNo) { | |||||
| this.outTradeNo = outTradeNo; | |||||
| } | |||||
| public Integer getTotalFee() { | |||||
| return totalFee; | |||||
| } | |||||
| public void setTotalFee(Integer totalFee) { | |||||
| this.totalFee = totalFee; | |||||
| } | |||||
| public Integer getSettlementTotalFee() { | |||||
| return settlementTotalFee; | |||||
| } | |||||
| public void setSettlementTotalFee(Integer settlementTotalFee) { | |||||
| this.settlementTotalFee = settlementTotalFee; | |||||
| } | |||||
| public String getFeeType() { | |||||
| return feeType; | |||||
| } | |||||
| public void setFeeType(String feeType) { | |||||
| this.feeType = feeType; | |||||
| } | |||||
| public Integer getCashFee() { | |||||
| return cashFee; | |||||
| } | |||||
| public void setCashFee(Integer cashFee) { | |||||
| this.cashFee = cashFee; | |||||
| } | |||||
| public Integer getRefundCount() { | |||||
| return refundCount; | |||||
| } | |||||
| public void setRefundCount(Integer refundCount) { | |||||
| this.refundCount = refundCount; | |||||
| } | |||||
| public List<RefundRecord> getRefundRecords() { | |||||
| return refundRecords; | |||||
| } | |||||
| public void setRefundRecords(List<RefundRecord> refundRecords) { | |||||
| this.refundRecords = refundRecords; | |||||
| } | |||||
| public static class RefundRecord { | |||||
| /** | |||||
| * <pre> | |||||
| * 商户退款单号 | |||||
| * out_refund_no_$n | |||||
| * 是 | |||||
| * String(32) | |||||
| * 1217752501201407033233368018 | |||||
| * 商户退款单号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("out_refund_no") | |||||
| private String outRefundNo; | |||||
| /** | |||||
| * <pre> | |||||
| * 微信退款单号 | |||||
| * refund_id_$n | |||||
| * 是 | |||||
| * String(28) | |||||
| * 1217752501201407033233368018 | |||||
| * 微信退款单号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_id") | |||||
| private String refundId; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款渠道 | |||||
| * refund_channel_$n | |||||
| * 否 | |||||
| * String(16) | |||||
| * ORIGINAL | |||||
| * ORIGINAL—原路退款 BALANCE—退回到余额 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_channel") | |||||
| private String refundChannel; | |||||
| /** | |||||
| * <pre> | |||||
| * 申请退款金额 | |||||
| * refund_fee_$n | |||||
| * 是 | |||||
| * Int | |||||
| * 100 | |||||
| * 退款总金额,单位为分,可以做部分退款 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_fee") | |||||
| private String refundFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款金额 | |||||
| * settlement_refund_fee_$n | |||||
| * 否 | |||||
| * Int | |||||
| * 100 | |||||
| * 退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("settlement_refund_fee") | |||||
| private String settlementRefundFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款资金来源 | |||||
| * refund_account | |||||
| * 否 | |||||
| * String(30) | |||||
| * REFUND_SOURCE_RECHARGE_FUNDS | |||||
| * REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款/基本账户, REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_account") | |||||
| private String refundAccount; | |||||
| /** | |||||
| * <pre> | |||||
| * 代金券类型 | |||||
| * coupon_type_$n | |||||
| * 否 | |||||
| * Int | |||||
| * CASH | |||||
| * CASH--充值代金券 , NO_CASH---非充值代金券。订单使用代金券时有返回(取值:CASH、NO_CASH)。$n为下标,从0开始编号,举例:coupon_type_$0 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_type") | |||||
| private String couponType; | |||||
| /** | |||||
| * <pre> | |||||
| * 代金券退款金额 | |||||
| * coupon_refund_fee_$n | |||||
| * 否 | |||||
| * Int | |||||
| * 100 | |||||
| * 代金券退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_fee") | |||||
| private String couponRefundFee; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款代金券使用数量 | |||||
| * coupon_refund_count_$n | |||||
| * 否 | |||||
| * Int | |||||
| * 1 | |||||
| * 退款代金券使用数量 ,$n为下标,从0开始编号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_count") | |||||
| private String couponRefundCount; | |||||
| private List<RefundCoupon> refundCoupons; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款状态 | |||||
| * refund_status_$n | |||||
| * 是 | |||||
| * String(16) | |||||
| * SUCCESS | |||||
| * 退款状态: | |||||
| * SUCCESS—退款成功, | |||||
| * FAIL—退款失败, | |||||
| * PROCESSING—退款处理中, | |||||
| * CHANGE—转入代发, | |||||
| * 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款。 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_status") | |||||
| private String refundStatus; | |||||
| /** | |||||
| * <pre> | |||||
| * 退款入账账户 | |||||
| * refund_recv_accout_$n | |||||
| * 是 | |||||
| * String(64) | |||||
| * 招商银行信用卡0403 | |||||
| * 取当前退款单的退款入账方,1)退回银行卡:{银行名称}{卡类型}{卡尾号},2)退回支付用户零钱:支付用户零钱 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("refund_recv_accout") | |||||
| private String refundRecvAccout; | |||||
| public String getOutRefundNo() { | |||||
| return outRefundNo; | |||||
| } | |||||
| public void setOutRefundNo(String outRefundNo) { | |||||
| this.outRefundNo = outRefundNo; | |||||
| } | |||||
| public String getRefundId() { | |||||
| return refundId; | |||||
| } | |||||
| public void setRefundId(String refundId) { | |||||
| this.refundId = refundId; | |||||
| } | |||||
| public String getRefundChannel() { | |||||
| return refundChannel; | |||||
| } | |||||
| public void setRefundChannel(String refundChannel) { | |||||
| this.refundChannel = refundChannel; | |||||
| } | |||||
| public String getRefundFee() { | |||||
| return refundFee; | |||||
| } | |||||
| public void setRefundFee(String refundFee) { | |||||
| this.refundFee = refundFee; | |||||
| } | |||||
| public String getSettlementRefundFee() { | |||||
| return settlementRefundFee; | |||||
| } | |||||
| public void setSettlementRefundFee(String settlementRefundFee) { | |||||
| this.settlementRefundFee = settlementRefundFee; | |||||
| } | |||||
| public String getRefundAccount() { | |||||
| return refundAccount; | |||||
| } | |||||
| public void setRefundAccount(String refundAccount) { | |||||
| this.refundAccount = refundAccount; | |||||
| } | |||||
| public String getCouponType() { | |||||
| return couponType; | |||||
| } | |||||
| public void setCouponType(String couponType) { | |||||
| this.couponType = couponType; | |||||
| } | |||||
| public String getCouponRefundFee() { | |||||
| return couponRefundFee; | |||||
| } | |||||
| public void setCouponRefundFee(String couponRefundFee) { | |||||
| this.couponRefundFee = couponRefundFee; | |||||
| } | |||||
| public String getCouponRefundCount() { | |||||
| return couponRefundCount; | |||||
| } | |||||
| public void setCouponRefundCount(String couponRefundCount) { | |||||
| this.couponRefundCount = couponRefundCount; | |||||
| } | |||||
| public List<RefundCoupon> getRefundCoupons() { | |||||
| return refundCoupons; | |||||
| } | |||||
| public void setRefundCoupons(List<RefundCoupon> refundCoupons) { | |||||
| this.refundCoupons = refundCoupons; | |||||
| } | |||||
| public String getRefundStatus() { | |||||
| return refundStatus; | |||||
| } | |||||
| public void setRefundStatus(String refundStatus) { | |||||
| this.refundStatus = refundStatus; | |||||
| } | |||||
| public String getRefundRecvAccout() { | |||||
| return refundRecvAccout; | |||||
| } | |||||
| public void setRefundRecvAccout(String refundRecvAccout) { | |||||
| this.refundRecvAccout = refundRecvAccout; | |||||
| } | |||||
| public static class RefundCoupon { | |||||
| /** | |||||
| * <pre> | |||||
| * 退款代金券批次ID | |||||
| * coupon_refund_batch_id_$n_$m | |||||
| * 否 | |||||
| * String(20) | |||||
| * 100 | |||||
| * 退款代金券批次ID ,$n为下标,$m为下标,从0开始编号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("coupon_refund_batch_id") | |||||
| private String couponRefundBatchId; | |||||
| /** | |||||
| * <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 String couponRefundFee; | |||||
| public RefundCoupon(String couponRefundBatchId, String couponRefundId, String couponRefundFee) { | |||||
| this.couponRefundBatchId = couponRefundBatchId; | |||||
| this.couponRefundId = couponRefundId; | |||||
| this.couponRefundFee = couponRefundFee; | |||||
| } | |||||
| } | |||||
| } | |||||
| public void composeRefundRecords(String xmlString){ | |||||
| if(this.refundCount != null && this.refundCount > 0 ){ | |||||
| this.refundRecords = Lists.newArrayList(); | |||||
| //TODO 暂时待实现 | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -9,6 +9,7 @@ import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest; | |||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest; | import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayRefundQueryResult; | |||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayRefundResult; | import me.chanjar.weixin.mp.bean.pay.result.WxPayRefundResult; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPaySendRedpackResult; | import me.chanjar.weixin.mp.bean.pay.result.WxPaySendRedpackResult; | ||||
| import me.chanjar.weixin.mp.bean.pay.result.WxPayUnifiedOrderResult; | import me.chanjar.weixin.mp.bean.pay.result.WxPayUnifiedOrderResult; | ||||
| @@ -20,6 +21,7 @@ import java.io.File; | |||||
| /** | /** | ||||
| * 测试支付相关接口 | * 测试支付相关接口 | ||||
| * Created by Binary Wang on 2016/7/28. | * Created by Binary Wang on 2016/7/28. | ||||
| * | |||||
| * @author binarywang (https://github.com/binarywang) | * @author binarywang (https://github.com/binarywang) | ||||
| */ | */ | ||||
| @Test | @Test | ||||
| @@ -46,6 +48,20 @@ public class WxMpPayServiceImplTest { | |||||
| System.err.println(result); | System.err.println(result); | ||||
| } | } | ||||
| @Test | |||||
| public void testRefundQuery() throws Exception { | |||||
| WxPayRefundQueryResult result = this.wxService.getPayService().refundQuery("1", "", "", ""); | |||||
| result = this.wxService.getPayService().refundQuery("", "2", "", ""); | |||||
| System.err.println(result); | |||||
| result = this.wxService.getPayService().refundQuery("", "", "3", ""); | |||||
| System.err.println(result); | |||||
| result = this.wxService.getPayService().refundQuery("", "", "", "4"); | |||||
| System.err.println(result); | |||||
| //测试四个参数都填的情况,应该报异常的 | |||||
| result = this.wxService.getPayService().refundQuery("1", "2", "3", "4"); | |||||
| System.err.println(result); | |||||
| } | |||||
| @Test | @Test | ||||
| public void testCheckJSSDKCallbackDataSignature() throws Exception { | public void testCheckJSSDKCallbackDataSignature() throws Exception { | ||||
| @@ -58,7 +74,7 @@ public class WxMpPayServiceImplTest { | |||||
| request.setClientIp("aaa"); | request.setClientIp("aaa"); | ||||
| request.setMchBillno("aaaa"); | request.setMchBillno("aaaa"); | ||||
| request | request | ||||
| .setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid()); | |||||
| .setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid()); | |||||
| File keyFile = new File("E:\\dlt.p12"); | File keyFile = new File("E:\\dlt.p12"); | ||||
| WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request, keyFile); | WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request, keyFile); | ||||
| System.err.println(redpackResult); | System.err.println(redpackResult); | ||||
| @@ -70,9 +86,9 @@ public class WxMpPayServiceImplTest { | |||||
| @Test | @Test | ||||
| public void testUnifiedOrder() throws WxErrorException { | public void testUnifiedOrder() throws WxErrorException { | ||||
| WxPayUnifiedOrderResult result = this.wxService.getPayService() | WxPayUnifiedOrderResult result = this.wxService.getPayService() | ||||
| .unifiedOrder(WxPayUnifiedOrderRequest.builder().body("1111111") | |||||
| .totalFee(1).spbillCreateIp("111111").notifyURL("111111") | |||||
| .tradeType("JSAPI").openid("122").outTradeNo("111111").build()); | |||||
| .unifiedOrder(WxPayUnifiedOrderRequest.builder().body("1111111") | |||||
| .totalFee(1).spbillCreateIp("111111").notifyURL("111111") | |||||
| .tradeType("JSAPI").openid("122").outTradeNo("111111").build()); | |||||
| System.err.println(result); | System.err.println(result); | ||||
| } | } | ||||