Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.github.binarywang.wxpay.bean.transfer;

import com.github.binarywang.wxpay.bean.notify.OriginNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayBaseNotifyV3Result;
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/4012716434
* </pre>
*/
@Data
public class TransferBillsNotifyResult implements Serializable, WxPayBaseNotifyV3Result<TransferBillsNotifyResult.DecryptNotifyResult> {
/**
* 源数据
*/
private OriginNotifyResponse rawData;
/**
* 解密后的数据
*/
private TransferBillsNotifyResult.DecryptNotifyResult result;

@Data
@NoArgsConstructor
public static class DecryptNotifyResult implements Serializable {
/**
* 商户号
*/
@SerializedName(value = "mch_id")
private String mchId;
/**
* 商家批次单号
*/
@SerializedName(value = "out_bill_no")
private String outBillNo;
/**
* 微信批次单号
*/
@SerializedName(value = "transfer_bill_no")
private String transferBillNo;
/**
* 批次状态
*/
@SerializedName(value = "state")
private String state;
/**
* 转账金额
*/
@SerializedName(value = "transfer_amount")
private Integer transferAmount;

/**
* 批次状态
*/
@SerializedName(value = "openid")
private String openid;

/**
* 单据创建时间
*/
@SerializedName(value = "create_time")
private String createTime;
/**
* 最后一次状态变更时间
*/
@SerializedName(value = "update_time")
private String updateTime;
/**
* 错误原因
*/
@SerializedName(value = "fail_reason")
private String failReason;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.github.binarywang.wxpay.bean.transfer;

import com.github.binarywang.wxpay.v3.SpecEncrypt;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
* 发起商家转账API参数
*
* @author allovine
* created on 2025/1/15
**/
@Data
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
public class TransferBillsRequest implements Serializable {
private static final long serialVersionUID = -2175582517588397437L;

/**
* 直连商户的appid
*/
@SerializedName("appid")
private String appid;

/**
* 商户系统内部的商家单号
*/
@SerializedName("out_bill_no")
private String outBillNo;

/**
* 转账场景ID
* 商户平台-产品中心-商家转账 申请
* 佣金报酬 ID:1005
*/
@SerializedName("transfer_scene_id")
private String transferSceneId;

/**
* 用户在直连商户应用下的用户标示
*/
@SerializedName("openid")
private String openid;

/**
* 收款用户姓名
*/
@SpecEncrypt
@SerializedName("user_name")
private String userName;

/**
* 转账金额
*/
@SerializedName("transfer_amount")
private Integer transferAmount;

/**
* 转账备注
*/
@SerializedName("transfer_remark")
private String transferRemark;

/**
* 异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的url,必须为https,不能携带参数
*/
@SerializedName("notify_url")
private String notifyUrl;

/**
* 用户收款感知
*/
@SerializedName("user_recv_perception")
private String userRecvPerception;


/**
* 转账场景报备信息
*/
@SerializedName("transfer_scene_report_infos")
private List<TransferSceneReportInfo> transferSceneReportInfos;


@Data
@Builder(builderMethodName = "newBuilder")
@AllArgsConstructor
@NoArgsConstructor
public static class TransferSceneReportInfo {
/**
* 信息类型
*/
@SerializedName("info_type")
private String infoType;

/**
* 信息内容
*/
@SerializedName("info_content")
private String infoContent;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.github.binarywang.wxpay.bean.transfer;

import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
* 商家转账结果
*
* @author allovine
* created on 2025/1/15
**/
@Data
@NoArgsConstructor
public class TransferBillsResult implements Serializable {
private static final long serialVersionUID = -2175582517588397437L;

/**
* 商户单号
*/
@SerializedName("out_bill_no")
private String outBillNo;

/**
* 微信转账单号
*/
@SerializedName("transfer_bill_no")
private String transferBillNo;

/**
* 单据创建时间
*/
@SerializedName("create_time")
private String createTime;

/**
* 单据状态
*/
@SerializedName("status")
private String status;

/**
* 失败原因
*/
@SerializedName("fail_reason")
private String failReason;

/**
* 跳转领取页面的package信息
*/
@SerializedName("package_info")
private String packageInfo;
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,31 @@ public interface TransferService {
*/
TransferBatchDetailResult transferBatchesOutBatchNoDetail(String outBatchNo, String outDetailNo) throws WxPayException;

/**
* <pre>
*
* 2025.1.15 开始新接口 发起商家转账API
*
* 请求方式:POST(HTTPS)
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills">请求地址</a>
*
* 文档地址:<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716434">发起商家转账API</a>
* </pre>
*
* @param request 转账请求参数
* @return TransferBillsResult 转账结果
* @throws WxPayException .
*/
TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException;

/**
* 2025.1.15 开始新接口 解析商家转账结果
* 详见<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012712115"></a>
*
* @param notifyData 通知数据
* @param header 通知头部数据,不传则表示不校验头
* @return the wx transfer notify result
* @throws WxPayException the wx pay exception
*/
TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
Expand Down Expand Up @@ -991,6 +992,17 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
*/
WxPayTransferBatchesNotifyV3Result parseTransferBatchesNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;

/**
* 解析商家转账批次回调通知
* https://pay.weixin.qq.com/doc/v3/merchant/4012712115
*
* @param notifyData
* @param header
* @return
* @throws WxPayException
*/
TransferBillsNotifyResult parseTransferBillsNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;

/**
* 解析服务商模式退款结果通知
* 详见https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_11.shtml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.config.WxPayConfigHolder;
import com.github.binarywang.wxpay.constant.WxPayConstants;
Expand Down Expand Up @@ -442,6 +443,11 @@ public WxPayTransferBatchesNotifyV3Result parseTransferBatchesNotifyV3Result(Str
return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayTransferBatchesNotifyV3Result.class, WxPayTransferBatchesNotifyV3Result.DecryptNotifyResult.class);
}

@Override
public TransferBillsNotifyResult parseTransferBillsNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException {
return this.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);
}

@Override
public WxPayPartnerRefundNotifyV3Result parsePartnerRefundNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException {
return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayPartnerRefundNotifyV3Result.class, WxPayPartnerRefundNotifyV3Result.DecryptNotifyResult.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,20 @@ public TransferBatchDetailResult transferBatchesOutBatchNoDetail(String outBatch
String result = this.payService.getV3(url);
return GSON.fromJson(result, TransferBatchDetailResult.class);
}

@Override
public TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException {
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills", this.payService.getPayBaseUrl());
if (request.getUserName() != null && request.getUserName().length() > 0) {
X509Certificate validCertificate = this.payService.getConfig().getVerifier().getValidCertificate();
RsaCryptoUtil.encryptFields(request, validCertificate);
}
String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
return GSON.fromJson(result, TransferBillsResult.class);
}

@Override
public TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
return this.payService.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.testbase.ApiTestModule;
Expand Down Expand Up @@ -73,4 +74,17 @@ public void testTransferBatchesOutBatchNo() throws WxPayException {
public void testTransferBatchesOutBatchNoDetail() throws WxPayException {
log.info("商家明细单号查询明细单:{}", this.payService.getTransferService().transferBatchesOutBatchNoDetail("1655447999520", "1655447989156"));
}

@Test
public void testTransferBills() throws WxPayException {
TransferBillsRequest transferBillsRequest = TransferBillsRequest.newBuilder()
.appid("wxf636efh5xxxxx")
.outBillNo("1655447989156")
.transferSceneId("1005")
.transferAmount(100)
.transferRemark("测试转账")
.openid("oX_7Jzr9gSZz4X_Xc9-_7HGf8XzI")
.userName("测试用户").build();
log.info("发起商家转账:{}", this.payService.getTransferService().transferBills(transferBillsRequest));
}
}