diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillRequest.java new file mode 100644 index 0000000000..9f12bc3781 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillRequest.java @@ -0,0 +1,79 @@ +package com.github.binarywang.wxpay.bean.ecommerce; + +import com.google.gson.annotations.SerializedName; +import lombok.*; + +/** + * 资金账单请求 + * @author: f00lish + * @date: 2020/09/28 + */ +@Data +@Builder +@ToString +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class FundBillRequest { + + /** + *
+ * 字段名:账单日期 + * 变量名:bill_date + * 是否必填:是 + * 类型:string(10) + * 描述: + * 格式YYYY-MM-DD + * 仅支持三个月内的账单下载申请。 + * 示例值:2019-06-11 + *+ */ + @SerializedName(value = "bill_date") + private String billDate; + + + /** + *
+ * 字段名:资金账户类型 + * 变量名:account_type + * 是否必填:是 + * 类型:string(32) + * 描述: + * 枚举值: + * ALL:所有账户 + * 示例值:ALL + *+ */ + @SerializedName(value = "account_type") + private String accountType; + + /** + *
+ * 字段名:压缩类型 + * 变量名:tar_type + * 是否必填:否 + * 类型:string(32) + * 描述: + * 不填则以不压缩的方式返回数据流 + * 枚举值: + * GZIP:返回格式为.gzip的压缩包账单 + * 示例值:GZIP + *+ */ + @SerializedName(value = "tar_type") + private String tarType; + + /** + *
+ * 字段名:加密算法 + * 变量名:algorithm + * 是否必填:是 + * 类型:string(32) + * 描述: + * 枚举值: + * AEAD_AES_256_GCM:AEAD_AES_256_GCM加密算法 + * 示例值:AEAD_AES_256_GCM + *+ */ + @SerializedName(value = "algorithm") + private String algorithm; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java new file mode 100644 index 0000000000..de0dcdb890 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java @@ -0,0 +1,139 @@ +package com.github.binarywang.wxpay.bean.ecommerce; + +import com.google.gson.annotations.SerializedName; +import lombok.*; + +/** + * 资金账单结果 + * @author: f00lish + * @date: 2020/09/28 + */ +@Data +@Builder +@ToString +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class FundBillResult { + + /** + *
+ * 字段名:下载信息总数 + * 变量名:download_bill_count + * 是否必填:是 + * 类型:int + * 描述: + * 下载信息总数 + * 示例值:1 + *+ */ + @SerializedName(value = "download_bill_count") + private int downloadBillCount; + + + + /** + *
+ * 字段名:下载信息明细 + * 变量名:download_bill_list + * 是否必填:否 + * 类型:array + * 描述: + * 下载信息明细 + *+ */ + @SerializedName(value = "download_bill_list") + private FundBill[] downloadBillList; + + @Data + public static class FundBill { + + /** + *
+ * 字段名:账单文件序号 + * 变量名:bill_sequence + * 是否必填:是 + * 类型:int + * 描述: + * 商户将多个文件按账单文件序号的顺序合并为完整的资金账单文件,起始值为1 + * 示例值:1 + *+ */ + @SerializedName(value = "bill_sequence") + private String billSequence; + + /** + *
+ * 字段名:哈希类型 + * 变量名:hash_type + * 是否必填:是 + * 类型:string(32) + * 描述: + * 枚举值: + * SHA1:SHA1值 + * 示例值:SHA1 + *+ */ + @SerializedName(value = "hash_type") + private String hashType; + + /** + *
+ * 字段名:哈希值 + * 变量名:hash_value + * 是否必填:是 + * 类型:string(1024) + * 描述: + * 原始账单(gzip需要解压缩)的摘要值,用于校验文件的完整性。 + * 示例值:79bb0f45fc4c42234a918000b2668d689e2bde04 + *+ */ + @SerializedName(value = "hash_value") + private String hashValue; + + /** + *
+ * 字段名:账单下载地址 + * 变量名:download_url + * 是否必填:是 + * 类型:string(2048) + * 描述: + * 供下一步请求账单文件的下载地址,该地址30s内有效。 + * 示例值:https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx + *+ */ + @SerializedName(value = "download_url") + private String downloadUrl; + + + /** + *
+ * 字段名:加密密钥 + * 变量名:encrypt_key + * 是否必填:是 + * 类型:string(512) + * 描述: + * 加密账单文件使用的加密密钥。密钥用商户证书的公钥进行加密,然后进行Base64编码 + * 示例值:YpkbxSne+mDwyXq//xYPmtr9eQ5LsH7zLMZSs+GSEcY4wjhlsfioS4n9X6q1ZBL0wM1v5qd7KhWuj0rFJ4N1FidP7Q8KDy25QDTt46wiKnsPKSCAXWRFNw1D2JmJBqZsc9y5g0DupONWKYB2GfRigRDEBVszj67uOIILPdxOKX1w3N4jvu0U9IFanJa7ldm70KVvYrMWVgQFDPbgjh1gVDbuTAjmPN88AobLdkiegnBUS2woDZW+PfhPo13kweOiR3h1gXIKRlnKnN3Jkkwpna/AFFijXrFphO3voSuiV0CfptfzTtcae4X3DYG3RSroKqmpa+5tuy2aU2VJUSIuFQ== + *+ */ + @SerializedName(value = "encrypt_key") + private String encryptKey; + + /** + *
+ * 字段名:随机字符串 + * 变量名:nonce + * 是否必填:是 + * 类型:string(16) + * 描述: + * 加密账单文件使用的随机字符串 + * 示例值:a8607ef79034c49c + *+ */ + @SerializedName(value = "nonce") + private String nonce; + + + } + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/BillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/TradeBillRequest.java similarity index 97% rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/BillRequest.java rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/TradeBillRequest.java index 247b2a7d01..ad623edf56 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/BillRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/TradeBillRequest.java @@ -4,7 +4,7 @@ import lombok.*; /** - * 账单请求 + * 交易账单请求 * @author: f00lish * @date: 2020/09/28 */ @@ -13,7 +13,7 @@ @ToString @NoArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE) -public class BillRequest { +public class TradeBillRequest { /** *
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/BillResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/TradeBillResult.java similarity index 96% rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/BillResult.java rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/TradeBillResult.java index 4a5bdb9524..2fb7b60564 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/BillResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/TradeBillResult.java @@ -4,7 +4,7 @@ import lombok.*; /** - * 账单结果 + * 交易账单结果 * @author: f00lish * @date: 2020/09/28 */ @@ -13,7 +13,7 @@ @ToString @NoArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE) -public class BillResult { +public class TradeBillResult { /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/enums/BillTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/enums/FundBillTypeEnum.java similarity index 64% rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/enums/BillTypeEnum.java rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/enums/FundBillTypeEnum.java index 598ee4be4b..72aff3a02b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/enums/BillTypeEnum.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/enums/FundBillTypeEnum.java @@ -10,17 +10,16 @@ */ @Getter @AllArgsConstructor -public enum BillTypeEnum { +public enum FundBillTypeEnum { /** - * 交易账单 + * 资金账单 */ - TRADE_BILL("%s/v3/bill/tradebill?%s"), + FUND_FLOW_BILL("%s/v3/bill/fundflowbill?%s"), /** - * 资金账单 + * 二级商户资金账单 */ - FUND_FLOW_BILL("%s/v3/bill/fundflowbill?%s"); - + SUB_FUND_FLOW_BILL("%s/v3/ecommerce/bill/fundflowbill?%s"); /** * url diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java index 367f2e8e1e..91c58e7ac3 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java @@ -1,7 +1,7 @@ package com.github.binarywang.wxpay.service; import com.github.binarywang.wxpay.bean.ecommerce.*; -import com.github.binarywang.wxpay.bean.ecommerce.enums.BillTypeEnum; +import com.github.binarywang.wxpay.bean.ecommerce.enums.FundBillTypeEnum; import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum; import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum; import com.github.binarywang.wxpay.exception.WxPayException; @@ -394,12 +394,24 @@ public interface EcommerceService { * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/bill.shtml ** + * @param request 请求信息。 + * @return 返回数据 return trade bill result + * @throws WxPayException the wx pay exception + */ + TradeBillResult applyBill(TradeBillRequest request) throws WxPayException; + + /** + *+ * 申请资金账单API + * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/bill/chapter3_2.shtml + *+ * * @param billType 账单类型。 - * @param request 二级商户号。 - * @return 返回数据 return bill result + * @param request 请求信息。 + * @return 返回数据 return fund bill result * @throws WxPayException the wx pay exception */ - BillResult applyBill(BillTypeEnum billType, BillRequest request) throws WxPayException; + FundBillResult applyFundBill(FundBillTypeEnum billType, FundBillRequest request) throws WxPayException; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java index 67976caf31..58a02d8ff8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java @@ -1,7 +1,7 @@ package com.github.binarywang.wxpay.service.impl; import com.github.binarywang.wxpay.bean.ecommerce.*; -import com.github.binarywang.wxpay.bean.ecommerce.enums.BillTypeEnum; +import com.github.binarywang.wxpay.bean.ecommerce.enums.FundBillTypeEnum; import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum; import com.github.binarywang.wxpay.bean.ecommerce.enums.TradeTypeEnum; import com.github.binarywang.wxpay.exception.WxPayException; @@ -295,10 +295,17 @@ public SettlementResult querySettlement(String subMchid) throws WxPayException { } @Override - public BillResult applyBill(BillTypeEnum billType, BillRequest request) throws WxPayException { + public TradeBillResult applyBill(TradeBillRequest request) throws WxPayException { + String url = String.format("%s/v3/bill/tradebill?%s", this.payService.getPayBaseUrl(), this.parseURLPair(request)); + String response = this.payService.getV3(URI.create(url)); + return GSON.fromJson(response, TradeBillResult.class); + } + + @Override + public FundBillResult applyFundBill(FundBillTypeEnum billType, FundBillRequest request) throws WxPayException { String url = String.format(billType.getUrl(), this.payService.getPayBaseUrl(), this.parseURLPair(request)); String response = this.payService.getV3(URI.create(url)); - return GSON.fromJson(response, BillResult.class); + return GSON.fromJson(response, FundBillResult.class); } @Override diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java index 4030965ebe..2c8c40252f 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java @@ -4,6 +4,11 @@ import com.google.common.io.BaseEncoding; import org.apache.commons.lang3.StringUtils; +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; @@ -13,11 +18,6 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.SecretKeySpec; public class AesUtils { @@ -32,6 +32,31 @@ public AesUtils(byte[] key) { this.aesKey = key; } + public static byte[] decryptToByte(byte[] nonce, byte[] cipherData, byte[] key) + throws GeneralSecurityException { + return decryptToByte(null, nonce, cipherData, key); + } + + public static byte[] decryptToByte(byte[] associatedData, byte[] nonce, byte[] cipherData, byte[] key) + throws GeneralSecurityException { + try { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + + SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); + GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce); + + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, spec); + if (associatedData != null) { + cipher.updateAAD(associatedData); + } + return cipher.doFinal(cipherData); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new IllegalStateException(e); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException(e); + } + } + public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException { try { diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayBillResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayTradeFundBillResultTest.java similarity index 100% rename from weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayBillResultTest.java rename to weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayTradeFundBillResultTest.java