Skip to content

Commit 429f170

Browse files
authored
🆕 #1789 微信支付电商收付通增加下载账单的接口
1 parent b797152 commit 429f170

File tree

9 files changed

+292
-3
lines changed

9 files changed

+292
-3
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.github.binarywang.wxpay.bean.ecommerce;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.*;
5+
6+
/**
7+
* 账单请求
8+
* @author: f00lish
9+
* @date: 2020/09/28
10+
*/
11+
@Data
12+
@Builder
13+
@ToString
14+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
15+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
16+
public class BillRequest {
17+
18+
/**
19+
* <pre>
20+
* 字段名:账单日期
21+
* 变量名:bill_date
22+
* 是否必填:是
23+
* 类型:string(10)
24+
* 描述:
25+
* 格式YYYY-MM-DD
26+
* 仅支持三个月内的账单下载申请。
27+
* 示例值:2019-06-11
28+
* </pre>
29+
*/
30+
@SerializedName(value = "bill_date")
31+
private String billDate;
32+
33+
/**
34+
* <pre>
35+
* 字段名:二级商户号
36+
* 变量名:sub_mchid
37+
* 是否必填:否
38+
* 类型:string(12)
39+
* 描述:
40+
* 1、若商户是直连商户:无需填写该字段。
41+
* 2、若商户是服务商:
42+
* ● 不填则默认返回服务商下的交易或退款数据。
43+
* ● 如需下载某个子商户下的交易或退款数据,则该字段必填。
44+
* 特殊规则:最小字符长度为8
45+
* 注意:仅适用于电商平台 服务商
46+
* 示例值:1900000001
47+
* </pre>
48+
*/
49+
@SerializedName(value = "sub_mchid")
50+
private String subMchid;
51+
52+
/**
53+
* <pre>
54+
* 字段名:账单类型
55+
* 变量名:bill_type
56+
* 是否必填:否
57+
* 类型:string(32)
58+
* 描述:
59+
* 不填则默认是ALL
60+
* 枚举值:
61+
* ALL:返回当日所有订单信息(不含充值退款订单)
62+
* SUCCESS:返回当日成功支付的订单(不含充值退款订单)
63+
* REFUND:返回当日退款订单(不含充值退款订单)
64+
* 示例值:ALL
65+
* </pre>
66+
*/
67+
@SerializedName(value = "bill_type")
68+
private String billType;
69+
70+
/**
71+
* <pre>
72+
* 字段名:压缩类型
73+
* 变量名:tar_type
74+
* 是否必填:否
75+
* 类型:string(32)
76+
* 描述:
77+
* 不填则默认是数据流
78+
* 枚举值:
79+
* GZIP:返回格式为.gzip的压缩包账单
80+
* 示例值:GZIP
81+
* </pre>
82+
*/
83+
@SerializedName(value = "tar_type")
84+
private String tarType;
85+
86+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.github.binarywang.wxpay.bean.ecommerce;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.*;
5+
6+
/**
7+
* 账单结果
8+
* @author: f00lish
9+
* @date: 2020/09/28
10+
*/
11+
@Data
12+
@Builder
13+
@ToString
14+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
15+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
16+
public class BillResult {
17+
18+
/**
19+
* <pre>
20+
* 字段名:哈希类型
21+
* 变量名:hash_type
22+
* 是否必填:是
23+
* 类型:string(32)
24+
* 描述:
25+
* 原始账单(gzip需要解压缩)的摘要值,用于校验文件的完整性。
26+
* 示例值:SHA1
27+
* </pre>
28+
*/
29+
@SerializedName(value = "hash_type")
30+
private String hashType;
31+
32+
/**
33+
* <pre>
34+
* 字段名:哈希值
35+
* 变量名:hash_value
36+
* 是否必填:是
37+
* 类型:string(1024)
38+
* 描述:
39+
* 原始账单(gzip需要解压缩)的摘要值,用于校验文件的完整性。
40+
* 示例值:79bb0f45fc4c42234a918000b2668d689e2bde04
41+
* </pre>
42+
*/
43+
@SerializedName(value = "hash_value")
44+
private String hashValue;
45+
46+
/**
47+
* <pre>
48+
* 字段名:账单下载地址
49+
* 变量名:download_url
50+
* 是否必填:是
51+
* 类型:string(32)
52+
* 描述:
53+
* 供下一步请求账单文件的下载地址,该地址30s内有效。
54+
* 示例值:https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx
55+
* </pre>
56+
*/
57+
@SerializedName(value = "download_url")
58+
private String downloadUrl;
59+
60+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.github.binarywang.wxpay.bean.ecommerce.enums;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
/**
7+
* 账单类型
8+
* @author: f00lish
9+
* @date: 2020/09/28
10+
*/
11+
@Getter
12+
@AllArgsConstructor
13+
public enum BillTypeEnum {
14+
15+
/**
16+
* 交易账单
17+
*/
18+
TRADE_BILL("%s/v3/bill/tradebill?%s"),
19+
/**
20+
* 资金账单
21+
*/
22+
FUND_FLOW_BILL("%s/v3/bill/fundflowbill?%s");
23+
24+
25+
/**
26+
* url
27+
*/
28+
private final String url;
29+
30+
}

weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.github.binarywang.wxpay.service;
22

33
import com.github.binarywang.wxpay.bean.ecommerce.*;
4+
import com.github.binarywang.wxpay.bean.ecommerce.enums.BillTypeEnum;
45
import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum;
56
import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
67
import com.github.binarywang.wxpay.exception.WxPayException;
78

9+
import java.io.InputStream;
10+
811
/**
912
* <pre>
1013
* 电商收付通相关服务类.
@@ -360,4 +363,29 @@ public interface EcommerceService {
360363
*/
361364
SettlementResult querySettlement(String subMchid) throws WxPayException;
362365

366+
/**
367+
* <pre>
368+
* 请求账单API
369+
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/bill.shtml
370+
* </pre>
371+
*
372+
* @param billType 账单类型。
373+
* @param request 二级商户号。
374+
* @return 返回数据 return bill result
375+
* @throws WxPayException the wx pay exception
376+
*/
377+
BillResult applyBill(BillTypeEnum billType, BillRequest request) throws WxPayException;
378+
379+
/**
380+
* <pre>
381+
* 下载账单API
382+
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/bill.shtml
383+
* </pre>
384+
*
385+
* @param url 微信返回的账单地址。
386+
* @return 返回数据 return inputStream
387+
* @throws WxPayException the wx pay exception
388+
*/
389+
InputStream downloadBill(String url) throws WxPayException;
390+
363391
}

weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.apache.http.client.methods.HttpPost;
1414

1515
import java.io.File;
16+
import java.io.InputStream;
1617
import java.net.URI;
1718
import java.util.Date;
1819
import java.util.Map;
@@ -97,6 +98,15 @@ public interface WxPayService {
9798
*/
9899
String getV3(URI url) throws WxPayException;
99100

101+
/**
102+
* 发送下载 V3请求,得到响应流.
103+
*
104+
* @param url 请求地址
105+
* @return 返回请求响应流
106+
* @throws WxPayException the wx pay exception
107+
*/
108+
InputStream downloadV3(URI url) throws WxPayException;
109+
100110
/**
101111
* 获取企业付款服务类.
102112
*

weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
package com.github.binarywang.wxpay.service.impl;
22

33
import com.github.binarywang.wxpay.bean.ecommerce.*;
4+
import com.github.binarywang.wxpay.bean.ecommerce.enums.BillTypeEnum;
45
import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum;
56
import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum;
67
import com.github.binarywang.wxpay.exception.WxPayException;
78
import com.github.binarywang.wxpay.service.EcommerceService;
89
import com.github.binarywang.wxpay.service.WxPayService;
910
import com.github.binarywang.wxpay.v3.util.AesUtils;
1011
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
12+
import com.google.common.base.CaseFormat;
1113
import com.google.gson.Gson;
1214
import com.google.gson.GsonBuilder;
1315
import lombok.RequiredArgsConstructor;
16+
import org.apache.commons.beanutils.BeanMap;
1417

1518
import java.io.IOException;
19+
import java.io.InputStream;
1620
import java.net.URI;
1721
import java.nio.charset.StandardCharsets;
1822
import java.security.GeneralSecurityException;
23+
import java.util.Iterator;
24+
import java.util.Map;
1925
import java.util.Objects;
26+
import java.util.Set;
2027

2128
@RequiredArgsConstructor
2229
public class EcommerceServiceImpl implements EcommerceService {
@@ -273,6 +280,18 @@ public SettlementResult querySettlement(String subMchid) throws WxPayException {
273280
return GSON.fromJson(response, SettlementResult.class);
274281
}
275282

283+
@Override
284+
public BillResult applyBill(BillTypeEnum billType, BillRequest request) throws WxPayException {
285+
String url = String.format(billType.getUrl(), this.payService.getPayBaseUrl(), this.parseURLPair(request));
286+
String response = this.payService.getV3(URI.create(url));
287+
return GSON.fromJson(response, BillResult.class);
288+
}
289+
290+
@Override
291+
public InputStream downloadBill(String url) throws WxPayException {
292+
return this.payService.downloadV3(URI.create(url));
293+
}
294+
276295
/**
277296
* 校验通知签名
278297
* @param header 通知头信息
@@ -287,4 +306,24 @@ private boolean verifyNotifySign(SignatureHeader header, String data) {
287306
return payService.getConfig().getVerifier().verify(header.getSerialNo(),
288307
beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned());
289308
}
290-
}
309+
310+
/**
311+
* 对象拼接到url
312+
* @param o 转换对象
313+
* @return 拼接好的string
314+
*/
315+
private String parseURLPair(Object o) {
316+
Map<Object, Object> map = new BeanMap(o);
317+
Set<Map.Entry<Object, Object>> set = map.entrySet();
318+
Iterator<Map.Entry<Object, Object>> it = set.iterator();
319+
StringBuilder sb = new StringBuilder();
320+
while (it.hasNext()) {
321+
Map.Entry<Object, Object> e = it.next();
322+
if ( !"class".equals(e.getKey()) && e.getValue() != null)
323+
sb.append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, String.valueOf(e.getKey()))).append("=").append(e.getValue()).append("&");
324+
}
325+
return sb.deleteCharAt(sb.length() - 1).toString();
326+
}
327+
328+
329+
}

weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.http.util.EntityUtils;
2727

2828
import javax.net.ssl.SSLContext;
29+
import java.io.InputStream;
2930
import java.net.URI;
3031
import java.nio.charset.StandardCharsets;
3132
import java.util.Base64;
@@ -207,6 +208,31 @@ public String getV3(URI url) throws WxPayException {
207208
}
208209
}
209210

211+
@Override
212+
public InputStream downloadV3(URI url) throws WxPayException {
213+
CloseableHttpClient httpClient = this.createApiV3HttpClient();
214+
HttpGet httpGet = new HttpGet(url);
215+
httpGet.addHeader("Accept", ContentType.WILDCARD.getMimeType());
216+
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
217+
//v3已经改为通过状态码判断200 204 成功
218+
int statusCode = response.getStatusLine().getStatusCode();
219+
if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
220+
this.log.info("\n【请求地址】:{}\n", url);
221+
return response.getEntity().getContent();
222+
} else {
223+
//有错误提示信息返回
224+
String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
225+
JsonObject jsonObject = GsonParser.parse(responseString);
226+
throw new WxPayException(jsonObject.get("message").getAsString());
227+
}
228+
} catch (Exception e) {
229+
this.log.error("\n【请求地址】:{}\n【异常信息】:{}", url, e.getMessage());
230+
throw new WxPayException(e.getMessage(), e);
231+
} finally {
232+
httpGet.releaseConnection();
233+
}
234+
}
235+
210236
private CloseableHttpClient createApiV3HttpClient() throws WxPayException {
211237
CloseableHttpClient apiV3HttpClient = this.getConfig().getApiV3HttpClient();
212238
if (null == apiV3HttpClient) {

weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.apache.http.client.methods.HttpPost;
1414

1515
import javax.net.ssl.SSLContext;
16+
import java.io.InputStream;
1617
import java.net.URI;
1718
import java.nio.charset.StandardCharsets;
1819
import java.util.Base64;
@@ -80,6 +81,11 @@ public String getV3(URI url) throws WxPayException {
8081
return null;
8182
}
8283

84+
@Override
85+
public InputStream downloadV3(URI url) throws WxPayException {
86+
return null;
87+
}
88+
8389
private HttpRequest buildHttpRequest(String url, String requestStr, boolean useKey) throws WxPayException {
8490
HttpRequest request = HttpRequest
8591
.post(url)

0 commit comments

Comments
 (0)