diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java new file mode 100644 index 000000000..8ce06238e --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java @@ -0,0 +1,90 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.github.binarywang.wxpay.constant.WxPayConstants.AccountType; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import lombok.*; +import me.chanjar.weixin.common.annotation.Required; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; + +/** + *
+ * 微信支付下载资金账单请求参数类 + * Created by cwivan on 2018-08-02. + *+ * + * @author cwivan + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Builder(builderMethodName = "newBuilder") +@NoArgsConstructor +@AllArgsConstructor +@XStreamAlias("xml") +public class WxPayDownloadFundFlowRequest extends BaseWxPayRequest { + private static final String[] ACCOUNT_TYPES = new String[]{AccountType.BASIC, AccountType.OPERATION, AccountType.FEES}; + private static final String SIGN_TYPE_HMAC_SHA256 = "HMAC-SHA256"; + private static final String TAR_TYPE_GZIP = "GZIP"; + + /** + *
+ * 对账单日期 + * bill_date + * 是 + * String(8) + * 20140603 + * 下载对账单的日期,格式:20140603 + *+ */ + @Required + @XStreamAlias("bill_date") + private String billDate; + + /** + *
+ * 资金账户类型 + * account_type + * 是 + * Basic + * String(8) + * --Basic,基本账户 + * --Operation,运营账户 + * --Fees,手续费账户 + *+ */ + @Required + @XStreamAlias("account_type") + private String accountType; + + /** + *
+ * 压缩账单 + * tar_type + * 否 + * String(8) + * GZIP + * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。 + *+ */ + @XStreamAlias("tar_type") + private String tarType; + + @Override + protected void checkConstraints() throws WxPayException { + if (StringUtils.isNotBlank(this.getTarType()) && !TAR_TYPE_GZIP.equals(this.getTarType())) { + throw new WxPayException("tar_type值如果存在,只能为GZIP"); + } + + if (!ArrayUtils.contains(ACCOUNT_TYPES, this.getAccountType())) { + throw new WxPayException(String.format("account_type必须为%s其中之一,实际值:%s", + Arrays.toString(ACCOUNT_TYPES), this.getAccountType())); + } + /** + * 目前仅支持HMAC-SHA256 + */ + this.setSignType(SIGN_TYPE_HMAC_SHA256); + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java new file mode 100644 index 000000000..dc631314b --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java @@ -0,0 +1,71 @@ +package com.github.binarywang.wxpay.bean.result; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; + +/** + * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款 + * 业务类型:退款 收支类型:支出 收支金额(元):0.02 账户结余(元):0.17 资金变更提交申请人:system 备注:缺货 业务凭证号:REF4200000068201801293084726067 + * + * @author cwivan + */ +@Data +@NoArgsConstructor +public class WxPayFundFlowBaseResult implements Serializable { + private static final long serialVersionUID = 4474557532904682718L; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + /** + * 记账时间 + */ + private String BillingTime; + /** + * 微信支付业务单号 + */ + private String bizTransactionId; + /** + * 资金流水单号 + */ + private String fundFlowId; + /** + * 业务名称 + */ + private String bizName; + /** + * 业务类型 + */ + private String bizType; + /** + * 收支类型 + */ + private String financialType; + /** + * 收支金额(元) + */ + private String financialFee; + /** + * 账户结余(元) + */ + private String AccountBalance; + /** + * 资金变更提交申请人 + */ + private String fundApplicant; + /** + * 备注 + */ + private String memo; + /** + * 业务凭证号 + */ + private String bizVoucherId; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java new file mode 100644 index 000000000..2cfd56e8a --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java @@ -0,0 +1,60 @@ +package com.github.binarywang.wxpay.bean.result; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; +import java.util.List; + +/** + *
+ * 下载资金账单接口响应结果对象类 + * Created by cwivan on 2018-08-02. + *+ * + * @author cwivan + * @date 2018-08-02 + */ +@Data +@NoArgsConstructor +public class WxPayFundFlowResult implements Serializable{ + private static final long serialVersionUID = 8371500036495349207L; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); + } + + /** + * 资金流水返回对象 + */ + private List
* 微信支付常量类
@@ -106,6 +105,24 @@ public class WxPayConstants {
public static final String MICROPAY = "MICROPAY";
}
+ /**
+ * 账户类型
+ */
+ public static class AccountType{
+ /**
+ * 基本账户
+ */
+ public static final String BASIC = "Basic";
+ /**
+ * 运营账户
+ */
+ public static final String OPERATION = "Operation";
+ /**
+ * Fees
+ */
+ public static final String FEES = "Fees";
+ }
+
/**
* 签名类型.
*/
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
index 7e3dd1964..e1dccd434 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
@@ -1,44 +1,19 @@
package com.github.binarywang.wxpay.service;
+import com.github.binarywang.wxpay.bean.WxPayApiData;
+import com.github.binarywang.wxpay.bean.coupon.*;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
+import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult;
+import com.github.binarywang.wxpay.bean.request.*;
+import com.github.binarywang.wxpay.bean.result.*;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+
import java.io.File;
import java.util.Date;
import java.util.Map;
-import com.github.binarywang.wxpay.bean.WxPayApiData;
-import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryRequest;
-import com.github.binarywang.wxpay.bean.coupon.WxPayCouponInfoQueryResult;
-import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
-import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
-import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryRequest;
-import com.github.binarywang.wxpay.bean.coupon.WxPayCouponStockQueryResult;
-import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
-import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
-import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult;
-import com.github.binarywang.wxpay.bean.request.WxPayAuthcode2OpenidRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayDownloadBillRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayReportRequest;
-import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayShorturlRequest;
-import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
-import com.github.binarywang.wxpay.bean.result.WxPayBillResult;
-import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
-import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
-import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
-import com.github.binarywang.wxpay.bean.result.WxPayOrderReverseResult;
-import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult;
-import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
-import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
-import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult;
-import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
-import com.github.binarywang.wxpay.config.WxPayConfig;
-import com.github.binarywang.wxpay.exception.WxPayException;
-
/**
*
* 微信支付相关接口.
@@ -378,6 +353,42 @@ public interface WxPayService {
*/
WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException;
+ /**
+ *
+ * 下载资金账单.
+ * 商户可以通过该接口下载自2017年6月1日起 的历史资金流水账单。
+ * 注意:
+ * 1、资金账单中的数据反映的是商户微信账户资金变动情况;
+ * 2、当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
+ * 3、资金账单中涉及金额的字段单位为“元”。
+ * 接口链接:https://api.mch.weixin.qq.com/pay/downloadfundflow
+ * 详情请见: 下载对账单
+ *
+ *
+ * @param billDate 资金账单日期 bill_date 下载对账单的日期,格式:20140603
+ * @param accountType 资金账户类型 account_type Basic,基本账户,Operation,运营账户,Fees,手续费账户
+ * @param tarType 压缩账单 tar_type 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
+ * @return WxPayFundFlowResult对象
+ */
+ WxPayFundFlowResult downloadFundFlow(String billDate, String accountType, String tarType) throws WxPayException;
+
+ /**
+ *
+ * 下载资金账单.
+ * 商户可以通过该接口下载自2017年6月1日起 的历史资金流水账单。
+ * 注意:
+ * 1、资金账单中的数据反映的是商户微信账户资金变动情况;
+ * 2、当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
+ * 3、资金账单中涉及金额的字段单位为“元”。
+ * 接口链接:https://api.mch.weixin.qq.com/pay/downloadfundflow
+ * 详情请见: 下载对账单
+ *
+ *
+ * @param request 下载资金流水请求
+ * @return WxPayFundFlowResult对象
+ */
+ WxPayFundFlowResult downloadFundFlow(WxPayDownloadFundFlowRequest request) throws WxPayException;
+
/**
*
* 提交刷卡支付.
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index c627dcae1..a113ca12a 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -581,6 +581,125 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
return wxPayBillResult;
}
+ @Override
+ public WxPayFundFlowResult downloadFundFlow(String billDate, String accountType, String tarType) throws WxPayException {
+
+ WxPayDownloadFundFlowRequest request = new WxPayDownloadFundFlowRequest();
+ request.setBillDate(billDate);
+ request.setAccountType(accountType);
+ request.setTarType(tarType);
+
+ return this.downloadFundFlow(request);
+ }
+
+ @Override
+ public WxPayFundFlowResult downloadFundFlow(WxPayDownloadFundFlowRequest request) throws WxPayException {
+ request.checkAndSign(this.getConfig());
+
+ String url = this.getPayBaseUrl() + "/pay/downloadfundflow";
+
+ String responseContent;
+ if (TarType.GZIP.equals(request.getTarType())) {
+ responseContent = this.handleGzipFundFlow(url, request.toXML());
+ } else {
+ responseContent = this.post(url, request.toXML(), true);
+ if (responseContent.startsWith("<")) {
+ throw WxPayException.from(BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class));
+ }
+ }
+
+ return this.handleFundFlow(responseContent);
+ }
+
+ private String handleGzipFundFlow(String url, String requestStr) throws WxPayException {
+ try {
+ byte[] responseBytes = this.postForBytes(url, requestStr, true);
+ Path tempDirectory = Files.createTempDirectory("fundFlow");
+ Path path = Paths.get(tempDirectory.toString(), System.currentTimeMillis() + ".gzip");
+ Files.write(path, responseBytes);
+
+ try {
+ List allLines = Files.readAllLines(ZipUtil.ungzip(path.toFile()).toPath(), StandardCharsets.UTF_8);
+ return Joiner.on("\n").join(allLines);
+ } catch (ZipException e) {
+ if (e.getMessage().contains("Not in GZIP format")) {
+ throw WxPayException.from(BaseWxPayResult.fromXML(new String(responseBytes, StandardCharsets.UTF_8),
+ WxPayCommonResult.class));
+ } else {
+ this.log.error("解压zip文件出错", e);
+ throw new WxPayException("解压zip文件出错");
+ }
+ }
+ } catch (WxPayException wxPayException) {
+ throw wxPayException;
+ } catch (Exception e){
+ this.log.error("解析对账单文件时出错", e);
+ throw new WxPayException("解压zip文件出错");
+ }
+ }
+
+ private WxPayFundFlowResult handleFundFlow(String responseContent) {
+ WxPayFundFlowResult wxPayFundFlowResult = new WxPayFundFlowResult();
+
+ String listStr = "";
+ String objStr = "";
+
+ if (StringUtils.isNotBlank(responseContent) && responseContent.contains("资金流水总笔数")) {
+ listStr = responseContent.substring(0, responseContent.indexOf("资金流水总笔数"));
+ objStr = responseContent.substring(responseContent.indexOf("资金流水总笔数"));
+ }
+ /*
+ * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款
+ * 业务类型:退款 收支类型:支出 收支金额(元):0.02 账户结余(元):0.17 资金变更提交申请人:system 备注:缺货 业务凭证号:REF4200000068201801293084726067
+ * 参考以上格式进行取值
+ */
+ List wxPayFundFlowBaseResultList = new LinkedList<>();
+ // 去空格
+ String newStr = listStr.replaceAll(",", " ");
+ // 数据分组
+ String[] tempStr = newStr.split("`");
+ // 分组标题
+ String[] t = tempStr[0].split(" ");
+ // 计算循环次数
+ int j = tempStr.length / t.length;
+ // 纪录数组下标
+ int k = 1;
+ for (int i = 0; i < j; i++) {
+ WxPayFundFlowBaseResult wxPayFundFlowBaseResult = new WxPayFundFlowBaseResult();
+
+ wxPayFundFlowBaseResult.setBillingTime(tempStr[k].trim());
+ wxPayFundFlowBaseResult.setBizTransactionId(tempStr[k + 1].trim());
+ wxPayFundFlowBaseResult.setFundFlowId(tempStr[k + 2].trim());
+ wxPayFundFlowBaseResult.setBizName(tempStr[k + 3].trim());
+ wxPayFundFlowBaseResult.setBizType(tempStr[k + 4].trim());
+ wxPayFundFlowBaseResult.setFinancialType(tempStr[k + 5].trim());
+ wxPayFundFlowBaseResult.setFinancialFee(tempStr[k + 6].trim());
+ wxPayFundFlowBaseResult.setAccountBalance(tempStr[k + 7].trim());
+ wxPayFundFlowBaseResult.setFundApplicant(tempStr[k + 8].trim());
+ wxPayFundFlowBaseResult.setMemo(tempStr[k + 9].trim());
+ wxPayFundFlowBaseResult.setBizVoucherId(tempStr[k + 10].trim());
+
+ wxPayFundFlowBaseResultList.add(wxPayFundFlowBaseResult);
+ k += t.length;
+ }
+ wxPayFundFlowResult.setWxPayFundFlowBaseResultList(wxPayFundFlowBaseResultList);
+
+ /*
+ * 资金流水总笔数,收入笔数,收入金额,支出笔数,支出金额 `20.0,`17.0,`0.35,`3.0,`0.18
+ * 参考以上格式进行取值
+ */
+ String totalStr = objStr.replaceAll(",", " ");
+ String[] totalTempStr = totalStr.split("`");
+ wxPayFundFlowResult.setTotalRecord(totalTempStr[1]);
+ wxPayFundFlowResult.setIncomeRecord(totalTempStr[2]);
+ wxPayFundFlowResult.setIncomeAmount(totalTempStr[3]);
+ wxPayFundFlowResult.setExpenditureRecord(totalTempStr[4]);
+ wxPayFundFlowResult.setExpenditureAmount(totalTempStr[5]);
+
+ return wxPayFundFlowResult;
+
+ }
+
@Override
public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException {
request.checkAndSign(this.getConfig());
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java
index 15cfdd825..8e01429ea 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImplTest.java
@@ -11,6 +11,7 @@ import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.constant.WxPayConstants.BillType;
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
+import com.github.binarywang.wxpay.constant.WxPayConstants.AccountType;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.testbase.ApiTestModule;
@@ -165,6 +166,31 @@ public class BaseWxPayServiceImplTest {
this.payService.downloadBill("", "", "", null);
}
+ @DataProvider
+ public Object[][] fundFlowData() {
+ return new Object[][]{
+ {"20180819", AccountType.BASIC, TarType.GZIP},
+ {"20180819", AccountType.OPERATION, TarType.GZIP},
+ {"20180819", AccountType.FEES, TarType.GZIP},
+ {"20180819", AccountType.BASIC, null},
+ {"20180819", AccountType.OPERATION, null},
+ {"20180819", AccountType.FEES, null}
+ };
+ }
+
+ @Test(dataProvider = "fundFlowData")
+ public void testDownloadFundFlow(String billDate, String accountType, String tarType) throws Exception {
+ WxPayFundFlowResult fundFlowResult = this.payService.downloadFundFlow(billDate, accountType, tarType);
+ assertThat(fundFlowResult).isNotNull();
+ this.logger.info(fundFlowResult.toString());
+ }
+
+ @Test(expectedExceptions = WxPayException.class)
+ public void testDownloadFundFlow_withNoParams() throws Exception {
+ //必填字段为空时,抛出异常
+ this.payService.downloadFundFlow("", "", null);
+ }
+
@Test
public void testReport() throws Exception {
WxPayReportRequest request = new WxPayReportRequest();