Bläddra i källkod

部分实现微信支付查询退款的接口 for #59

master
Binary Wang 8 år sedan
förälder
incheckning
1bc2a5c7b3
5 ändrade filer med 743 tillägg och 50 borttagningar
  1. +38
    -16
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java
  2. +62
    -30
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
  3. +135
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayRefundQueryRequest.java
  4. +488
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayRefundQueryResult.java
  5. +20
    -4
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java

+ 38
- 16
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java Visa fil

@@ -2,7 +2,6 @@ package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
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.WxPayRefundRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest;
@@ -13,8 +12,9 @@ import java.io.File;
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)
*/
public interface WxMpPayService {
@@ -24,14 +24,15 @@ public interface WxMpPayService {
* 查询订单(详见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
* </pre>
*
* @param transactionId 微信支付分配的商户号
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
* @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
* 是否需要证书: 不需要。
* </pre>
*
* @param outTradeNo 商户系统内部的订单号,当没提供transaction_id时需要传这个。
* @throws WxErrorException
*/
@@ -56,15 +58,16 @@ public interface WxMpPayService {
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
* 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
* @throws WxErrorException
* @param request 请求对象
*
* @param 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
*
* @param request 请求对象
*/
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://api.mch.weixin.qq.com/secapi/pay/refund
* </pre>
*
* @param request 请求对象
* @param keyFile 证书文件对象
* @param keyFile 证书文件对象
* @return 退款操作结果
*/
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
*
*/
WxPayJsSDKCallback getJSSDKCallbackData(String xmlData) throws WxErrorException;

@@ -93,7 +113,6 @@ public interface WxMpPayService {
* 计算Map键值对是否和签名相符,
* 按照字段名的 ASCII 码从小到大排序(字典序)后,使用 URL 键值对的 格式(即 key1=value1&key2=value2...)拼接成字符串
* </pre>
*
*/
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_5&index=4
* </pre>
*
* @param request 请求对象
* @param keyFile 证书文件对象
* @param keyFile 证书文件对象
*/
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://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
* </pre>
*
* @param request 请求对象
* @param keyFile 证书文件对象
* @param keyFile 证书文件对象
*/
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://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
* </pre>
*
* @param partnerTradeNo 商户订单号
* @param keyFile 证书文件对象
* @param keyFile 证书文件对象
*/
WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException;



+ 62
- 30
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java Visa fil

@@ -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.WxMpService;
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.result.*;
import org.apache.commons.codec.digest.DigestUtils;
@@ -42,13 +41,11 @@ import java.util.*;
*/
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[] 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"};
protected final Logger log = LoggerFactory.getLogger(this.getClass());
private WxMpService wxMpService;

public WxMpPayServiceImpl(WxMpService wxMpService) {
@@ -57,7 +54,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {

@Override
public WxPayRefundResult refund(WxPayRefundRequest request, File keyFile)
throws WxErrorException {
throws WxErrorException {
checkParameters(request);

XStream xstream = XStreamInitializer.getInstance();
@@ -67,7 +64,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
String partnerId = this.wxMpService.getWxMpConfigStorage().getPartnerId();
request.setMchId(partnerId);
request.setNonceStr( System.currentTimeMillis() + "");
request.setNonceStr(System.currentTimeMillis() + "");
request.setOpUserId(partnerId);
String sign = this.createSign(BeanUtils.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
@@ -79,11 +76,45 @@ public class WxMpPayServiceImpl implements WxMpPayService {
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 {
if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode())
|| !"SUCCESS".equalsIgnoreCase(result.getResultCode())) {
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1)
.setErrorMsg("返回代码:" + result.getReturnCode() + ", 返回信息: "
.setErrorMsg("返回代码: " + result.getReturnCode() + ", 返回信息: "
+ result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: "
+ result.getErrCode() + ", 错误详情: " + result.getErrCodeDes())
.build());
@@ -94,7 +125,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
BeanUtils.checkRequiredFields(request);

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) + "其中之一");
}
}
@@ -118,14 +149,14 @@ public class WxMpPayServiceImpl implements WxMpPayService {

@Override
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm,
String signature) {
String signature) {
return signature.equals(this.createSign(kvm,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
}

@Override
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile)
throws WxErrorException {
throws WxErrorException {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxPaySendRedpackRequest.class);
xstream.processAnnotations(WxPaySendRedpackResult.class);
@@ -136,7 +167,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

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);
WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream
.fromXML(responseContent);
.fromXML(responseContent);
this.checkResult(result);
return result;
}

/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @param signKey 加密Key(即 商户Key)
* @return 签名字符串
*/
private String createSign(Map<String, String> packageParams, String signKey) {
@@ -165,7 +197,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
for (String key : sortedMap.keySet()) {
String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}
@@ -237,7 +269,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {

@Override
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request)
throws WxErrorException {
throws WxErrorException {
checkParameters(request);

XStream xstream = XStreamInitializer.getInstance();
@@ -249,14 +281,14 @@ public class WxMpPayServiceImpl implements WxMpPayService {
request.setNonceStr(System.currentTimeMillis() + "");

String sign = this.createSign(BeanUtils.xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);

String url = PAY_BASE_URL + "/pay/unifiedorder";

String responseContent = this.executeRequest(url, xstream.toXML(request));
WxPayUnifiedOrderResult result = (WxPayUnifiedOrderResult) xstream
.fromXML(responseContent);
.fromXML(responseContent);
this.checkResult(result);
return result;
}
@@ -264,7 +296,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException {
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) + "其中之一");
}

@@ -283,7 +315,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
String prepayId = unifiedOrderResult.getPrepayId();
if (StringUtils.isBlank(prepayId)) {
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<>();
@@ -347,7 +379,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
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);
if (this.wxMpService.getHttpProxy() != null) {
httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build());
@@ -358,25 +390,25 @@ public class WxMpPayServiceImpl implements WxMpPayService {

try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
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;
}
} catch (IOException e) {
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);
}finally {
} finally {
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)) {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(inputStream, mchId.toCharArray());

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);
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")));
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
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;
}
}finally {
} finally {
httpPost.releaseConnection();
}
} catch (Exception e) {


+ 135
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/request/WxPayRefundQueryRequest.java Visa fil

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

+ 488
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/result/WxPayRefundQueryResult.java Visa fil

@@ -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 暂时待实现
}
}
}


+ 20
- 4
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java Visa fil

@@ -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.WxPaySendRedpackRequest;
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.WxPaySendRedpackResult;
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.
*
* @author binarywang (https://github.com/binarywang)
*/
@Test
@@ -46,6 +48,20 @@ public class WxMpPayServiceImplTest {
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
public void testCheckJSSDKCallbackDataSignature() throws Exception {

@@ -58,7 +74,7 @@ public class WxMpPayServiceImplTest {
request.setClientIp("aaa");
request.setMchBillno("aaaa");
request
.setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid());
.setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid());
File keyFile = new File("E:\\dlt.p12");
WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request, keyFile);
System.err.println(redpackResult);
@@ -70,9 +86,9 @@ public class WxMpPayServiceImplTest {
@Test
public void testUnifiedOrder() throws WxErrorException {
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);
}



Laddar…
Avbryt
Spara