Skip to content

Commit fdb7fcd

Browse files
author
郑灶生
committed
微信V3商家转账到零钱相关API实现
1 parent 8f7ca71 commit fdb7fcd

File tree

8 files changed

+566
-10
lines changed

8 files changed

+566
-10
lines changed

pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/DefaultWxPayAssistService.java

+5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public DefaultWxPayAssistService(WxPayService wxPayService) {
6060
* @param transactionType 交易类型
6161
* @return 响应内容体
6262
*/
63+
@Override
6364
public JSONObject doExecute(Map<String, Object> parameters, TransactionType transactionType) {
6465
// String requestBody = JSON.toJSONString(parameters, SerializerFeature.WriteMapNullValue);
6566
String requestBody = JSON.toJSONString(parameters);
@@ -75,6 +76,7 @@ public JSONObject doExecute(Map<String, Object> parameters, TransactionType tran
7576
* @param uriVariables 用于匹配表达式
7677
* @return 响应内容体
7778
*/
79+
@Override
7880
public ResponseEntity<JSONObject> doExecuteEntity(String body, TransactionType transactionType, Object... uriVariables) {
7981
String reqUrl = UriVariables.getUri(wxPayService.getReqUrl(transactionType), uriVariables);
8082
MethodType method = MethodType.valueOf(transactionType.getMethod());
@@ -95,6 +97,7 @@ public ResponseEntity<JSONObject> doExecuteEntity(String body, TransactionType t
9597
* @param uriVariables 用于匹配表达式
9698
* @return 响应内容体
9799
*/
100+
@Override
98101
public JSONObject doExecute(String body, TransactionType transactionType, Object... uriVariables) {
99102
final ResponseEntity<JSONObject> responseEntity = doExecuteEntity(body, transactionType, uriVariables);
100103
int statusCode = responseEntity.getStatusCode();
@@ -112,6 +115,7 @@ public JSONObject doExecute(String body, TransactionType transactionType, Object
112115
* @param order 订单
113116
* @return 请求响应
114117
*/
118+
@Override
115119
public JSONObject doExecute(Map<String, Object> parameters, PayOrder order) {
116120
TransactionType transactionType = order.getTransactionType();
117121
return doExecute(parameters, transactionType);
@@ -127,6 +131,7 @@ public JSONObject doExecute(Map<String, Object> parameters, PayOrder order) {
127131
* @param method 请求方法
128132
* @return 请求实体
129133
*/
134+
@Override
130135
public HttpEntity buildHttpEntity(String url, String body, String method) {
131136
String nonceStr = SignTextUtils.randomStr();
132137
long timestamp = DateUtils.toEpochSecond();

pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java

+99-9
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
import java.io.InputStream;
55
import java.security.PrivateKey;
66
import java.security.cert.Certificate;
7+
import java.util.ArrayList;
78
import java.util.Collections;
89
import java.util.Date;
910
import java.util.Enumeration;
1011
import java.util.HashMap;
1112
import java.util.LinkedHashMap;
1213
import java.util.List;
1314
import java.util.Map;
15+
import java.util.stream.Collectors;
1416

1517
import org.apache.http.HttpEntity;
1618

@@ -21,9 +23,9 @@
2123
import com.alibaba.fastjson.JSON;
2224
import com.alibaba.fastjson.JSONObject;
2325
import com.egzosn.pay.common.api.BasePayService;
26+
import com.egzosn.pay.common.api.TransferService;
2427
import com.egzosn.pay.common.bean.AssistOrder;
2528
import com.egzosn.pay.common.bean.BillType;
26-
2729
import com.egzosn.pay.common.bean.CurType;
2830
import com.egzosn.pay.common.bean.MethodType;
2931
import com.egzosn.pay.common.bean.NoticeParams;
@@ -50,16 +52,17 @@
5052
import com.egzosn.pay.common.util.sign.encrypt.RSA2;
5153
import com.egzosn.pay.common.util.str.StringUtils;
5254
import com.egzosn.pay.wx.bean.WxPayError;
53-
import com.egzosn.pay.wx.bean.WxTransferType;
5455
import com.egzosn.pay.wx.v3.bean.WxAccountType;
5556
import com.egzosn.pay.wx.v3.bean.WxBillType;
5657
import com.egzosn.pay.wx.v3.bean.WxTransactionType;
58+
import com.egzosn.pay.wx.v3.bean.WxTransferType;
5759
import com.egzosn.pay.wx.v3.bean.order.Amount;
5860
import com.egzosn.pay.wx.v3.bean.order.RefundAmount;
5961
import com.egzosn.pay.wx.v3.bean.response.Resource;
6062
import com.egzosn.pay.wx.v3.bean.response.WxNoticeParams;
6163
import com.egzosn.pay.wx.v3.bean.response.WxPayMessage;
6264
import com.egzosn.pay.wx.v3.bean.response.WxRefundResult;
65+
import com.egzosn.pay.wx.v3.bean.transfer.TransferDetail;
6366
import com.egzosn.pay.wx.v3.utils.AntCertificationUtil;
6467
import com.egzosn.pay.wx.v3.utils.WxConst;
6568

@@ -72,7 +75,7 @@
7275
* date 2021/10/6
7376
* </pre>
7477
*/
75-
public class WxPayService extends BasePayService<WxPayConfigStorage> {
78+
public class WxPayService extends BasePayService<WxPayConfigStorage> implements TransferService {
7679

7780

7881
/**
@@ -91,14 +94,14 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
9194
*/
9295
private volatile WxParameterStructure wxParameterStructure;
9396

97+
9498
/**
9599
* 创建支付服务
96100
*
97101
* @param payConfigStorage 微信对应的支付配置
98102
*/
99103
public WxPayService(WxPayConfigStorage payConfigStorage) {
100-
super(payConfigStorage);
101-
104+
this(payConfigStorage, null);
102105
}
103106

104107
/**
@@ -110,6 +113,7 @@ public WxPayService(WxPayConfigStorage payConfigStorage) {
110113
public WxPayService(WxPayConfigStorage payConfigStorage, HttpConfigStorage configStorage) {
111114
super(payConfigStorage, configStorage);
112115
}
116+
113117
{
114118
initAfter();
115119
}
@@ -613,14 +617,100 @@ public Map<String, Object> downloadBill(Date billDate, BillType billType) {
613617

614618

615619
/**
616-
* 转账
620+
* 发起商家转账, 转账账单电子回单申请受理接口
617621
*
618-
* @param order 转账订单
622+
* @param transferOrder 转账订单
619623
* @return 对应的转账结果
620624
*/
621625
@Override
622-
public Map<String, Object> transfer(TransferOrder order) {
623-
throw new PayErrorException(new WxPayError("", "V3不支持转账"));
626+
public Map<String, Object> transfer(TransferOrder transferOrder) {
627+
//转账账单电子回单申请受理接口
628+
if (transferOrder.getTransferType() == WxTransferType.TRANSFER_BILL_RECEIPT) {
629+
Map<String, Object> attr = new MapGen<String, Object>(WxConst.OUT_BATCH_NO, transferOrder.getBatchNo()).getAttr();
630+
return getAssistService().doExecute(attr, transferOrder.getTransferType());
631+
}
632+
633+
Map<String, Object> parameters = new HashMap<>(12);
634+
parameters.put(WxConst.APPID, payConfigStorage.getAppId());
635+
parameters.put(WxConst.OUT_BATCH_NO, transferOrder.getBatchNo());
636+
OrderParaStructure.loadParameters(parameters, WxConst.BATCH_NAME, transferOrder);
637+
parameters.put(WxConst.BATCH_REMARK, transferOrder.getRemark());
638+
parameters.put(WxConst.TOTAL_AMOUNT, Util.conversionCentAmount(transferOrder.getAmount()));
639+
parameters.put(WxConst.TOTAL_NUM, transferOrder.getAttr(WxConst.TOTAL_NUM));
640+
Object transferDetailListAttr = transferOrder.getAttr(WxConst.TRANSFER_DETAIL_LIST);
641+
List<TransferDetail> transferDetails = initTransferDetailListAttr(transferDetailListAttr);
642+
parameters.put(WxConst.TRANSFER_DETAIL_LIST, transferDetails);
643+
OrderParaStructure.loadParameters(parameters, WxConst.TRANSFER_SCENE_ID, transferOrder);
644+
return getAssistService().doExecute(parameters, transferOrder.getTransferType());
645+
}
646+
647+
private List<TransferDetail> initTransferDetailListAttr(Object transferDetailListAttr) {
648+
List<TransferDetail> transferDetails = null;
649+
if (transferDetailListAttr instanceof String) {
650+
transferDetails = JSON.parseArray((String) transferDetailListAttr, TransferDetail.class);
651+
}
652+
else if (null != transferDetailListAttr) {
653+
//偷懒的做法
654+
transferDetails = JSON.parseArray(JSON.toJSONString(transferDetailListAttr), TransferDetail.class);
655+
}
656+
else {
657+
return null;
658+
}
659+
660+
String serialNumber = payConfigStorage.getCertEnvironment().getSerialNumber();
661+
Certificate certificate = getAssistService().getCertificate(serialNumber);
662+
return transferDetails.stream()
663+
.peek(transferDetailListItem -> {
664+
String userName = transferDetailListItem.getUserName();
665+
if (StringUtils.isNotEmpty(userName)) {
666+
String encryptedUserName = AntCertificationUtil.encryptToString(userName, certificate);
667+
transferDetailListItem.setUserName(encryptedUserName);
668+
}
669+
String userIdCard = transferDetailListItem.getUserIdCard();
670+
if (StringUtils.isNotEmpty(userIdCard)) {
671+
String encryptedUserIdCard = AntCertificationUtil.encryptToString(userIdCard, certificate);
672+
transferDetailListItem.setUserIdCard(encryptedUserIdCard);
673+
}
674+
}).collect(Collectors.toList());
675+
}
676+
677+
/**
678+
* 转账查询API
679+
* 通过批次单号查询批次单 与 通过明细单号查询明细单
680+
*
681+
* @param assistOrder 辅助交易订单
682+
* @return 对应的转账订单
683+
*/
684+
@Override
685+
public Map<String, Object> transferQuery(AssistOrder assistOrder) {
686+
Map<String, Object> parameters = new HashMap<>(6);
687+
TransactionType transactionType = assistOrder.getTransactionType();
688+
List<Object> uriVariables = new ArrayList<>(3);
689+
690+
if (StringUtils.isNotEmpty(assistOrder.getTradeNo())) {
691+
uriVariables.add(assistOrder.getTradeNo());
692+
String detailId = assistOrder.getAttrForString(WxConst.DETAIL_ID);
693+
if (StringUtils.isNotEmpty(detailId)) {
694+
uriVariables.add(detailId);
695+
}
696+
}
697+
else if (StringUtils.isNotEmpty(assistOrder.getOutTradeNo())) {
698+
uriVariables.add(assistOrder.getOutTradeNo());
699+
String outDetailNo = assistOrder.getAttrForString(WxConst.OUT_DETAIL_NO);
700+
if (StringUtils.isNotEmpty(outDetailNo)) {
701+
uriVariables.add(outDetailNo);
702+
}
703+
}
704+
705+
if (transactionType == com.egzosn.pay.wx.v3.bean.WxTransferType.QUERY_BATCH_BY_BATCH_ID || transactionType == com.egzosn.pay.wx.v3.bean.WxTransferType.QUERY_BATCH_BY_OUT_BATCH_NO) {
706+
OrderParaStructure.loadParameters(parameters, WxConst.NEED_QUERY_DETAIL, assistOrder);
707+
OrderParaStructure.loadParameters(parameters, WxConst.OFFSET, assistOrder);
708+
OrderParaStructure.loadParameters(parameters, WxConst.LIMIT, assistOrder);
709+
OrderParaStructure.loadParameters(parameters, WxConst.DETAIL_STATUS, assistOrder);
710+
}
711+
712+
String requestBody = JSON.toJSONString(parameters);
713+
return getAssistService().doExecute(requestBody, assistOrder.getTransactionType(), uriVariables.toArray());
624714
}
625715

626716

pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/WxTransactionType.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public void setAttribute(Map<String, Object> parameters, PayOrder order) {
153153
/**
154154
* 合单关闭订单
155155
*/
156-
COMBINE_CLOSE("/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close", MethodType.POST),
156+
COMBINE_CLOSE("/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close", MethodType.POST)
157157
;
158158

159159
WxTransactionType(String type, MethodType method) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.egzosn.pay.wx.v3.bean;
2+
3+
import java.util.Map;
4+
5+
import com.egzosn.pay.common.bean.MethodType;
6+
import com.egzosn.pay.common.bean.TransferOrder;
7+
import com.egzosn.pay.common.bean.TransferType;
8+
9+
/**
10+
* 微信转账类型
11+
*
12+
* @author egan
13+
14+
* date 2018/9/28.19:56
15+
*/
16+
public enum WxTransferType implements TransferType {
17+
/**
18+
* 转账到零钱
19+
*/
20+
TRANSFER_BATCHES("/v3/transfer/batches", MethodType.POST),
21+
/**
22+
* 查询转账到零钱的记录,通过微信批次单号查询批次单
23+
*/
24+
QUERY_BATCH_BY_BATCH_ID("/v3/transfer/batches/batch-id/{batch_id}"),
25+
/**
26+
* 查询转账到零钱的记录,通过商家批次单号查询批次单
27+
*/
28+
QUERY_BATCH_BY_OUT_BATCH_NO("/v3/transfer/batches/out-batch-no/{out_batch_no}"),
29+
/**
30+
* 通过微信明细单号查询明细单
31+
*/
32+
QUERY_BATCH_DETAIL_BY_BATCH_ID("/v3/transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}"),
33+
/**
34+
* 通过商家明细单号查询明细单
35+
*/
36+
QUERY_BATCH_DETAIL_BY_OUT_BATCH_NO("/v3/transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}"),
37+
/**
38+
* 转账账单电子回单申请受理接口
39+
*/
40+
TRANSFER_BILL_RECEIPT("/v3/transfer/bill-receipt", MethodType.POST),
41+
/**
42+
* 查询转账账单电子回单接口
43+
*/
44+
QUERY_TRANSFER_BILL_RECEIPT("/v3/transfer/bill-receipt/{out_batch_no}"),
45+
/**
46+
* 受理转账明细电子回单API
47+
*/
48+
TRANSFER_DETAIL_ELECTRONIC_RECEIPTS("/v3/transfer-detail/electronic-receipts", MethodType.POST),
49+
/**
50+
* 查询转账明细电子回单受理结果API
51+
*/
52+
QUERY_TRANSFER_DETAIL_ELECTRONIC_RECEIPTS("/v3/transfer-detail/electronic-receipts"),
53+
;
54+
55+
WxTransferType(String type, MethodType method) {
56+
this.type = type;
57+
this.method = method;
58+
}
59+
60+
WxTransferType(String type) {
61+
this(type, MethodType.GET);
62+
}
63+
64+
private String type;
65+
private MethodType method;
66+
67+
68+
@Override
69+
public String getType() {
70+
return type;
71+
}
72+
73+
@Override
74+
public String getMethod() {
75+
return this.method.name();
76+
}
77+
78+
/**
79+
* 设置属性
80+
*
81+
* @param attr 已有属性对象
82+
* @param order 转账订单
83+
* @return 属性对象
84+
*/
85+
@Override
86+
public Map<String, Object> setAttr(Map<String, Object> attr, TransferOrder order) {
87+
return attr;
88+
}
89+
}

0 commit comments

Comments
 (0)