<commit_before>package com.github.binarywang.wxpay.service.impl;

import com.github.binarywang.wxpay.bean.ecommerce.FundBalanceResult;
import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum;
import com.github.binarywang.wxpay.bean.marketing.transfer.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerTransferService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.io.InputStream;

/**
 * 批量转账到零钱（服务商）
 *
 * @author xiaoqiang
 * @date 2021-12-06
 */
@Slf4j
@RequiredArgsConstructor
public class PartnerTransferServiceImpl implements PartnerTransferService {

  private static final Gson GSON = new GsonBuilder().create();
  private final WxPayService payService;

  /**
   * 发起批量转账API
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches
   * 请求方式：POST
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param request 请求对象
   * @return 返回数据 {@link PartnerTransferResult}
   * @throws WxPayException the wx pay exception
   */
  @Override
  public PartnerTransferResult batchTransfer(PartnerTransferRequest request) throws WxPayException {
    request.getTransferDetailList().stream().forEach(p -> {
      try {
        String userName = RsaCryptoUtil.encryptOAEP(p.getUserName(), this.payService.getConfig().getVerifier().getValidCertificate());
        p.setUserName(userName);
      } catch (IllegalBlockSizeException e) {
        throw new RuntimeException("姓名转换异常!", e);
      }
    });
    String url = String.format("%s/v3/partner-transfer/batches", this.payService.getPayBaseUrl());
    String response = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
    return GSON.fromJson(response, PartnerTransferResult.class);
  }

  /**
   * 微信支付批次单号查询批次单API
   * 接口说明
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/{batch_id}
   * https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/1030000071100999991182020050700019480001?need_query_detail=true&offset=1
   * 请求方式：GET
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param request 请求对象
   * @return 返回数据 {@link BatchNumberResult}
   * @throws WxPayException the wx pay exception
   */
  @Override
  public BatchNumberResult queryBatchByBatchId(BatchNumberRequest request) throws WxPayException {
    String url = String.format("%s/v3/partner-transfer/batches/batch-id/%s", this.payService.getPayBaseUrl(), request.getBatchId());
    if (request.getOffset() == null) {
      request.setOffset(0);
    }
    if (request.getLimit() == null || request.getLimit() <= 0) {
      request.setLimit(20);
    }
    String query = String.format("?need_query_detail=true&detail_status=ALL&offset=%s&limit=%s", request.getNeedQueryDetail(), request.getOffset(), request.getLimit());
    if (StringUtil.isNotBlank(request.getDetailStatus())){
      query += "&detail_status="+request.getDetailStatus();
    }
    String response = this.payService.getV3(url + query);
    return GSON.fromJson(response, BatchNumberResult.class);
  }

  /**
   * 商家批次单号查询批次单API
   * 接口说明
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches/out-batch-no/{out_batch_no}
   * 请求方式：GET
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param request 请求对象
   * @return 返回数据 {@link BatchNumberResult}
   * @throws WxPayException the wx pay exception
   */
  @Override
  public BatchNumberResult queryBatchByOutBatchNo(MerchantBatchRequest request) throws WxPayException {
    String url = String.format("%s/v3/partner-transfer/batches/out-batch-no/%s", this.payService.getPayBaseUrl(), request.getOutBatchNo());
    if (request.getOffset() == null) {
      request.setOffset(0);
    }
    if (request.getLimit() == null || request.getLimit() <= 0) {
      request.setLimit(20);
    }
    String query = String.format("?need_query_detail=true&offset=%s&limit=%s", request.getNeedQueryDetail(), request.getOffset(), request.getLimit());
    if (StringUtil.isNotBlank(request.getDetailStatus())){
      query += "&detail_status="+request.getDetailStatus();
    }
    String response = this.payService.getV3(url + query);
    return GSON.fromJson(response, BatchNumberResult.class);
  }

