mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
🆕 #2443【微信支付】增加服务商微工卡相关功能接口以及微信批量转账到零钱的服务商接口实现
Co-authored-by: xiaoqiang <dengmingqiang@youmengbang.com>
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
package com.github.binarywang.wxpay.service;
|
||||
|
||||
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 javax.crypto.BadPaddingException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 微信批量转账到零钱【V3接口】服务商API
|
||||
*
|
||||
* @author xiaoqiang
|
||||
* @date 2021-12-06
|
||||
*/
|
||||
public interface PartnerTransferService {
|
||||
|
||||
/**
|
||||
* 发起批量转账API
|
||||
* 适用对象:服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_1.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/partner-transfer/batches
|
||||
* 请求方式:POST
|
||||
* 接口限频:单个服务商 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
PartnerTransferResult batchTransfer(PartnerTransferRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 微信支付批次单号查询批次单API
|
||||
* 接口说明
|
||||
* 适用对象:服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_2.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/partner-transfer/batches/batch-id/{batch_id}
|
||||
* 请求方式:GET
|
||||
* 接口限频:单个服务商 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
BatchNumberResult queryBatchByBatchId(BatchNumberRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 微信支付明细单号查询明细单API
|
||||
* 接口说明
|
||||
* 适用对象:服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_3.shtml
|
||||
* 请求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 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
* @throws BadPaddingException the wx decrypt exception
|
||||
*/
|
||||
BatchDetailsResult queryBatchDetailByWeChat(String batchId, String detailId) throws WxPayException, BadPaddingException;
|
||||
|
||||
/**
|
||||
* 商家批次单号查询批次单API
|
||||
* 接口说明
|
||||
* 适用对象:服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_4.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/partner-transfer/batches/out-batch-no/{out_batch_no}
|
||||
* 请求方式:GET
|
||||
* 接口限频:单个服务商 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
BatchNumberResult queryBatchByOutBatchNo(MerchantBatchRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 商家明细单号查询明细单API
|
||||
* 接口说明
|
||||
* 适用对象:服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_5.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/partner-transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}
|
||||
* 请求方式:GET
|
||||
* 接口限频:单个服务商 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
|
||||
*
|
||||
* @param outBatchNo 商家明细单号
|
||||
* @param outDetailNo 商家批次单号
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
* @throws BadPaddingException the wx decrypt exception
|
||||
*/
|
||||
BatchDetailsResult queryBatchDetailByMch(String outBatchNo, String outDetailNo) throws WxPayException, BadPaddingException;
|
||||
|
||||
|
||||
/**
|
||||
* 转账电子回单申请受理API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 商家批次单号
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
BillReceiptResult receiptBill(ReceiptBillRequest request) throws WxPayException;
|
||||
|
||||
|
||||
/**
|
||||
* 查询转账电子回单API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_2.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt/{out_batch_no}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param outBatchNo 商家批次单号
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
BillReceiptResult queryBillReceipt(String outBatchNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 转账明细电子回单受理API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_4.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer-detail/electronic-receipts
|
||||
* 请求方式:POST
|
||||
* 前置条件:只支持受理最近90天内的转账明细单
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
ElectronicReceiptsResult transferElectronic(ElectronicReceiptsRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 查询转账明细电子回单受理结果API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_5.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer-detail/electronic-receipts
|
||||
* 请求方式:GET
|
||||
* 前置条件:只支持查询最近90天内的转账明细单
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
ElectronicReceiptsResult queryTransferElectronicResult(ElectronicReceiptsRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 下载电子回单API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_3.shtml
|
||||
* 请求URL:通过申请账单接口获取到“download_url”,URL有效期10min
|
||||
* 请求方式:GET
|
||||
* 前置条件:调用申请账单接口并获取到“download_url”
|
||||
*
|
||||
* @param url 微信返回的电子回单地址。
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
InputStream transferDownload(String url) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询账户实时余额API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_1.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/merchant/fund/balance/{account_type}
|
||||
* 请求方式:GET
|
||||
* </pre>
|
||||
*
|
||||
* @param accountType 服务商账户类型 {@link SpAccountTypeEnum}
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
FundBalanceResult fundBalance(SpAccountTypeEnum accountType) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 服务商账户日终余额
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_2.shtml
|
||||
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/amount.shtml
|
||||
* </pre>
|
||||
*
|
||||
* @param accountType 服务商账户类型
|
||||
* @param date 查询日期 2020-09-11
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
FundBalanceResult spDayEndBalance(SpAccountTypeEnum accountType, String date);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.github.binarywang.wxpay.service;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.marketing.payroll.*;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
|
||||
/**
|
||||
* 微工卡-对接微信api
|
||||
*
|
||||
* @author xiaoqiang
|
||||
* @date 2021/12/7 14:26
|
||||
*/
|
||||
public interface PayrollService {
|
||||
/**
|
||||
* 生成授权token
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/tokens
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
TokensResult payrollCardTokens(TokensRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 查询微工卡授权关系API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/relations/{openid}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
RelationsResult payrollCardRelations(RelationsRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 微工卡核身预下单API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications/pre-order
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
PreOrderResult payrollCardPreOrder(PreOrderRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 获取核身结果API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications/{authenticate_number}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param subMchid 子商户号
|
||||
* @param authenticateNumber 商家核身单号
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
AuthenticationsResult payrollCardAuthenticationsNumber(String subMchid, String authenticateNumber) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 查询核身记录API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
AuthRecordResult payrollCardAuthentications(AuthRecordRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 微工卡核身预下单(流程中完成授权)
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications/pre-order-with-auth
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
PreOrderWithAuthResult payrollCardPreOrderWithAuth(PreOrderWithAuthRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 按日下载提现异常文件API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/merchant/fund/withdraw/bill-type/{bill_type}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param billType 账单类型
|
||||
* NO_SUCC:提现异常账单,包括提现失败和提现退票账单。
|
||||
* 示例值:NO_SUCC
|
||||
* @param billDate 账单日期 表示所在日期的提现账单,格式为YYYY-MM-DD。
|
||||
* 例如:2008-01-01日发起的提现,2008-01-03日银行返回提现失败,则该提现数据将出现在bill_date为2008-01-03日的账单中。
|
||||
* 示例值:2019-08-17
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
PreOrderWithAuthResult merchantFundWithdrawBillType(String billType, String billDate) throws WxPayException;
|
||||
|
||||
}
|
||||
@@ -179,6 +179,20 @@ public interface WxPayService {
|
||||
*/
|
||||
WxEntrustPapService getWxEntrustPapService();
|
||||
|
||||
/**
|
||||
* 获取批量转账到零钱服务类.
|
||||
*
|
||||
* @return the Batch transfer to change service
|
||||
*/
|
||||
PartnerTransferService getPartnerTransferService();
|
||||
|
||||
/**
|
||||
* 微工卡
|
||||
*
|
||||
* @return the micro card
|
||||
*/
|
||||
PayrollService getPayrollService();
|
||||
|
||||
/**
|
||||
* 获取企业付款服务类.
|
||||
*
|
||||
|
||||
@@ -75,7 +75,8 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
private final MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(this);
|
||||
private final MarketingBusiFavorService marketingBusiFavorService = new MarketingBusiFavorServiceImpl(this);
|
||||
private final WxEntrustPapService wxEntrustPapService = new WxEntrustPapServiceImpl(this);
|
||||
|
||||
private final PartnerTransferService partnerTransferService = new PartnerTransferServiceImpl(this);
|
||||
private final PayrollService payrollService = new PayrollServiceImpl(this);
|
||||
|
||||
protected Map<String, WxPayConfig> configMap;
|
||||
|
||||
@@ -144,6 +145,12 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
return wxEntrustPapService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartnerTransferService getPartnerTransferService(){return partnerTransferService;}
|
||||
|
||||
@Override
|
||||
public PayrollService getPayrollService(){return payrollService;}
|
||||
|
||||
@Override
|
||||
public WxPayConfig getConfig() {
|
||||
if (this.configMap.size() == 1) {
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
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());
|
||||
batchDetailsResult.setUserName(userName);
|
||||
return batchDetailsResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商家明细单号查询明细单API
|
||||
* 接口说明
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/partner-transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}
|
||||
* 请求方式:GET
|
||||
* 接口限频:单个服务商 50QPS,如果超过频率限制,会报错FREQUENCY_LIMITED,请降低频率请求。
|
||||
*
|
||||
* @param outBatchNo 商家明细单号
|
||||
* @param outDetailNo 商家批次单号
|
||||
* @return 返回数据 {@link BatchDetailsResult}
|
||||
* @throws WxPayException the wx pay exception
|
||||
* @throws BadPaddingException the wx decrypt exception
|
||||
*/
|
||||
@Override
|
||||
public BatchDetailsResult queryBatchDetailByMch(String outBatchNo, String outDetailNo) throws WxPayException, BadPaddingException {
|
||||
String url = String.format("%s/v3/partner-transfer/batches/out-batch-no/%s/details/out-detail-no/%s", this.payService.getPayBaseUrl(), outBatchNo, outDetailNo);
|
||||
String response = this.payService.getV3(url);
|
||||
BatchDetailsResult batchDetailsResult = GSON.fromJson(response, BatchDetailsResult.class);
|
||||
String userName = RsaCryptoUtil.decryptOAEP(batchDetailsResult.getUserName(), this.payService.getConfig().getPrivateKey());
|
||||
batchDetailsResult.setUserName(userName);
|
||||
return batchDetailsResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转账电子回单申请受理API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 商家批次单号
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public BillReceiptResult receiptBill(ReceiptBillRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/transfer/bill-receipt", this.payService.getPayBaseUrl());
|
||||
String response = this.payService.postV3(url, GSON.toJson(request));
|
||||
return GSON.fromJson(response, BillReceiptResult.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询转账电子回单API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_2.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer/bill-receipt/{out_batch_no}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param outBatchNo 商家批次单号
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public BillReceiptResult queryBillReceipt(String outBatchNo) throws WxPayException {
|
||||
String url = String.format("%s/v3/transfer/bill-receipt/%s", this.payService.getPayBaseUrl(), outBatchNo);
|
||||
String response = this.payService.getV3(url);
|
||||
return GSON.fromJson(response, BillReceiptResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转账明细电子回单受理API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_4.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer-detail/electronic-receipts
|
||||
* 请求方式:POST
|
||||
* 前置条件:只支持受理最近90天内的转账明细单
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public ElectronicReceiptsResult transferElectronic(ElectronicReceiptsRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/transfer-detail/electronic-receipts", this.payService.getPayBaseUrl());
|
||||
String response = this.payService.postV3(url, GSON.toJson(request));
|
||||
return GSON.fromJson(response, ElectronicReceiptsResult.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询转账明细电子回单受理结果API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_5.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/transfer-detail/electronic-receipts
|
||||
* 请求方式:GET
|
||||
* 前置条件:只支持查询最近90天内的转账明细单
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public ElectronicReceiptsResult queryTransferElectronicResult(ElectronicReceiptsRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/transfer-detail/electronic-receipts", this.payService.getPayBaseUrl());
|
||||
String query = String.format("?accept_type=%s&out_batch_no=%s&out_detail_no=%s", request.getAcceptType(), request.getOutBatchNo(), request.getOutDetailNo());
|
||||
String response = this.payService.getV3(url + query);
|
||||
return GSON.fromJson(response, ElectronicReceiptsResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载电子回单API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_3.shtml
|
||||
* 请求URL:通过申请账单接口获取到“download_url”,URL有效期10min
|
||||
* 请求方式:GET
|
||||
* 前置条件:调用申请账单接口并获取到“download_url”
|
||||
*
|
||||
* @param url 微信返回的电子回单地址。
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public InputStream transferDownload(String url) throws WxPayException {
|
||||
InputStream response = this.payService.downloadV3(url);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询账户实时余额API
|
||||
* 接口说明
|
||||
* 适用对象:直连商户 服务商
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_1.shtml
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/merchant/fund/balance/{account_type}
|
||||
* 请求方式:GET
|
||||
* </pre>
|
||||
*
|
||||
* @param accountType 服务商账户类型 {@link SpAccountTypeEnum}
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public FundBalanceResult fundBalance(SpAccountTypeEnum accountType) throws WxPayException {
|
||||
String url = String.format("%s/v3/merchant/fund/balance/%s", this.payService.getPayBaseUrl(), accountType);
|
||||
String response = this.payService.getV3(url);
|
||||
return GSON.fromJson(response, FundBalanceResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 服务商账户日终余额
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_2.shtml
|
||||
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/amount.shtml
|
||||
* </pre>
|
||||
*
|
||||
* @param accountType 服务商账户类型
|
||||
* @param date 查询日期 2020-09-11
|
||||
* @return 返回数据 fund balance result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public FundBalanceResult spDayEndBalance(SpAccountTypeEnum accountType, String date) {
|
||||
try {
|
||||
return this.payService.getEcommerceService().spDayEndBalance(accountType, date);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.github.binarywang.wxpay.service.impl;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.marketing.payroll.*;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import com.github.binarywang.wxpay.service.PayrollService;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
|
||||
/**
|
||||
* 微信支付-微工卡
|
||||
*
|
||||
* @author xiaoqiang
|
||||
* @date 2021/12/2
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class PayrollServiceImpl implements PayrollService {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().create();
|
||||
|
||||
private final WxPayService payService;
|
||||
|
||||
/**
|
||||
* 生成授权token
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/tokens
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public TokensResult payrollCardTokens(TokensRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/payroll-card/tokens", payService.getPayBaseUrl());
|
||||
try {
|
||||
String userName = RsaCryptoUtil.encryptOAEP(request.getUserName(), payService.getConfig().getVerifier().getValidCertificate());
|
||||
request.setUserName(userName);
|
||||
String idCardNumber = RsaCryptoUtil.encryptOAEP(request.getIdCardNumber(), payService.getConfig().getVerifier().getValidCertificate());
|
||||
request.setIdCardNumber(idCardNumber);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
throw new RuntimeException("加密异常!", e);
|
||||
}
|
||||
String response = payService.postV3(url, GSON.toJson(request));
|
||||
return GSON.fromJson(response, TokensResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询微工卡授权关系API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/relations/{openid}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public RelationsResult payrollCardRelations(RelationsRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/payroll-card/relations/%s",
|
||||
payService.getPayBaseUrl(), request.getOpenid());
|
||||
String query = String.format("?sub_mchid=%s", request.getSubMchid());
|
||||
if (StringUtils.isNotEmpty(request.getAppid())) {
|
||||
query += "&appid=" + request.getAppid();
|
||||
}
|
||||
if (StringUtils.isNotEmpty(request.getSubAppid())) {
|
||||
query += "&sub_appid=" + request.getSubAppid();
|
||||
}
|
||||
String response = payService.getV3(url + query);
|
||||
return GSON.fromJson(response, RelationsResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微工卡核身预下单API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications/pre-order
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public PreOrderResult payrollCardPreOrder(PreOrderRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/payroll-card/authentications/pre-order", payService.getPayBaseUrl());
|
||||
String response = payService.postV3(url, GSON.toJson(request));
|
||||
return GSON.fromJson(response, PreOrderResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取核身结果API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications/{authenticate_number}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param subMchid 子商户号
|
||||
* @param authenticateNumber 商家核身单号
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public AuthenticationsResult payrollCardAuthenticationsNumber(String subMchid, String authenticateNumber) throws WxPayException {
|
||||
String url = String.format("%s/v3/payroll-card/authentications/%s", payService.getPayBaseUrl(), authenticateNumber);
|
||||
String query = String.format("?sub_mchid=%s", subMchid);
|
||||
String response = payService.getV3(url + query);
|
||||
return GSON.fromJson(response, AuthenticationsResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询核身记录API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public AuthRecordResult payrollCardAuthentications(AuthRecordRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/payroll-card/authentications", payService.getPayBaseUrl());
|
||||
String query = String.format("?openid=%s&sub_mchid=%s&authenticate_date=%s",
|
||||
request.getOpenid(), request.getAppid(), request.getSubMchid(), request.getAuthenticateDate());
|
||||
if (StringUtils.isNotEmpty(request.getAppid())) {
|
||||
query += "&appid=" + request.getAppid();
|
||||
}
|
||||
if (StringUtils.isNotEmpty(request.getAppid())) {
|
||||
query += "&sub_appid=" + request.getSubAppid();
|
||||
}
|
||||
if (StringUtils.isNotEmpty(request.getAuthenticateState())) {
|
||||
query += "&authenticate_state=" + request.getAuthenticateState();
|
||||
}
|
||||
String response = payService.getV3(url + query);
|
||||
return GSON.fromJson(response, AuthRecordResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微工卡核身预下单(流程中完成授权)
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/payroll-card/authentications/pre-order-with-auth
|
||||
* 请求方式:POST
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public PreOrderWithAuthResult payrollCardPreOrderWithAuth(PreOrderWithAuthRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/payroll-card/authentications/pre-order-with-auth", payService.getPayBaseUrl());
|
||||
try {
|
||||
String userName = RsaCryptoUtil.encryptOAEP(request.getUserName(), payService.getConfig().getVerifier().getValidCertificate());
|
||||
request.setUserName(userName);
|
||||
String idCardNumber = RsaCryptoUtil.encryptOAEP(request.getIdCardNumber(), payService.getConfig().getVerifier().getValidCertificate());
|
||||
request.setIdCardNumber(idCardNumber);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
throw new RuntimeException("敏感信息加密异常!", e);
|
||||
}
|
||||
String response = payService.postV3(url, GSON.toJson(request));
|
||||
return GSON.fromJson(response, PreOrderWithAuthResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按日下载提现异常文件API
|
||||
* 适用对象:服务商
|
||||
* 请求URL:https://api.mch.weixin.qq.com/v3/merchant/fund/withdraw/bill-type/{bill_type}
|
||||
* 请求方式:GET
|
||||
*
|
||||
* @param billType 账单类型
|
||||
* NO_SUCC:提现异常账单,包括提现失败和提现退票账单。
|
||||
* 示例值:NO_SUCC
|
||||
* @param billDate 账单日期 表示所在日期的提现账单,格式为YYYY-MM-DD。
|
||||
* 例如:2008-01-01日发起的提现,2008-01-03日银行返回提现失败,则该提现数据将出现在bill_date为2008-01-03日的账单中。
|
||||
* 示例值:2019-08-17
|
||||
* @return 返回数据
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
@Override
|
||||
public PreOrderWithAuthResult merchantFundWithdrawBillType(String billType, String billDate) throws WxPayException {
|
||||
String url = String.format("%s/v3/merchant/fund/withdraw/bill-type/%s", payService.getPayBaseUrl(), billType);
|
||||
String query = String.format("?bill_date=%s", billDate);
|
||||
String response = payService.getV3(url + query);
|
||||
return GSON.fromJson(response, PreOrderWithAuthResult.class);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user