From 5fe1c061f27f1abde29078a2a1454097a578eb45 Mon Sep 17 00:00:00 2001 From: BinaryWang Date: Sat, 8 Oct 2016 17:07:36 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E7=94=B3=E8=AF=B7=E9=80=80=E6=AC=BE=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=20for=20issue=20#25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/api/WxMpPayService.java | 35 +- .../mp/api/impl/WxMpPayServiceImpl.java | 147 ++++----- .../weixin/mp/api/impl/WxMpServiceImpl.java | 63 +--- .../mp/bean/pay/WxMpPayRefundRequest.java | 301 ++++++++++++++++++ .../mp/api/impl/WxMpPayServiceImplTest.java | 26 +- 5 files changed, 413 insertions(+), 159 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxMpPayRefundRequest.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java index cf5bb8c3..45973443 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java @@ -1,19 +1,11 @@ package me.chanjar.weixin.mp.api; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.pay.*; + import java.io.File; import java.util.Map; -import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.mp.bean.pay.WxEntPayRequest; -import me.chanjar.weixin.mp.bean.pay.WxEntPayResult; -import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback; -import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult; -import me.chanjar.weixin.mp.bean.pay.WxMpPayResult; -import me.chanjar.weixin.mp.bean.pay.WxRedpackResult; -import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest; -import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest; -import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult; - /** * 微信支付相关接口 * Created by Binary Wang on 2016/7/28. @@ -25,7 +17,7 @@ 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 + * @throws WxErrorException * */ WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request) @@ -42,7 +34,7 @@ public interface WxMpPayService { /** * 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 - * @throws WxErrorException + * @throws WxErrorException * */ WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo) @@ -56,18 +48,15 @@ public interface WxMpPayService { WxMpPayCallback getJSSDKCallbackData(String xmlData); /** + *
    * 微信支付-申请退款
    * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
