@@ -1,19 +1,11 @@ | |||||
package me.chanjar.weixin.mp.api; | 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.io.File; | ||||
import java.util.Map; | 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. | * 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) | * 统一下单(详见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 | |||||
* @throws WxErrorException | |||||
* | * | ||||
*/ | */ | ||||
WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request) | WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request) | ||||
@@ -42,7 +34,7 @@ public interface WxMpPayService { | |||||
/** | /** | ||||
* 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 | * 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 | ||||
* 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 | * 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2 | ||||
* @throws WxErrorException | |||||
* @throws WxErrorException | |||||
* | * | ||||
*/ | */ | ||||
WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo) | WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo) | ||||
@@ -56,18 +48,15 @@ public interface WxMpPayService { | |||||
WxMpPayCallback getJSSDKCallbackData(String xmlData); | WxMpPayCallback getJSSDKCallbackData(String xmlData); | ||||
/** | /** | ||||
* <pre> | |||||
* 微信支付-申请退款 | * 微信支付-申请退款 | ||||
* 详见 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 | ||||
* | |||||
* @param parameters 需要传入的退款参数的Map。以下几项为参数的必须项:<br/> | |||||
* <li/> transaction_id | |||||
* <li/> out_trade_no (仅在上述transaction_id为空时是必须项) | |||||
* <li/> out_refund_no | |||||
* <li/> total_fee | |||||
* <li/> refund_fee | |||||
* 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund | |||||
* </pre> | |||||
* @param keyFile 证书文件对象 | |||||
* @return 退款操作结果 | * @return 退款操作结果 | ||||
*/ | */ | ||||
WxMpPayRefundResult refundPay(Map<String, String> parameters) throws WxErrorException; | |||||
WxMpPayRefundResult refund(WxMpPayRefundRequest request, File keyFile) throws WxErrorException; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -80,7 +69,7 @@ public interface WxMpPayService { | |||||
/** | /** | ||||
* 发送微信红包给个人用户 | * 发送微信红包给个人用户 | ||||
* <pre> | |||||
* <pre> | |||||
* 文档详见: | * 文档详见: | ||||
* 发送普通红包 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 | ||||
@@ -89,7 +78,7 @@ public interface WxMpPayService { | |||||
WxRedpackResult sendRedpack(WxSendRedpackRequest request) throws WxErrorException; | WxRedpackResult sendRedpack(WxSendRedpackRequest request) throws WxErrorException; | ||||
/** | /** | ||||
* <pre> | |||||
* <pre> | |||||
* 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。 | * 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。 | ||||
* 比如目前的保险行业向客户退保、给付、理赔。 | * 比如目前的保险行业向客户退保、给付、理赔。 | ||||
* 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。 | * 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。 | ||||
@@ -1,19 +1,18 @@ | |||||
package me.chanjar.weixin.mp.api.impl; | 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.codec.digest.DigestUtils; | ||||
import org.apache.commons.lang3.ArrayUtils; | |||||
import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
import org.apache.http.client.methods.HttpPost; | 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.apache.http.util.EntityUtils; | ||||
import org.joor.Reflect; | 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. | * 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 { | public class WxMpPayServiceImpl implements WxMpPayService { | ||||
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 List<String> 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; | private WxMpService wxMpService; | ||||
public WxMpPayServiceImpl(WxMpService wxMpService) { | public WxMpPayServiceImpl(WxMpService wxMpService) { | ||||
@@ -115,33 +103,25 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
} | } | ||||
@Override | @Override | ||||
public WxMpPayRefundResult refundPay(Map<String, String> parameters) | |||||
public WxMpPayRefundResult refund(WxMpPayRefundRequest request, File keyFile) | |||||
throws WxErrorException { | throws WxErrorException { | ||||
SortedMap<String, String> 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("<xml>"); | |||||
for (Map.Entry<String, String> para : refundParams.entrySet()) { | |||||
request.append(String.format("<%s>%s</%s>", para.getKey(), | |||||
para.getValue(), para.getKey())); | |||||
} | |||||
request.append("</xml>"); | |||||
checkParameters(request); | |||||
String url = PAY_BASE_URL + "/secapi/pay/refund"; | |||||
String responseContent = this.wxMpService.post(url, request.toString()); | |||||
XStream xstream = XStreamInitializer.getInstance(); | XStream xstream = XStreamInitializer.getInstance(); | ||||
xstream.processAnnotations(WxMpPayRefundResult.class); | 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()) | if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode()) | ||||
|| !"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) { | || !"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) { | ||||
@@ -158,6 +138,20 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
return wxMpPayRefundResult; | 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 | @Override | ||||
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, | public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, | ||||
String signature) { | String signature) { | ||||
@@ -176,7 +170,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); | request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); | ||||
request.setNonceStr(System.currentTimeMillis() + ""); | request.setNonceStr(System.currentTimeMillis() + ""); | ||||
String sign = this.createSign(xmlBean2Map(request), | |||||
String sign = this.createSign(this.xmlBean2Map(request), | |||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | ||||
request.setSign(sign); | request.setSign(sign); | ||||
@@ -258,7 +252,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); | request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId()); | ||||
request.setNonceStr(System.currentTimeMillis() + ""); | request.setNonceStr(System.currentTimeMillis() + ""); | ||||
String sign = this.createSign(xmlBean2Map(request), | |||||
String sign = this.createSign(this.xmlBean2Map(request), | |||||
this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | this.wxMpService.getWxMpConfigStorage().getPartnerKey()); | ||||
request.setSign(sign); | request.setSign(sign); | ||||
@@ -274,16 +268,13 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
private void checkParameters(WxUnifiedOrderRequest request) { | private void checkParameters(WxUnifiedOrderRequest request) { | ||||
checkNotNullParams(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) { | 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"; | 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 keyStore = KeyStore.getInstance("PKCS12"); | ||||
keyStore.load(instream, 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, | 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()) { | try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) { | ||||
HttpPost httpPost = new HttpPost(url); | 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)) { | 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) { | } catch (Exception e) { | ||||
@@ -1,23 +1,9 @@ | |||||
package me.chanjar.weixin.mp.api.impl; | 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.JsonArray; | ||||
import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||
import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
import me.chanjar.weixin.common.bean.WxJsapiSignature; | import me.chanjar.weixin.common.bean.WxJsapiSignature; | ||||
import me.chanjar.weixin.common.bean.result.WxError; | 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.session.WxSessionManager; | ||||
import me.chanjar.weixin.common.util.RandomUtils; | import me.chanjar.weixin.common.util.RandomUtils; | ||||
import me.chanjar.weixin.common.util.crypto.SHA1; | 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 { | public class WxMpServiceImpl implements WxMpService { | ||||
@@ -477,6 +447,7 @@ public class WxMpServiceImpl implements WxMpService { | |||||
} | } | ||||
return null; | return null; | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXECEPTION]: {}", uri, data, e.getMessage()); | |||||
throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,301 @@ | |||||
package me.chanjar.weixin.mp.bean.pay; | |||||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
import me.chanjar.weixin.common.annotation.Required; | |||||
/** | |||||
* <pre> | |||||
* 微信支付-申请退款请求参数 | |||||
* 注释中各行每个字段描述对应如下: | |||||
* <li>字段名 | |||||
* <li>变量名 | |||||
* <li>是否必填 | |||||
* <li>类型 | |||||
* <li>示例值 | |||||
* <li>描述 | |||||
* </pre> | |||||
* | |||||
* @author binarywang(https://github.com/binarywang) | |||||
* Created by Binary Wang on 2016-10-08. | |||||
*/ | |||||
@XStreamAlias("xml") | |||||
public class WxMpPayRefundRequest { | |||||
/** | |||||
* <pre> | |||||
* 公众账号ID | |||||
* appid | |||||
* 是 | |||||
* String(32) | |||||
* wx8888888888888888 | |||||
* 微信分配的公众账号ID(企业号corpid即为此appId) | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("appid") | |||||
private String appid; | |||||
/** | |||||
* <pre> | |||||
* 商户号 | |||||
* mch_id | |||||
* 是 | |||||
* String(32) | |||||
* 1900000109 | |||||
* 微信支付分配的商户号 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("mch_id") | |||||
private String mchId; | |||||
/** | |||||
* <pre> | |||||
* 设备号 | |||||
* device_info | |||||
* 否 | |||||
* String(32) | |||||
* 13467007045764 | |||||
* 终端设备号 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("device_info") | |||||
private String deviceInfo; | |||||
/** | |||||
* <pre> | |||||
* 随机字符串 | |||||
* nonce_str | |||||
* 是 | |||||
* String(32) | |||||
* 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | |||||
* 随机字符串,不长于32位。推荐随机数生成算法 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("nonce_str") | |||||
private String nonceStr; | |||||
/** | |||||
* <pre> | |||||
* 签名 | |||||
* sign | |||||
* 是 | |||||
* String(32) | |||||
* C380BEC2BFD727A4B6845133519F3AD6 | |||||
* 签名,详见签名生成算法 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("sign") | |||||
private String sign; | |||||
/** | |||||
* <pre> | |||||
* 微信订单号 | |||||
* transaction_id | |||||
* 跟out_trade_no二选一 | |||||
* String(28) | |||||
* 1217752501201400000000000000 | |||||
* 微信生成的订单号,在支付通知中有返回 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("transaction_id") | |||||
private String transactionId; | |||||
/** | |||||
* <pre> | |||||
* 商户订单号 | |||||
* out_trade_no | |||||
* 跟transaction_id二选一 | |||||
* String(32) | |||||
* 1217752501201400000000000000 | |||||
* 商户侧传给微信的订单号 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("out_trade_no") | |||||
private String outTradeNo; | |||||
/** | |||||
* <pre> | |||||
* 商户退款单号 | |||||
* out_refund_no | |||||
* 是 | |||||
* String(32) | |||||
* 1217752501201400000000000000 | |||||
* 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔 | |||||
* </pre> | |||||
*/ | |||||
@Required | |||||
@XStreamAlias("out_refund_no") | |||||
private String outRefundNo; | |||||
/** | |||||
* <pre> | |||||
* 订单金额 | |||||
* total_fee | |||||
* 是 | |||||
* Int | |||||
* 100 | |||||
* 订单总金额,单位为分,只能为整数,详见支付金额 | |||||
* </pre> | |||||
*/ | |||||
@Required | |||||
@XStreamAlias("total_fee") | |||||
private Integer totalFee; | |||||
/** | |||||
* <pre> | |||||
* 退款金额 | |||||
* refund_fee | |||||
* 是 | |||||
* Int | |||||
* 100 | |||||
* 退款总金额,订单总金额,单位为分,只能为整数,详见支付金额 | |||||
* </pre> | |||||
*/ | |||||
@Required | |||||
@XStreamAlias("refund_fee") | |||||
private Integer refundFee; | |||||
/** | |||||
* <pre> | |||||
* 货币种类 | |||||
* refund_fee_type | |||||
* 否 | |||||
* String(8) | |||||
* CNY | |||||
* 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型 | |||||
* </pre> | |||||
*/ | |||||
@XStreamAlias("refund_fee_type") | |||||
private String refundFeeType; | |||||
/** | |||||
* <pre> | |||||
* 操作员 | |||||
* op_user_id | |||||
* 是 | |||||
* String(32) | |||||
* 1900000109 | |||||
* 操作员帐号, 默认为商户号 | |||||
* </pre> | |||||
*/ | |||||
//@Required | |||||
@XStreamAlias("op_user_id") | |||||
private String opUserId; | |||||
/** | |||||
* <pre> | |||||
* 退款资金来源 | |||||
* refund_account | |||||
* 否 | |||||
* String(30) | |||||
* REFUND_SOURCE_RECHARGE_FUNDS | |||||
* 仅针对老资金流商户使用, | |||||
* <li>REFUND_SOURCE_UNSETTLED_FUNDS---未结算资金退款(默认使用未结算资金退款), | |||||
* <li>REFUND_SOURCE_RECHARGE_FUNDS---可用余额退款 | |||||
* </pre> | |||||
*/ | |||||
@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; | |||||
} | |||||
} |
@@ -1,20 +1,14 @@ | |||||
package me.chanjar.weixin.mp.api.impl; | 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 com.google.inject.Inject; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.mp.api.ApiTestModule; | import me.chanjar.weixin.mp.api.ApiTestModule; | ||||
import me.chanjar.weixin.mp.api.WxXmlMpInMemoryConfigStorage; | 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 | @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 | @Test | ||||