diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/CouponBgColor.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/CouponBgColor.java index 392111f..1cb4b7b 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/CouponBgColor.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/CouponBgColor.java @@ -20,7 +20,7 @@ package cn.felord.payment.wechat.enumeration; /** * 优惠券背景色 *

- * https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_1.shtml#menu1 + * 详见优惠券背景色参考 * * @author felord.cn * @since 1.0.0.RELEASE diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/FundFlowAccountType.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/FundFlowAccountType.java new file mode 100644 index 0000000..effbbf8 --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/FundFlowAccountType.java @@ -0,0 +1,38 @@ +/* + * + * Copyright 2019-2021 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.felord.payment.wechat.enumeration; + +/** + * 申请资金账单账户类型. + * + * @since 1.0.3.RELEASE + */ +public enum FundFlowAccountType { + /** + * 基本账户 + */ + BASIC, + /** + * 运营账户 + */ + OPERATION, + /** + * 手续费账户 + */ + FEES +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/TarType.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/TarType.java new file mode 100644 index 0000000..5d0c90d --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/TarType.java @@ -0,0 +1,31 @@ +/* + * + * Copyright 2019-2021 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.felord.payment.wechat.enumeration; + +/** + * 账单压缩类型 + * + * @author felord.cn + * @since 1.0.3.RELEASE + */ +public enum TarType { + /** + * 格式为{@code .gzip}的压缩包账单 + */ + GZIP +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/TradeBillType.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/TradeBillType.java new file mode 100644 index 0000000..8f7473d --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/TradeBillType.java @@ -0,0 +1,40 @@ +/* + * + * Copyright 2019-2021 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.felord.payment.wechat.enumeration; + +/** + * 交易账单类型 + * + * @author felord.cn + * @since 1.0.3.RELEASE + */ +public enum TradeBillType { + /** + * 返回当日所有订单信息(不含充值退款订单) + */ + ALL, + /** + * 返回当日成功支付的订单(不含充值退款订单) + */ + SUCCESS, + /** + * 返回当日退款订单(不含充值退款订单) + */ + REFUND + +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java index c8decc6..96ef262 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/enumeration/WechatPayV3Type.java @@ -133,6 +133,18 @@ public enum WechatPayV3Type { * @since 1.0.0.RELEASE */ COMBINE_CLOSE(HttpMethod.POST, "%s/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close"), + /** + * 申请交易账单API. + * + * @since 1.0.3.RELEASE + */ + COMBINE_TRADEBILL(HttpMethod.POST, "%s/v3/bill/tradebill"), + /** + * 申请资金账单API. + * + * @since 1.0.3.RELEASE + */ + COMBINE_FUNDFLOWBILL(HttpMethod.POST, "%s/v3/bill/fundflowbill"), //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -222,7 +234,8 @@ public enum WechatPayV3Type { PAY_SCORE_SYNC_USER_SERVICE_ORDER(HttpMethod.POST, "%s/v3/payscore/serviceorder/{out_order_no}/sync"), -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /** * 微信先享卡预受理领卡请求API. * diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java index 2964e3d..04d078e 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/AbstractApi.java @@ -19,6 +19,7 @@ package cn.felord.payment.wechat.v3; import cn.felord.payment.PayException; +import cn.felord.payment.wechat.enumeration.WechatPayV3Type; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -27,6 +28,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.http.RequestEntity; import org.springframework.util.Assert; +import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; @@ -127,7 +129,7 @@ public abstract class AbstractApi { } /** - * Post request entity. + * 构建Post请求对象. * * @param uri the uri * @param params the params @@ -143,7 +145,7 @@ public abstract class AbstractApi { } /** - * Get request entity. + * 构建Get请求对象. * * @param uri the uri * @return the request entity @@ -152,4 +154,22 @@ public abstract class AbstractApi { return RequestEntity.get(uri).header("Pay-TenantId", tenantId) .build(); } + + + /** + * 对账单下载。 + * + * @param link the link + * @return 对账单内容,有可能为空字符 “” + */ + protected String billDownload(String link) { + return this.client().withType(WechatPayV3Type.FILE_DOWNLOAD, link) + .function((type, downloadUrl) -> { + URI uri = UriComponentsBuilder.fromHttpUrl(downloadUrl) + .build() + .toUri(); + return Get(uri); + }) + .download(); + } } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatCombinePayApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatCombinePayApi.java index 9c62786..1169705 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatCombinePayApi.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatCombinePayApi.java @@ -19,16 +19,20 @@ package cn.felord.payment.wechat.v3; import cn.felord.payment.wechat.WechatPayProperties; -import cn.felord.payment.wechat.enumeration.WeChatServer; -import cn.felord.payment.wechat.enumeration.WechatPayV3Type; -import cn.felord.payment.wechat.v3.model.combine.CombineCloseParams; -import cn.felord.payment.wechat.v3.model.combine.CombineH5PayParams; -import cn.felord.payment.wechat.v3.model.combine.CombinePayParams; +import cn.felord.payment.wechat.enumeration.*; +import cn.felord.payment.wechat.v3.model.combine.*; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.http.RequestEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Objects; +import java.util.Optional; /** * 微信合单支付. @@ -211,4 +215,85 @@ public class WechatCombinePayApi extends AbstractApi { .request(); return wechatResponseEntity; } + + /** + * 申请交易账单API + *

+ * 微信支付按天提供交易账单文件,商户可以通过该接口获取账单文件的下载地址。文件内包含交易相关的金额、时间、营销等信息,供商户核对订单、退款、银行到账等情况。 + *

+ * 注意: + *

+ * + * @param tradeBillParams tradeBillParams + * @since 1.0.3.RELEASE + */ + public void downloadTradeBill(TradeBillParams tradeBillParams) { + this.client().withType(WechatPayV3Type.COMBINE_TRADEBILL, tradeBillParams) + .function((wechatPayV3Type, params) -> { + MultiValueMap queryParams = new LinkedMultiValueMap<>(); + LocalDate billDate = params.getBillDate(); + queryParams.add("bill_date", billDate.format(DateTimeFormatter.ISO_DATE)); + String subMchid = params.getSubMchid(); + + if (StringUtils.hasText(subMchid)) { + queryParams.add("sub_mchid", subMchid); + } + + TradeBillType tradeBillType = Optional.ofNullable(params.getBillType()) + .orElse(TradeBillType.ALL); + queryParams.add("bill_type", tradeBillType.name()); + TarType tarType = params.getTarType(); + if (Objects.nonNull(tarType)) { + queryParams.add("tar_type", tarType.name()); + } + URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA)) + .queryParams(queryParams) + .build().toUri(); + return Get(uri); + }) + .consumer(response -> this.billDownload(Objects.requireNonNull(response.getBody()).get("download_url").asText())) + .request(); + } + + /** + * 申请资金账单API + *

+ * 微信支付按天提供微信支付账户的资金流水账单文件,商户可以通过该接口获取账单文件的下载地址。文件内包含该账户资金操作相关的业务单号、收支金额、记账时间等信息,供商户进行核对。 + *

+ * 注意: + *

+ * + * @param fundFlowBillParams fundFlowBillParams + * @since 1.0.3.RELEASE + */ + public void downloadFundFlowBill(FundFlowBillParams fundFlowBillParams) { + this.client().withType(WechatPayV3Type.COMBINE_FUNDFLOWBILL, fundFlowBillParams) + .function((wechatPayV3Type, params) -> { + MultiValueMap queryParams = new LinkedMultiValueMap<>(); + LocalDate billDate = params.getBillDate(); + queryParams.add("bill_date", billDate.format(DateTimeFormatter.ISO_DATE)); + + FundFlowAccountType accountType = Optional.ofNullable(params.getAccountType()) + .orElse(FundFlowAccountType.BASIC); + queryParams.add("account_type", accountType.name()); + TarType tarType = params.getTarType(); + if (Objects.nonNull(tarType)) { + queryParams.add("tar_type", tarType.name()); + } + URI uri = UriComponentsBuilder.fromHttpUrl(wechatPayV3Type.uri(WeChatServer.CHINA)) + .queryParams(queryParams) + .build().toUri(); + return Get(uri); + }) + .consumer(response -> this.billDownload(Objects.requireNonNull(response.getBody()).get("download_url").asText())) + .request(); + } } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java index ccfbce2..2209320 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatMarketingFavorApi.java @@ -490,6 +490,7 @@ public class WechatMarketingFavorApi extends AbstractApi { * * @param stockId the stock id * @return the wechat response entity + * @see AbstractApi#billDownload(String) 对账单下载api */ public WechatResponseEntity downloadStockUseFlow(String stockId) { WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); @@ -497,7 +498,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .function(this::downloadFlowFunction) .consumer(wechatResponseEntity::convert) .request(); - String csv = billDownload(wechatResponseEntity.getBody().get("url").asText()); + String csv = this.billDownload(wechatResponseEntity.getBody().get("url").asText()); wechatResponseEntity.getBody().put("csv", csv); return wechatResponseEntity; } @@ -511,6 +512,7 @@ public class WechatMarketingFavorApi extends AbstractApi { * * @param stockId the stock id * @return the wechat response entity + * @see AbstractApi#billDownload(String) 对账单下载api */ public WechatResponseEntity downloadStockRefundFlow(String stockId) { WechatResponseEntity wechatResponseEntity = new WechatResponseEntity<>(); @@ -518,7 +520,7 @@ public class WechatMarketingFavorApi extends AbstractApi { .function(this::downloadFlowFunction) .consumer(wechatResponseEntity::convert) .request(); - String csv = billDownload(wechatResponseEntity.getBody().get("url").asText()); + String csv = this.billDownload(wechatResponseEntity.getBody().get("url").asText()); wechatResponseEntity.getBody().put("csv", csv); return wechatResponseEntity; } @@ -629,35 +631,6 @@ public class WechatMarketingFavorApi extends AbstractApi { .toUri(); return Post(uri, body); } - - /** - * csv对账单下载。 - * - * @param link the link - * @return the string - * @see WechatMarketingFavorApi#downloadStockUseFlow(String) 下载批次核销明细API - * @see WechatMarketingFavorApi#downloadStockRefundFlow(String) 下载批次退款明细API - */ - public String billDownload(String link) { - return this.client().withType(WechatPayV3Type.FILE_DOWNLOAD, link) - .function(this::billDownloadFunction) - .download(); - } - - - /** - * Bill download function request entity. - * - * @param type the type - * @param link the link - * @return the request entity - */ - private RequestEntity billDownloadFunction(WechatPayV3Type type, String link) { - URI uri = UriComponentsBuilder.fromHttpUrl(link) - .build() - .toUri(); - return Get(uri); - } } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java index efe1a10..e2011f0 100644 --- a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/WechatPayClient.java @@ -37,6 +37,7 @@ import org.springframework.web.util.UriComponentsBuilder; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -238,7 +239,7 @@ public class WechatPayClient { // 微信请求id String requestId = headers.getFirst("Request-ID"); if (!statusCode.is2xxSuccessful()) { - throw new PayException("wechat pay server error, Request-ID "+requestId+" , statusCode " + statusCode + ",result : " + body); + throw new PayException("wechat pay server error, Request-ID " + requestId + " , statusCode " + statusCode + ",result : " + body); } ResponseSignVerifyParams params = new ResponseSignVerifyParams(); @@ -261,7 +262,7 @@ public class WechatPayClient { responseConsumer.accept(responseEntity); } } else { - throw new PayException("wechat pay signature failed, Request-ID "+requestId ); + throw new PayException("wechat pay signature failed, Request-ID " + requestId); } } @@ -276,17 +277,13 @@ public class WechatPayClient { ResponseEntity responseEntity = restOperations.exchange(requestEntity, String.class); - String body = responseEntity.getBody(); HttpStatus statusCode = responseEntity.getStatusCode(); // 微信请求id String requestId = requestEntity.getHeaders().getFirst("Request-ID"); if (!statusCode.is2xxSuccessful()) { - throw new PayException("wechat pay server error, Request-ID "+requestId+" , statusCode " + statusCode + ",result : " + body); + throw new PayException("wechat pay server error, Request-ID " + requestId + " , statusCode " + statusCode + ",result : " + responseEntity); } - if (Objects.isNull(body)) { - throw new PayException("cant obtain wechat response body, Request-ID "+requestId); - } - return body; + return Optional.ofNullable(responseEntity.getBody()).orElse(""); } } diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/combine/FundFlowBillParams.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/combine/FundFlowBillParams.java new file mode 100644 index 0000000..e889562 --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/combine/FundFlowBillParams.java @@ -0,0 +1,52 @@ +/* + * + * Copyright 2019-2021 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.felord.payment.wechat.v3.model.combine; + +import cn.felord.payment.wechat.enumeration.FundFlowAccountType; +import cn.felord.payment.wechat.enumeration.TarType; +import lombok.Data; + +import java.time.LocalDate; + +/** + * 合单支付申请资金账单请求参数 + * + * @author felord.cn + * @since 1.0.3.RELEASE + */ +@Data +public class FundFlowBillParams { + /** + * 账单日期,必传。 + *

+ * 格式YYYY-MM-DD,仅支持三个月内的账单下载申请。 + */ + private LocalDate billDate; + /** + * 资金账户类型,不填则默认值为{@link FundFlowAccountType#BASIC} + * + * @see FundFlowAccountType + */ + private FundFlowAccountType accountType; + /** + * 压缩类型,不填默认值为数据流 + * + * @see TarType + */ + private TarType tarType; +} diff --git a/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/combine/TradeBillParams.java b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/combine/TradeBillParams.java new file mode 100644 index 0000000..df7b80f --- /dev/null +++ b/payment-spring-boot-autoconfigure/src/main/java/cn/felord/payment/wechat/v3/model/combine/TradeBillParams.java @@ -0,0 +1,70 @@ +/* + * + * Copyright 2019-2021 felord.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * Website: + * https://felord.cn + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.felord.payment.wechat.v3.model.combine; + +import cn.felord.payment.wechat.enumeration.TarType; +import cn.felord.payment.wechat.enumeration.TradeBillType; +import lombok.Data; + +import java.time.LocalDate; + +/** + * 合单支付申请交易账单请求参数 + * + * @author felord.cn + * @since 1.0.3.RELEASE + */ +@Data +public class TradeBillParams { + /** + * 账单日期,必传。 + *

+ * 格式YYYY-MM-DD,仅支持三个月内的账单下载申请。 + */ + private LocalDate billDate; + /** + * 二级商户号,选填。 + * + *

    + *
  1. 若商户是直连商户:无需填写该字段。
  2. + *
  3. 若商户是服务商: + *
      + *
    • 不填则默认返回服务商下的交易或退款数据。
    • + *
    • 如需下载某个子商户下的交易或退款数据,则该字段必填。
    • + *
    + *
  4. + *
+ *

+ * 特殊规则:最小字符长度为8 + *

+ * 注意:仅适用于电商平台 服务商 + */ + private String subMchid; + /** + * 账单类型,不填则默认值为{@link TradeBillType#ALL} + * + * @see TradeBillType + */ + private TradeBillType billType; + /** + * 压缩类型,不填默认值为数据流 + * + * @see TarType + */ + private TarType tarType; +}