🎨 【微信支付】完善微信商家转账功能API !151

This commit is contained in:
Neror 2025-01-21 11:49:38 +00:00 committed by Binary Wang
parent 24ebc91dca
commit c3b16228c0
7 changed files with 332 additions and 6 deletions

View File

@ -0,0 +1,48 @@
package com.github.binarywang.wxpay.bean.transfer;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* <pre>
* 商家转账到零钱撤销转账接口
* 文档地址https://pay.weixin.qq.com/doc/v3/merchant/4012716458
* </pre>
*
* @author Nor
* @date 2025/1/17
*/
@Data
@NoArgsConstructor
public class TransferBillsCancelResult implements Serializable {
private static final long serialVersionUID = -4935840810530008418L;
/**
* 商户单号 商户系统内部的商家单号要求此参数只能由数字大小写字母组成在商户系统内部唯一
*/
@SerializedName("out_bill_no")
private String outBillNo;
/**
* 微信转账单号 微信转账单号微信商家转账系统返回的唯一标识
*/
@SerializedName("transfer_bill_no")
private String transferBillNo;
/**
* 单据状态 商家转账订单状态
* 可选取值
* CANCELING: 商户撤销请求受理成功该笔转账正在撤销中
* CANCELLED: 转账撤销完成
*/
private String state;
/**
* 最后一次单据状态变更时间 按照使用rfc3339所定义的格式格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
*/
@SerializedName("update_time")
private String updateTime;
}

View File

@ -0,0 +1,103 @@
package com.github.binarywang.wxpay.bean.transfer;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* <pre>
* 商家转账到零钱查询转账单接口
* 文档地址https://pay.weixin.qq.com/doc/v3/merchant/4012716457 https://pay.weixin.qq.com/doc/v3/merchant/4012716437
* </pre>
*
* @author Nor
* @date 2025/1/17
*/
@Data
@NoArgsConstructor
public class TransferBillsGetResult implements Serializable {
private static final long serialVersionUID = -6376955113492371763L;
/**
* 商户号 微信支付分配的商户号
*/
@SerializedName("mch_id")
private String mchId;
/**
* 商户单号 商户系统内部的商家单号要求此参数只能由数字大小写字母组成在商户系统内部唯一
*/
@SerializedName("out_bill_no")
private String outBillNo;
/**
* 商家转账订单号 商家转账订单的主键唯一定义此资源的标识
*/
@SerializedName("transfer_bill_no")
private String transferBillNo;
/**
* 商户AppID 申请商户号的AppID或商户号绑定的AppID企业号corpid即为此AppID
*/
private String appid;
/**
* 单据状态
* 可选取值
* ACCEPTED: 转账已受理
* PROCESSING: 转账处理中转账结果尚未明确如一直处于此状态建议检查账户余额是否足够
* WAIT_USER_CONFIRM: 待收款用户确认可拉起微信收款确认页面进行收款确认
* TRANSFERING: 转账结果尚未明确可拉起微信收款确认页面再次重试确认收款
* SUCCESS: 转账成功
* FAIL: 转账失败
* CANCELING: 商户撤销请求受理成功该笔转账正在撤销中
* CANCELLED: 转账撤销完成
*
* @see WxPayConstants.TransformBillState
*/
private String state;
/**
* 转账金额 转账金额单位为
*/
@SerializedName("transfer_amount")
private String transferAmount;
/**
* 转账备注 单条转账备注微信用户会收到该备注UTF8编码最多允许32个字符
*/
@SerializedName("transfer_remark")
private String transferRemark;
/**
* 失败原因 订单已失败或者已退资金时返回失败原因
*/
@SerializedName("fail_reason")
private String failReason;
/**
* 收款用户OpenID 商户AppID下某用户的OpenID
*/
private String openid;
/**
* 收款用户姓名 收款方真实姓名支持标准RSA算法和国密算法公钥由微信侧提供转账金额 >= 2,000元时该笔明细必须填写若商户传入收款用户姓名微信支付会校验用户OpenID与姓名是否一致并提供电子回单
*/
@SerializedName("user_name")
private String userName;
/**
* 单据创建时间 单据受理成功时返回按照使用rfc3339所定义的格式格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
*/
@SerializedName("create_time")
private String createTime;
/**
* 最后一次状态变更时间 单据最后更新时间按照使用rfc3339所定义的格式格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
*/
@SerializedName("update_time")
private String updateTime;
}

View File

