mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-04-05 17:38:05 +08:00
🆕 #1885 【微信支付】电商收付通增加资金账单下载的接口
This commit is contained in:
parent
57ab245093
commit
b4da5c9fe4
@ -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 {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:账单日期
|
||||
* 变量名:bill_date
|
||||
* 是否必填:是
|
||||
* 类型:string(10)
|
||||
* 描述:
|
||||
* 格式YYYY-MM-DD
|
||||
* 仅支持三个月内的账单下载申请。
|
||||
* 示例值:2019-06-11
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "bill_date")
|
||||
private String billDate;
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:资金账户类型
|
||||
* 变量名:account_type
|
||||
* 是否必填:是
|
||||
* 类型:string(32)
|
||||
* 描述:
|
||||
* 枚举值:
|
||||
* ALL:所有账户
|
||||
* 示例值:ALL
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "account_type")
|
||||
private String accountType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:压缩类型
|
||||
* 变量名:tar_type
|
||||
* 是否必填:否
|
||||
* 类型:string(32)
|
||||
* 描述:
|
||||
* 不填则以不压缩的方式返回数据流
|
||||
* 枚举值:
|
||||
* GZIP:返回格式为.gzip的压缩包账单
|
||||
* 示例值:GZIP
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "tar_type")
|
||||
private String tarType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:加密算法
|
||||
* 变量名:algorithm
|
||||
* 是否必填:是
|
||||
* 类型:string(32)
|
||||
* 描述:
|
||||
* 枚举值:
|
||||
* AEAD_AES_256_GCM:AEAD_AES_256_GCM加密算法
|
||||
* 示例值:AEAD_AES_256_GCM
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "algorithm")
|
||||
private String algorithm;
|
||||
}
|
@ -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 {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:下载信息总数
|
||||
* 变量名:download_bill_count
|
||||
* 是否必填:是
|
||||
* 类型:int
|
||||
* 描述:
|
||||
* 下载信息总数
|
||||
* 示例值:1
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "download_bill_count")
|
||||
private int downloadBillCount;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:下载信息明细
|
||||
* 变量名:download_bill_list
|
||||
* 是否必填:否
|
||||
* 类型:array
|
||||
* 描述:
|
||||
* 下载信息明细
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "download_bill_list")
|
||||
private FundBill[] downloadBillList;
|
||||
|
||||
@Data
|
||||
public static class FundBill {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:账单文件序号
|
||||
* 变量名:bill_sequence
|
||||
* 是否必填:是
|
||||
* 类型:int
|
||||
* 描述:
|
||||
* 商户将多个文件按账单文件序号的顺序合并为完整的资金账单文件,起始值为1
|
||||
* 示例值:1
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "bill_sequence")
|
||||
private String billSequence;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:哈希类型
|
||||
* 变量名:hash_type
|
||||
* 是否必填:是
|
||||
* 类型:string(32)
|
||||
* 描述:
|
||||
* 枚举值:
|
||||
* SHA1:SHA1值
|
||||
* 示例值:SHA1
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "hash_type")
|
||||
private String hashType;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:哈希值
|
||||
* 变量名:hash_value
|
||||
* 是否必填:是
|
||||
* 类型:string(1024)
|
||||
* 描述:
|
||||
* 原始账单(gzip需要解压缩)的摘要值,用于校验文件的完整性。
|
||||
* 示例值:79bb0f45fc4c42234a918000b2668d689e2bde04
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "hash_value")
|
||||
private String hashValue;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:账单下载地址
|
||||
* 变量名:download_url
|
||||
* 是否必填:是
|
||||
* 类型:string(2048)
|
||||
* 描述:
|
||||
* 供下一步请求账单文件的下载地址,该地址30s内有效。
|
||||
* 示例值:https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "download_url")
|
||||
private String downloadUrl;
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:加密密钥
|
||||
* 变量名:encrypt_key
|
||||
* 是否必填:是
|
||||
* 类型:string(512)
|
||||
* 描述:
|
||||
* 加密账单文件使用的加密密钥。密钥用商户证书的公钥进行加密,然后进行Base64编码
|
||||
* 示例值:YpkbxSne+mDwyXq//xYPmtr9eQ5LsH7zLMZSs+GSEcY4wjhlsfioS4n9X6q1ZBL0wM1v5qd7KhWuj0rFJ4N1FidP7Q8KDy25QDTt46wiKnsPKSCAXWRFNw1D2JmJBqZsc9y5g0DupONWKYB2GfRigRDEBVszj67uOIILPdxOKX1w3N4jvu0U9IFanJa7ldm70KVvYrMWVgQFDPbgjh1gVDbuTAjmPN88AobLdkiegnBUS2woDZW+PfhPo13kweOiR3h1gXIKRlnKnN3Jkkwpna/AFFijXrFphO3voSuiV0CfptfzTtcae4X3DYG3RSroKqmpa+5tuy2aU2VJUSIuFQ==
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "encrypt_key")
|
||||
private String encryptKey;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:随机字符串
|
||||
* 变量名:nonce
|
||||
* 是否必填:是
|
||||
* 类型:string(16)
|
||||
* 描述:
|
||||
* 加密账单文件使用的随机字符串
|
||||
* 示例值:a8607ef79034c49c
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "nonce")
|
||||
private String nonce;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 账单请求
|
||||
* 交易账单请求
|
||||
* @author: f00lish
|
||||
* @date: 2020/09/28
|
||||
*/
|
||||
@ -13,7 +13,7 @@ import lombok.*;
|
||||
@ToString
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class BillRequest {
|
||||
public class TradeBillRequest {
|
||||
|
||||
/**
|
||||
* <pre>
|
@ -4,7 +4,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 账单结果
|
||||
* 交易账单结果
|
||||
* @author: f00lish
|
||||
* @date: 2020/09/28
|
||||
*/
|
||||
@ -13,7 +13,7 @@ import lombok.*;
|
||||
@ToString
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class BillResult {
|
||||
public class TradeBillResult {
|
||||
|
||||
/**
|
||||
* <pre>
|
@ -10,17 +10,16 @@ import lombok.Getter;
|
||||
*/
|
||||
@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
|
@ -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
|
||||
* </pre>
|
||||
*
|
||||
* @param billType 账单类型。
|
||||
* @param request 二级商户号。
|
||||
* @return 返回数据 return bill result
|
||||
* @param request 请求信息。
|
||||
* @return 返回数据 return trade bill result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
BillResult applyBill(BillTypeEnum billType, BillRequest request) throws WxPayException;
|
||||
TradeBillResult applyBill(TradeBillRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 申请资金账单API
|
||||
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/bill/chapter3_2.shtml
|
||||
* </pre>
|
||||
*
|
||||
* @param billType 账单类型。
|
||||
* @param request 请求信息。
|
||||
* @return 返回数据 return fund bill result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
FundBillResult applyFundBill(FundBillTypeEnum billType, FundBillRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
|
@ -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 class EcommerceServiceImpl implements EcommerceService {
|
||||
}
|
||||
|
||||
@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
|
||||
|
@ -4,6 +4,11 @@ import com.google.common.base.CharMatcher;
|
||||
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.Base64;
|
||||
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 class AesUtils {
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user