-   *
-   * @param parameters 需要传入的退款参数的Map。以下几项为参数的必须项:
- *
  • transaction_id - *
  • out_trade_no (仅在上述transaction_id为空时是必须项) - *
  • out_refund_no - *
  • total_fee - *
  • refund_fee + * 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund + *
  • + * @param keyFile 证书文件对象 * @return 退款操作结果 */ - WxMpPayRefundResult refundPay(Map parameters) throws WxErrorException; + WxMpPayRefundResult refund(WxMpPayRefundRequest request, File keyFile) throws WxErrorException; /** *
    @@ -80,7 +69,7 @@ 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
    @@ -89,7 +78,7 @@ public interface WxMpPayService {
       WxRedpackResult sendRedpack(WxSendRedpackRequest request) throws WxErrorException;
     
       /**
    -   * 
     
    +   * 
        * 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
        * 比如目前的保险行业向客户退保、给付、理赔。
        * 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
    index 79e2c312..a8d5dc3f 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
    @@ -1,19 +1,18 @@
     package me.chanjar.weixin.mp.api.impl;
     
    -import java.io.File;
    -import java.io.FileInputStream;
    -import java.lang.reflect.Field;
    -import java.security.KeyStore;
    -import java.util.HashMap;
    -import java.util.List;
    -import java.util.Map;
    -import java.util.Map.Entry;
    -import java.util.SortedMap;
    -import java.util.TreeMap;
    -
    -import javax.net.ssl.SSLContext;
    -
    +import com.google.common.collect.Lists;
    +import com.google.common.collect.Maps;
    +import com.thoughtworks.xstream.XStream;
    +import com.thoughtworks.xstream.annotations.XStreamAlias;
    +import me.chanjar.weixin.common.annotation.Required;
    +import me.chanjar.weixin.common.bean.result.WxError;
    +import me.chanjar.weixin.common.exception.WxErrorException;
    +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.*;
     import org.apache.commons.codec.digest.DigestUtils;
    +import org.apache.commons.lang3.ArrayUtils;
     import org.apache.commons.lang3.StringUtils;
     import org.apache.http.client.methods.CloseableHttpResponse;
     import org.apache.http.client.methods.HttpPost;
    @@ -26,26 +25,13 @@ import org.apache.http.ssl.SSLContexts;
     import org.apache.http.util.EntityUtils;
     import org.joor.Reflect;
     
    -import com.google.common.collect.Lists;
    -import com.google.common.collect.Maps;
    -import com.thoughtworks.xstream.XStream;
    -import com.thoughtworks.xstream.annotations.XStreamAlias;
    -
    -import me.chanjar.weixin.common.annotation.Required;
    -import me.chanjar.weixin.common.bean.result.WxError;
    -import me.chanjar.weixin.common.exception.WxErrorException;
    -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.WxEntPayRequest;
    -import me.chanjar.weixin.mp.bean.pay.WxEntPayResult;
    -import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback;
    -import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult;
    -import me.chanjar.weixin.mp.bean.pay.WxMpPayResult;
    -import me.chanjar.weixin.mp.bean.pay.WxRedpackResult;
    -import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest;
    -import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest;
    -import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult;
    +import javax.net.ssl.SSLContext;
    +import java.io.File;
    +import java.io.FileInputStream;
    +import java.lang.reflect.Field;
    +import java.security.KeyStore;
    +import java.util.*;
    +import java.util.Map.Entry;
     
     /**
      * Created by Binary Wang on 2016/7/28.
    @@ -55,8 +41,10 @@ import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult;
     public class WxMpPayServiceImpl implements WxMpPayService {
     
       private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
    -  private static final List TRADE_TYPES = Lists.newArrayList("JSAPI",
    -      "NATIVE", "APP");
    +  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"};
    +
       private WxMpService wxMpService;
     
       public WxMpPayServiceImpl(WxMpService wxMpService) {
    @@ -115,33 +103,25 @@ public class WxMpPayServiceImpl implements WxMpPayService {
       }
     
       @Override
    -  public WxMpPayRefundResult refundPay(Map parameters)
    +  public WxMpPayRefundResult refund(WxMpPayRefundRequest request, File keyFile)
           throws WxErrorException {
    -    SortedMap refundParams = new TreeMap<>(parameters);
    -    refundParams.put("appid",
    -        this.wxMpService.getWxMpConfigStorage().getAppId());
    -    refundParams.put("mch_id",
    -        this.wxMpService.getWxMpConfigStorage().getPartnerId());
    -    refundParams.put("nonce_str", System.currentTimeMillis() + "");
    -    refundParams.put("op_user_id",
    -        this.wxMpService.getWxMpConfigStorage().getPartnerId());
    -    String sign = this.createSign(refundParams,
    -        this.wxMpService.getWxMpConfigStorage().getPartnerKey());
    -    refundParams.put("sign", sign);
    -
    -    StringBuilder request = new StringBuilder("");
    -    for (Map.Entry para : refundParams.entrySet()) {
    -      request.append(String.format("<%s>%s", para.getKey(),
    -          para.getValue(), para.getKey()));
    -    }
    -    request.append("");
    +    checkParameters(request);
     
    -    String url = PAY_BASE_URL + "/secapi/pay/refund";
    -    String responseContent = this.wxMpService.post(url, request.toString());
         XStream xstream = XStreamInitializer.getInstance();
         xstream.processAnnotations(WxMpPayRefundResult.class);
    -    WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream
    -        .fromXML(responseContent);
    +    xstream.processAnnotations(WxMpPayRefundRequest.class);
    +
    +    request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
    +    String partnerId = this.wxMpService.getWxMpConfigStorage().getPartnerId();
    +    request.setMchId(partnerId);
    +    request.setNonceStr( System.currentTimeMillis() + "");
    +    request.setOpUserId(partnerId);
    +    String sign = this.createSign(this.xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
    +    request.setSign(sign);
    +
    +    String url = PAY_BASE_URL + "/secapi/pay/refund";
    +    String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request), keyFile, partnerId);
    +    WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream.fromXML(responseContent);
     
         if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode())
             || !"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) {
    @@ -158,6 +138,20 @@ public class WxMpPayServiceImpl implements WxMpPayService {
         return wxMpPayRefundResult;
       }
     
    +  private void checkParameters(WxMpPayRefundRequest request) {
    +    checkNotNullParams(request);
    +
    +    if (StringUtils.isNotBlank(request.getRefundAccount())) {
    +      if(!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())){
    +        throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) + "其中之一");
    +      }
    +    }
    +
    +    if (StringUtils.isBlank(request.getOutTradeNo()) && StringUtils.isBlank(request.getTransactionId())) {
    +      throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时为空,必须提供一个");
    +    }
    +  }
    +
       @Override
       public boolean checkJSSDKCallbackDataSignature(Map kvm,
           String signature) {
    @@ -176,7 +170,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
         request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
         request.setNonceStr(System.currentTimeMillis() + "");
     
    -    String sign = this.createSign(xmlBean2Map(request),
    +    String sign = this.createSign(this.xmlBean2Map(request),
             this.wxMpService.getWxMpConfigStorage().getPartnerKey());
         request.setSign(sign);
     
    @@ -258,7 +252,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
         request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
         request.setNonceStr(System.currentTimeMillis() + "");
     
    -    String sign = this.createSign(xmlBean2Map(request),
    +    String sign = this.createSign(this.xmlBean2Map(request),
             this.wxMpService.getWxMpConfigStorage().getPartnerKey());
         request.setSign(sign);
     
    @@ -274,16 +268,13 @@ public class WxMpPayServiceImpl implements WxMpPayService {
         }
     
         return result;
    -
       }
     
       private void checkParameters(WxUnifiedOrderRequest request) {
    -
         checkNotNullParams(request);
     
    -    if (!TRADE_TYPES.contains(request.getTradeType())) {
    -      throw new IllegalArgumentException("trade_type目前必须为" + TRADE_TYPES + "其中之一");
    -
    +    if (! ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) {
    +      throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一");
         }
     
         if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
    @@ -368,10 +359,19 @@ public class WxMpPayServiceImpl implements WxMpPayService {
     
         String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers";
     
    -    try (FileInputStream instream = new FileInputStream(keyFile)) {
    -      String mchId = request.getMchId();
    +    String responseContent = this.executeRequestWithKeyFile(xstream.toXML(request), url, keyFile, request.getMchId());
    +    WxEntPayResult result = (WxEntPayResult) xstream.fromXML(responseContent);
    +    if ("FAIL".equals(result.getResultCode())) {
    +      throw new WxErrorException(
    +        WxError.newBuilder().setErrorMsg(result.getErrCode() + ":" + result.getErrCodeDes()).build());
    +    }
    +    return result;
    +  }
    +
    +  private String executeRequestWithKeyFile( String requestStr, String url, File keyFile, String mchId) throws WxErrorException {
    +    try (FileInputStream inputStream = new FileInputStream(keyFile)) {
           KeyStore keyStore = KeyStore.getInstance("PKCS12");
    -      keyStore.load(instream, mchId.toCharArray());
    +      keyStore.load(inputStream, mchId.toCharArray());
     
           SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
           SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
    @@ -379,17 +379,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
     
           try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) {
             HttpPost httpPost = new HttpPost(url);
    -        httpPost.setEntity(new StringEntity(new String(xstream.toXML(request).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)) {
    -          String responseContent = EntityUtils.toString(response.getEntity());
    -          WxEntPayResult result = (WxEntPayResult) xstream.fromXML(responseContent);
    -          if ("FAIL".equals(result.getResultCode())) {
    -            throw new WxErrorException(
    -                WxError.newBuilder().setErrorMsg(result.getErrCode() + ":" + result.getErrCodeDes()).build());
    -          }
    -
    -          return result;
    +          return EntityUtils.toString(response.getEntity());
             }
           }
         } catch (Exception e) {
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
    index 1a7ffe84..4cd26894 100644
    --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
    @@ -1,23 +1,9 @@
     package me.chanjar.weixin.mp.api.impl;
     
    -import java.io.IOException;
    -
    -import org.apache.http.HttpHost;
    -import org.apache.http.client.config.RequestConfig;
    -import org.apache.http.client.methods.CloseableHttpResponse;
    -import org.apache.http.client.methods.HttpGet;
    -import org.apache.http.conn.ssl.DefaultHostnameVerifier;
    -import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    -import org.apache.http.impl.client.BasicResponseHandler;
    -import org.apache.http.impl.client.CloseableHttpClient;
    -import org.slf4j.Logger;
    -import org.slf4j.LoggerFactory;
    -
     import com.google.gson.JsonArray;
     import com.google.gson.JsonElement;
     import com.google.gson.JsonObject;
     import com.google.gson.JsonParser;
    -
     import me.chanjar.weixin.common.bean.WxAccessToken;
     import me.chanjar.weixin.common.bean.WxJsapiSignature;
     import me.chanjar.weixin.common.bean.result.WxError;
    @@ -26,38 +12,22 @@ import me.chanjar.weixin.common.session.StandardSessionManager;
     import me.chanjar.weixin.common.session.WxSessionManager;
     import me.chanjar.weixin.common.util.RandomUtils;
     import me.chanjar.weixin.common.util.crypto.SHA1;
    -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
    -import me.chanjar.weixin.common.util.http.DefaultApacheHttpClientBuilder;
    -import me.chanjar.weixin.common.util.http.RequestExecutor;
    -import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
    -import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
    -import me.chanjar.weixin.common.util.http.URIUtil;
    -import me.chanjar.weixin.mp.api.WxMpCardService;
    -import me.chanjar.weixin.mp.api.WxMpConfigStorage;
    -import me.chanjar.weixin.mp.api.WxMpDataCubeService;
    -import me.chanjar.weixin.mp.api.WxMpKefuService;
    -import me.chanjar.weixin.mp.api.WxMpMaterialService;
    -import me.chanjar.weixin.mp.api.WxMpMenuService;
    -import me.chanjar.weixin.mp.api.WxMpPayService;
    -import me.chanjar.weixin.mp.api.WxMpQrcodeService;
    -import me.chanjar.weixin.mp.api.WxMpService;
    -import me.chanjar.weixin.mp.api.WxMpStoreService;
    -import me.chanjar.weixin.mp.api.WxMpUserBlacklistService;
    -import me.chanjar.weixin.mp.api.WxMpUserService;
    -import me.chanjar.weixin.mp.api.WxMpUserTagService;
    -import me.chanjar.weixin.mp.bean.WxMpIndustry;
    -import me.chanjar.weixin.mp.bean.WxMpMassNews;
    -import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage;
    -import me.chanjar.weixin.mp.bean.WxMpMassPreviewMessage;
    -import me.chanjar.weixin.mp.bean.WxMpMassTagMessage;
    -import me.chanjar.weixin.mp.bean.WxMpMassVideo;
    -import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
    -import me.chanjar.weixin.mp.bean.WxMpTemplateMessage;
    -import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
    -import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
    -import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
    -import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
    -import me.chanjar.weixin.mp.bean.result.WxMpUser;
    +import me.chanjar.weixin.common.util.http.*;
    +import me.chanjar.weixin.mp.api.*;
    +import me.chanjar.weixin.mp.bean.*;
    +import me.chanjar.weixin.mp.bean.result.*;
    +import org.apache.http.HttpHost;
    +import org.apache.http.client.config.RequestConfig;
    +import org.apache.http.client.methods.CloseableHttpResponse;
    +import org.apache.http.client.methods.HttpGet;
    +import org.apache.http.conn.ssl.DefaultHostnameVerifier;
    +import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    +import org.apache.http.impl.client.BasicResponseHandler;
    +import org.apache.http.impl.client.CloseableHttpClient;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import java.io.IOException;
     
     public class WxMpServiceImpl implements WxMpService {
     
    @@ -477,6 +447,7 @@ public class WxMpServiceImpl implements WxMpService {
           }
           return null;
         } catch (IOException e) {
    +      this.log.error("\n[URL]:  {}\n[PARAMS]: {}\n[EXECEPTION]: {}", uri, data, e.getMessage());
           throw new RuntimeException(e);
         }
       }
    diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxMpPayRefundRequest.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxMpPayRefundRequest.java
    new file mode 100644
    index 00000000..e375d64e
    --- /dev/null
    +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/pay/WxMpPayRefundRequest.java
    @@ -0,0 +1,301 @@
    +package me.chanjar.weixin.mp.bean.pay;
    +
    +import com.thoughtworks.xstream.annotations.XStreamAlias;
    +import me.chanjar.weixin.common.annotation.Required;
    +
    +/**
    + * 
    + * 微信支付-申请退款请求参数
    + * 注释中各行每个字段描述对应如下:
    + * 
  • 字段名 + *
  • 变量名 + *
  • 是否必填 + *
  • 类型 + *
  • 示例值 + *
  • 描述 + *
  • + * + * @author binarywang(https://github.com/binarywang) + * Created by Binary Wang on 2016-10-08. + */ +@XStreamAlias("xml") +public class WxMpPayRefundRequest { + /** + *
    +   * 公众账号ID
    +   * appid
    +   * 是
    +   * String(32)
    +   * wx8888888888888888
    +   * 微信分配的公众账号ID(企业号corpid即为此appId)
    +   * 
    + */ + @XStreamAlias("appid") + private String appid; + + /** + *
    +   * 商户号
    +   * mch_id
    +   * 是
    +   * String(32)
    +   * 1900000109
    +   * 微信支付分配的商户号
    +   * 
    + */ + @XStreamAlias("mch_id") + private String mchId; + + /** + *
    +   * 设备号
    +   * device_info
    +   * 否
    +   * String(32)
    +   * 13467007045764
    +   * 终端设备号
    +   * 
    + */ + @XStreamAlias("device_info") + private String deviceInfo; + + /** + *
    +   * 随机字符串
    +   * nonce_str
    +   * 是
    +   * String(32)
    +   * 5K8264ILTKCH16CQ2502SI8ZNMTM67VS
    +   * 随机字符串,不长于32位。推荐随机数生成算法
    +   * 
    + */ + @XStreamAlias("nonce_str") + private String nonceStr; + + /** + *
    +   * 签名
    +   * sign
    +   * 是
    +   * String(32)
    +   * C380BEC2BFD727A4B6845133519F3AD6
    +   * 签名,详见签名生成算法
    +   * 
    + */ + @XStreamAlias("sign") + private String sign; + + /** + *
    +   * 微信订单号
    +   * transaction_id
    +   * 跟out_trade_no二选一
    +   * String(28)
    +   * 1217752501201400000000000000
    +   * 微信生成的订单号,在支付通知中有返回
    +   * 
    + */ + @XStreamAlias("transaction_id") + private String transactionId; + + /** + *
    +   * 商户订单号
    +   * out_trade_no
    +   * 跟transaction_id二选一
    +   * String(32)
    +   * 1217752501201400000000000000
    +   * 商户侧传给微信的订单号
    +   * 
    + */ + @XStreamAlias("out_trade_no") + private String outTradeNo; + + /** + *
    +   * 商户退款单号
    +   * out_refund_no
    +   * 是
    +   * String(32)
    +   * 1217752501201400000000000000
    +   * 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
    +   * 
    + */ + @Required + @XStreamAlias("out_refund_no") + private String outRefundNo; + + /** + *
    +   * 订单金额
    +   * total_fee
    +   * 是
    +   * Int
    +   * 100
    +   * 订单总金额,单位为分,只能为整数,详见支付金额
    +   * 
    + */ + @Required + @XStreamAlias("total_fee") + private Integer totalFee; + + /** + *
    +   * 退款金额
    +   * refund_fee
    +   * 是
    +   * Int
    +   * 100
    +   * 退款总金额,订单总金额,单位为分,只能为整数,详见支付金额
    +   * 
    + */ + @Required + @XStreamAlias("refund_fee") + private Integer refundFee; + + /** + *
    +   * 货币种类
    +   * refund_fee_type
    +   * 否
    +   * String(8)
    +   * CNY
    +   * 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
    +   * 
    + */ + @XStreamAlias("refund_fee_type") + private String refundFeeType; + + /** + *
    +   * 操作员
    +   * op_user_id
    +   * 是
    +   * String(32)
    +   * 1900000109
    +   * 操作员帐号, 默认为商户号
    +   * 
    + */ + //@Required + @XStreamAlias("op_user_id") + private String opUserId; + + /** + *
    +   * 退款资金来源
    +   * refund_account
    +   * 否
    +   * String(30)
    +   * REFUND_SOURCE_RECHARGE_FUNDS
    +   * 仅针对老资金流商户使用,
    +   * 
  • REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款), + *
  • REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款 + *
  • + */ + @XStreamAlias("refund_account") + private String refundAccount; + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getMchId() { + return mchId; + } + + public void setMchId(String mchId) { + this.mchId = mchId; + } + + public String getDeviceInfo() { + return deviceInfo; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public String getNonceStr() { + return nonceStr; + } + + public void setNonceStr(String nonceStr) { + this.nonceStr = nonceStr; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + 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 Integer getTotalFee() { + return totalFee; + } + + public void setTotalFee(Integer totalFee) { + this.totalFee = totalFee; + } + + public Integer getRefundFee() { + return refundFee; + } + + public void setRefundFee(Integer refundFee) { + this.refundFee = refundFee; + } + + public String getRefundFeeType() { + return refundFeeType; + } + + public void setRefundFeeType(String refundFeeType) { + this.refundFeeType = refundFeeType; + } + + public String getOpUserId() { + return opUserId; + } + + public void setOpUserId(String opUserId) { + this.opUserId = opUserId; + } + + public String getRefundAccount() { + return refundAccount; + } + + public void setRefundAccount(String refundAccount) { + this.refundAccount = refundAccount; + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java index 6199efeb..3f5dfe1a 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java @@ -1,20 +1,14 @@ package me.chanjar.weixin.mp.api.impl; -import java.io.File; - -import org.testng.annotations.Guice; -import org.testng.annotations.Test; - import com.google.inject.Inject; - import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.ApiTestModule; import me.chanjar.weixin.mp.api.WxXmlMpInMemoryConfigStorage; -import me.chanjar.weixin.mp.bean.pay.WxEntPayRequest; -import me.chanjar.weixin.mp.bean.pay.WxRedpackResult; -import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest; -import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest; -import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult; +import me.chanjar.weixin.mp.bean.pay.*; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.File; /** * 测试支付相关接口 @@ -44,8 +38,14 @@ public class WxMpPayServiceImplTest { } @Test - public void testRefundPay() throws Exception { - + public void testRefund() throws Exception { + WxMpPayRefundRequest request = new WxMpPayRefundRequest(); + request.setOutRefundNo("aaa"); + request.setOutTradeNo("1111"); + request.setTotalFee(1222); + request.setRefundFee(111); + WxMpPayRefundResult result = this.wxService.getPayService().refund(request); + System.err.println(result); } @Test