From cc6dd6567106bbaf61f73361cb0408ff728d8539 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=B1=BC=E4=B8=B8Cwivan?= <ccwriji@gmail.com>
Date: Wed, 5 Sep 2018 00:11:13 +0800
Subject: [PATCH] =?UTF-8?q?#503=20=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98?=
 =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B5=84=E9=87=91=E8=B4=A6=E5=8D=95=E4=B8=8B?=
 =?UTF-8?q?=E8=BD=BD=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../request/WxPayDownloadFundFlowRequest.java |  90 +++++++++++++
 .../bean/result/WxPayFundFlowBaseResult.java  |  71 +++++++++++
 .../bean/result/WxPayFundFlowResult.java      |  60 +++++++++
 .../wxpay/constant/WxPayConstants.java        |  25 +++-
 .../wxpay/service/WxPayService.java           |  81 ++++++------
 .../service/impl/BaseWxPayServiceImpl.java    | 119 ++++++++++++++++++
 .../impl/BaseWxPayServiceImplTest.java        |  26 ++++
 7 files changed, 433 insertions(+), 39 deletions(-)
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadFundFlowRequest.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowBaseResult.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayFundFlowResult.java

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;
+
+/**
+ * <pre>
+ *   微信支付下载资金账单请求参数类
+ * Created by cwivan on 2018-08-02.
+ * </pre>
+ *
+ * @author <a href="https://github.com/cwivan">cwivan</a>
+ */
+@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";
+
+  /**
+   * <pre>
+   * 对账单日期
+   * bill_date
+   * 是
+   * String(8)
+   * 20140603
+   * 下载对账单的日期,格式:20140603
+   * </pre>
+   */
+  @Required
+  @XStreamAlias("bill_date")
+  private String billDate;
+
+  /**
+   * <pre>
+   * 资金账户类型
+   * account_type
+   * 是
+   * Basic
+   * String(8)
+   * --Basic,基本账户
+   * --Operation,运营账户
+   * --Fees,手续费账户
+   * </pre>
+   */
+  @Required
+  @XStreamAlias("account_type")
+  private String accountType;
+
+  /**
+   * <pre>
+   * 压缩账单
+   * tar_type
+   * 否
+   * String(8)
+   * GZIP
+   * 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
+   * </pre>
+   */
+  @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;
+
+/**
+ * <pre>
+ * 下载资金账单接口响应结果对象类
+ * Created by cwivan on 2018-08-02.
+ * </pre>
+ *
+ * @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<WxPayFundFlowBaseResult> wxPayFundFlowBaseResultList;
+
+  /**
+   * 资金流水总笔数
+   */
+  private String totalRecord;
+
+  /**
+   * 收入笔数
+   */
+  private String incomeRecord;
+
+  /**
+   * 收入金额
+   */
+  private String incomeAmount;
+
+  /**
+   * 支出笔数
+   */
+  private String expenditureRecord;
+
+  /**
+   * 支出金额
+   */
+  private String expenditureAmount;
+
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
index 9dbe9d050..8668e812a 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
@@ -1,12 +1,11 @@
 package com.github.binarywang.wxpay.constant;
 
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.time.FastDateFormat;
+
 import java.text.Format;
 import java.util.List;
 
-import org.apache.commons.lang3.time.FastDateFormat;
-
-import com.google.common.collect.Lists;
-
 /**
  * <pre>
  * 微信支付常量类
@@ -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;
-
 /**
  * <pre>
  * 微信支付相关接口.
@@ -378,6 +353,42 @@ public interface WxPayService {
    */
   WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException;
 
+  /**
+   * <pre>
+   * 下载资金账单.
+   * 商户可以通过该接口下载自2017年6月1日起 的历史资金流水账单。
+   * 注意:
+   * 1、资金账单中的数据反映的是商户微信账户资金变动情况;
+   * 2、当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
+   * 3、资金账单中涉及金额的字段单位为“元”。
+   * 接口链接:https://api.mch.weixin.qq.com/pay/downloadfundflow
+   * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18">下载对账单</a>
+   * </pre>
+   *
+   * @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;
+
+  /**
+   * <pre>
+   * 下载资金账单.
+   * 商户可以通过该接口下载自2017年6月1日起 的历史资金流水账单。
+   * 注意:
+   * 1、资金账单中的数据反映的是商户微信账户资金变动情况;
+   * 2、当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
+   * 3、资金账单中涉及金额的字段单位为“元”。
+   * 接口链接:https://api.mch.weixin.qq.com/pay/downloadfundflow
+   * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_18">下载对账单</a>
+   * </pre>
+   *
+   * @param request 下载资金流水请求
+   * @return WxPayFundFlowResult对象
+   */
+  WxPayFundFlowResult downloadFundFlow(WxPayDownloadFundFlowRequest request) throws WxPayException;
+
   /**
    * <pre>
    * 提交刷卡支付.
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<String> 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<WxPayFundFlowBaseResult> 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();