@ -1,5 +1,6 @@
package com.github.binarywang.wxpay.bean.transfer;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -37,9 +38,11 @@ public class TransferBillsResult implements Serializable {
/**
* 单据状态
*
* @see WxPayConstants.TransformBillState
*/
@SerializedName("status")
private String status;
@SerializedName("state")
private String state;
/**
* 失败原因

View File

@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
import com.google.common.collect.Lists;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.time.FastDateFormat;
import java.text.Format;
@ -353,4 +354,86 @@ public class WxPayConstants {
public static final String PERSONAL_SUB_OPENID = "PERSONAL_SUB_OPENID";
}
/**
* 微信商户转账订单状态
*/
@UtilityClass
public static class TransformBillState {
/**
* 转账已受理
*/
public static final String ACCEPTED = "ACCEPTED";
/**
* 转账处理中转账结果尚未明确如一直处于此状态建议检查账户余额是否足够
*/
public static final String PROCESSING = "PROCESSING";
/**
* 待收款用户确认可拉起微信收款确认页面进行收款确认
*/
public static final String WAIT_USER_CONFIRM = "WAIT_USER_CONFIRM";
/**
* 转账结果尚未明确可拉起微信收款确认页面再次重试确认收款
*/
public static final String TRANSFERING = "TRANSFERING";
/**
* 转账成功
*/
public static final String SUCCESS = "SUCCESS";
/**
* 转账失败
*/
public static final String FAIL = "FAIL";
/**
* 商户撤销请求受理成功该笔转账正在撤销中
*/
public static final String CANCELING = "CANCELING";
/**
* 转账撤销完成
*/
public static final String CANCELLED = "CANCELLED";
}
/**
* 转账场景ID 该笔转账使用的转账场景可前往商户平台-产品中心-商家转账中申请
*/
@UtilityClass
public static class TransformSceneId {
/**
* 现金营销
*/
public static final String CASH_MARKETING = "1001";
}
/**
* 用户收款感知
*
* @see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012711988#3.3-%E5%8F%91%E8%B5%B7%E8%BD%AC%E8%B4%A6">官方文档</a>
*/
@UtilityClass
public static class UserRecvPerception {
/**
* 转账场景 现金营销
* 场景介绍 向参与营销活动的用户发放现金奖励
*/
public static class CASH_MARKETING {
/**
* 默认展示
*/
public static final String ACTIVITY = "活动奖励";
/**
* 需在发起转账时用户收款感知字段主动传入现金奖励才可展示
*/
public static final String CASH = "现金奖励";
}
}
}

View File

@ -128,6 +128,57 @@ public interface TransferService {
*/
TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException;
/**
* <pre>
*
* 2025.1.15 开始新接口 撤销转账API
*
* 请求方式POSTHTTPS
* 请求地址<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}/cancel">请求地址</a>
*
* 文档地址<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716458">商户撤销转账API</a>
* </pre>
*
* @param outBillNo 商户单号 商户系统内部的商家单号要求此参数只能由数字大小写字母组成在商户系统内部唯一
* @return TransformBillsGetResult 转账单
* @throws WxPayException .
*/
TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException;
/**
* <pre>
*
* 2025.1.15 开始新接口 发起商家转账API
*
* 请求方式GETHTTPS
* 请求地址<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}">请求地址</a>
*
* 文档地址<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716437">商户单号查询转账单API</a>
* </pre>
*
* @param outBillNo 商户单号 商户系统内部的商家单号要求此参数只能由数字大小写字母组成在商户系统内部唯一
* @return TransformBillsGetResult 转账单
* @throws WxPayException .
*/
TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException;
/**
* <pre>
*
* 2025.1.15 开始新接口 微信单号查询转账单API
*
* 请求方式GETHTTPS
* 请求地址<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/{transfer_bill_no}">请求地址</a>
*
* 文档地址<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716437">商户单号查询转账单API</a>
* </pre>
*
* @param transferBillNo 微信转账单号 微信转账单号微信商家转账系统返回的唯一标识
* @return TransformBillsGetResult 转账单
* @throws WxPayException .
*/
TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException;
/**
* 2025.1.15 开始新接口 解析商家转账结果
* 详见<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012712115"></a>

View File

@ -48,8 +48,7 @@ public class TransferServiceImpl implements TransferService {
if (request.getNeedQueryDetail()) {
url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s",
this.payService.getPayBaseUrl(), request.getBatchId(), request.getOffset(), request.getLimit(), request.getDetailStatus());
}
else {
} else {
url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=false",
this.payService.getPayBaseUrl(), request.getBatchId());
}
@ -70,8 +69,7 @@ public class TransferServiceImpl implements TransferService {
if (request.getNeedQueryDetail()) {
url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s",
this.payService.getPayBaseUrl(), request.getOutBatchNo(), request.getOffset(), request.getLimit(), request.getDetailStatus());
}
else {
} else {
url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=false",
this.payService.getPayBaseUrl(), request.getOutBatchNo());
}
@ -97,6 +95,31 @@ public class TransferServiceImpl implements TransferService {
return GSON.fromJson(result, TransferBillsResult.class);
}
@Override
public TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException {
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s/cancel",
this.payService.getPayBaseUrl(), outBillNo);
String result = this.payService.postV3(url, "");
return GSON.fromJson(result, TransferBillsCancelResult.class);
}
@Override
public TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException {
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s",
this.payService.getPayBaseUrl(), outBillNo);
String result = this.payService.getV3(url);
return GSON.fromJson(result, TransferBillsGetResult.class);
}
@Override
public TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException {
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/%s",
this.payService.getPayBaseUrl(), transferBillNo);
String result = this.payService.getV3(url);
return GSON.fromJson(result, TransferBillsGetResult.class);
}
@Override
public TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
return this.payService.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);

View File

@ -87,4 +87,19 @@ public class TransferServiceImplTest {
.userName("测试用户").build();
log.info("发起商家转账:{}", this.payService.getTransferService().transferBills(transferBillsRequest));
}
@Test
public void testTransformBillsCancel() throws WxPayException {
log.info("撤销商家转账:{}", this.payService.getTransferService().transformBillsCancel("123456"));
}
@Test
public void testGetBillsByOutBillNo() throws WxPayException {
log.info("商户单号查询转账单:{}", this.payService.getTransferService().getBillsByOutBillNo("123456"));
}
@Test
public void testGetBillsByTransferBillNo() throws WxPayException {
log.info("微信单号查询转账单:{}", this.payService.getTransferService().getBillsByTransferBillNo("123456"));
}
}