  /**
   * 微信支付明细单号查询明细单API
   * 接口说明
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}
   * 请求方式：GET
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param batchId  微信批次单号
   * @param detailId 微信明细单号
   * @return 返回数据 {@link BatchDetailsResult}
   * @throws WxPayException      the wx pay exception
   * @throws BadPaddingException the wx decrypt exception
   */
  @Override
  public BatchDetailsResult queryBatchDetailByWeChat(String batchId, String detailId) throws WxPayException, BadPaddingException {
    String url = String.format("%s/v3/partner-transfer/batches/batch-id/%s/details/detail-id/%s", this.payService.getPayBaseUrl(), batchId, detailId);
    String response = this.payService.getV3(url);
    BatchDetailsResult batchDetailsResult = GSON.fromJson(response, BatchDetailsResult.class);
    String userName = RsaCryptoUtil.decryptOAEP(batchDetailsResult.getUserName(), this.payService.getConfig().getPrivateKey());<commit_msg>:art: 修复代码<commit_after>package com.github.binarywang.wxpay.service.impl;

import com.github.binarywang.wxpay.bean.ecommerce.FundBalanceResult;
import com.github.binarywang.wxpay.bean.ecommerce.enums.SpAccountTypeEnum;
import com.github.binarywang.wxpay.bean.marketing.transfer.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerTransferService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.io.InputStream;

/**
 * 批量转账到零钱（服务商）
 *
 * @author xiaoqiang
 * @date 2021-12-06
 */
@Slf4j
@RequiredArgsConstructor
public class PartnerTransferServiceImpl implements PartnerTransferService {

  private static final Gson GSON = new GsonBuilder().create();
  private final WxPayService payService;

  /**
   * 发起批量转账API
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches
   * 请求方式：POST
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param request 请求对象
   * @return 返回数据 {@link PartnerTransferResult}
   * @throws WxPayException the wx pay exception
   */
  @Override
  public PartnerTransferResult batchTransfer(PartnerTransferRequest request) throws WxPayException {
    request.getTransferDetailList().stream().forEach(p -> {
      try {
        String userName = RsaCryptoUtil.encryptOAEP(p.getUserName(), this.payService.getConfig().getVerifier().getValidCertificate());
        p.setUserName(userName);
      } catch (IllegalBlockSizeException e) {
        throw new RuntimeException("姓名转换异常!", e);
      }
    });
    String url = String.format("%s/v3/partner-transfer/batches", this.payService.getPayBaseUrl());
    String response = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
    return GSON.fromJson(response, PartnerTransferResult.class);
  }

  /**
   * 微信支付批次单号查询批次单API
   * 接口说明
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/{batch_id}
   * https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/1030000071100999991182020050700019480001?need_query_detail=true&offset=1
   * 请求方式：GET
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param request 请求对象
   * @return 返回数据 {@link BatchNumberResult}
   * @throws WxPayException the wx pay exception
   */
  @Override
  public BatchNumberResult queryBatchByBatchId(BatchNumberRequest request) throws WxPayException {
    String url = String.format("%s/v3/partner-transfer/batches/batch-id/%s", this.payService.getPayBaseUrl(), request.getBatchId());
    if (request.getOffset() == null) {
      request.setOffset(0);
    }
    if (request.getLimit() == null || request.getLimit() <= 0) {
      request.setLimit(20);
    }
    String query = String.format("?need_query_detail=%s&detail_status=ALL&offset=%s&limit=%s", request.getNeedQueryDetail(), request.getOffset(), request.getLimit());
    if (StringUtil.isNotBlank(request.getDetailStatus())){
      query += "&detail_status="+request.getDetailStatus();
    }
    String response = this.payService.getV3(url + query);
    return GSON.fromJson(response, BatchNumberResult.class);
  }

  /**
   * 商家批次单号查询批次单API
   * 接口说明
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches/out-batch-no/{out_batch_no}
   * 请求方式：GET
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param request 请求对象
   * @return 返回数据 {@link BatchNumberResult}
   * @throws WxPayException the wx pay exception
   */
  @Override
  public BatchNumberResult queryBatchByOutBatchNo(MerchantBatchRequest request) throws WxPayException {
    String url = String.format("%s/v3/partner-transfer/batches/out-batch-no/%s", this.payService.getPayBaseUrl(), request.getOutBatchNo());
    if (request.getOffset() == null) {
      request.setOffset(0);
    }
    if (request.getLimit() == null || request.getLimit() <= 0) {
      request.setLimit(20);
    }
    String query = String.format("?need_query_detail=%s&offset=%s&limit=%s", request.getNeedQueryDetail(), request.getOffset(), request.getLimit());
    if (StringUtil.isNotBlank(request.getDetailStatus())){
      query += "&detail_status="+request.getDetailStatus();
    }
    String response = this.payService.getV3(url + query);
    return GSON.fromJson(response, BatchNumberResult.class);
  }

  /**
   * 微信支付明细单号查询明细单API
   * 接口说明
   * 适用对象：服务商
   * 请求URL：https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}
   * 请求方式：GET
   * 接口限频：单个服务商 50QPS，如果超过频率限制，会报错FREQUENCY_LIMITED，请降低频率请求。
   *
   * @param batchId  微信批次单号
   * @param detailId 微信明细单号
   * @return 返回数据 {@link BatchDetailsResult}
   * @throws WxPayException      the wx pay exception
   * @throws BadPaddingException the wx decrypt exception
   */
  @Override
  public BatchDetailsResult queryBatchDetailByWeChat(String batchId, String detailId) throws WxPayException, BadPaddingException {
    String url = String.format("%s/v3/partner-transfer/batches/batch-id/%s/details/detail-id/%s", this.payService.getPayBaseUrl(), batchId, detailId);
    String response = this.payService.getV3(url);
    BatchDetailsResult batchDetailsResult = GSON.fromJson(response, BatchDetailsResult.class);
    String userName = RsaCryptoUtil.decryptOAEP(batchDetailsResult.getUserName(), this.payService.getConfig().getPrivateKey());
{'fraction_non_alphanumeric': 0.12666490253153392, 'fraction_numerical': 0.014465908088559583, 'mean_word_length': 4.568762278978389, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 10, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3234229', 'n_tokens_mistral': 4257, 'n_tokens_neox': 4302, 'n_words': 562}