Skip to content

Commit dabafc2

Browse files
committed
实现企业付款的接口,暂时未调通,因缺少证书 for issue binarywang#50
1 parent a4b0fdc commit dabafc2

5 files changed

Lines changed: 553 additions & 14 deletions

File tree

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package me.chanjar.weixin.mp.api;
22

3+
import java.io.File;
34
import java.util.Map;
45

56
import me.chanjar.weixin.common.exception.WxErrorException;
7+
import me.chanjar.weixin.mp.bean.pay.WxEntPayRequest;
8+
import me.chanjar.weixin.mp.bean.pay.WxEntPayResult;
69
import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback;
710
import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult;
811
import me.chanjar.weixin.mp.bean.pay.WxMpPayResult;
@@ -85,4 +88,17 @@ WxMpPayResult getJSSDKPayResult(String transactionId, String outTradeNo)
8588
*/
8689
WxRedpackResult sendRedpack(WxSendRedpackRequest request) throws WxErrorException;
8790

91+
/**
92+
* <pre>
93+
* 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
94+
* 比如目前的保险行业向客户退保、给付、理赔。
95+
* 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
96+
* 注意:与商户微信支付收款资金并非同一账户,需要单独充值。
97+
* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
98+
* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
99+
* @param keyFile 证书文件对象
100+
* </pre>
101+
*/
102+
WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException;
103+
88104
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
package me.chanjar.weixin.mp.api.impl;
22

3+
import java.io.File;
4+
import java.io.FileInputStream;
35
import java.lang.reflect.Field;
6+
import java.security.KeyStore;
47
import java.util.HashMap;
58
import java.util.List;
69
import java.util.Map;
710
import java.util.Map.Entry;
811
import java.util.SortedMap;
912
import java.util.TreeMap;
1013

14+
import javax.net.ssl.SSLContext;
15+
1116
import org.apache.commons.codec.digest.DigestUtils;
1217
import org.apache.commons.lang3.StringUtils;
18+
import org.apache.http.client.methods.CloseableHttpResponse;
19+
import org.apache.http.client.methods.HttpPost;
20+
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
21+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
22+
import org.apache.http.entity.StringEntity;
23+
import org.apache.http.impl.client.CloseableHttpClient;
24+
import org.apache.http.impl.client.HttpClients;
25+
import org.apache.http.ssl.SSLContexts;
26+
import org.apache.http.util.EntityUtils;
1327
import org.joor.Reflect;
1428

1529
import com.google.common.collect.Lists;
@@ -23,6 +37,8 @@
2337
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
2438
import me.chanjar.weixin.mp.api.WxMpPayService;
2539
import me.chanjar.weixin.mp.api.WxMpService;
40+
import me.chanjar.weixin.mp.bean.pay.WxEntPayRequest;
41+
import me.chanjar.weixin.mp.bean.pay.WxEntPayResult;
2642
import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback;
2743
import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult;
2844
import me.chanjar.weixin.mp.bean.pay.WxMpPayResult;
@@ -263,6 +279,23 @@ public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
263279

264280
private void checkParameters(WxUnifiedOrderRequest request) {
265281

282+
checkNotNullParams(request);
283+
284+
if (!TRADE_TYPES.contains(request.getTradeType())) {
285+
throw new IllegalArgumentException("trade_type目前必须为" + TRADE_TYPES + "其中之一");
286+
287+
}
288+
289+
if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
290+
throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
291+
}
292+
293+
if ("NATIVE".equals(request.getTradeType()) && request.getProductId() == null) {
294+
throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id");
295+
}
296+
}
297+
298+
private void checkNotNullParams(Object request) {
266299
List<String> nullFields = Lists.newArrayList();
267300
for (Entry<String, Reflect> entry : Reflect.on(request).fields()
268301
.entrySet()) {
@@ -281,20 +314,6 @@ private void checkParameters(WxUnifiedOrderRequest request) {
281314
if (!nullFields.isEmpty()) {
282315
throw new IllegalArgumentException("必填字段[" + nullFields + "]必须提供值");
283316
}
284-
285-
if (!TRADE_TYPES.contains(request.getTradeType())) {
286-
throw new IllegalArgumentException("trade_type目前必须为" + TRADE_TYPES + "其中之一");
287-
288-
}
289-
290-
if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
291-
throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
292-
}
293-
294-
if ("NATIVE".equals(request.getTradeType())
295-
&& request.getProductId() == null) {
296-
throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id");
297-
}
298317
}
299318

300319
@Override
@@ -332,4 +351,50 @@ public Map<String, String> getPayInfo(WxUnifiedOrderRequest request) throws WxEr
332351
return payInfo;
333352
}
334353

354+
@Override
355+
public WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException {
356+
checkNotNullParams(request);
357+
358+
XStream xstream = XStreamInitializer.getInstance();
359+
xstream.processAnnotations(WxEntPayRequest.class);
360+
xstream.processAnnotations(WxEntPayResult.class);
361+
362+
request.setMchAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
363+
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
364+
request.setNonceStr(System.currentTimeMillis() + "");
365+
366+
String sign = this.createSign(xmlBean2Map(request), this.wxMpService.getWxMpConfigStorage().getPartnerKey());
367+
request.setSign(sign);
368+
369+
String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers";
370+
371+
try (FileInputStream instream = new FileInputStream(keyFile)) {
372+
String mchId = request.getMchId();
373+
KeyStore keyStore = KeyStore.getInstance("PKCS12");
374+
keyStore.load(instream, mchId.toCharArray());
375+
376+
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
377+
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
378+
new DefaultHostnameVerifier());
379+
380+
try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) {
381+
HttpPost httpPost = new HttpPost(url);
382+
httpPost.setEntity(new StringEntity(new String(xstream.toXML(request).getBytes("UTF-8"), "ISO-8859-1")));
383+
384+
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
385+
String responseContent = EntityUtils.toString(response.getEntity());
386+
WxEntPayResult result = (WxEntPayResult) xstream.fromXML(responseContent);
387+
if ("FAIL".equals(result.getResultCode())) {
388+
throw new WxErrorException(
389+
WxError.newBuilder().setErrorMsg(result.getErrCode() + ":" + result.getErrCodeDes()).build());
390+
}
391+
392+
return result;
393+
}
394+
}
395+
} catch (Exception e) {
396+
throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build(), e);
397+
}
398+
}
399+
335400
}

0 commit comments

Comments
 (0)