先检查申请的商户号是否接入升级版本功能,在2025-01-18后微信转账到零钱功能升级,有所变化,当前文档只适用于未接入升级版本功能的商户号
什么是商家转账到零钱?
为了满足商家向用户微信零钱转账的需求,微信支付推出“商家转账到零钱”
服务,方便商户可以通过“商家转账到零钱”
一次向单个或多个用户的微信零钱转账。商家转账到零钱提供了两种转账方式:“页面发起转账”
和“API发起转账”
,为商户提供了简便、免费、安全的转账服务。使用“商家转账到零钱”
可以帮助商户更加便捷、安全地向用户转账,提高转账效率。
要求
1、商户号已入驻90日且截止今日回推30天商户号保持连续不间断的交易。
2、登录微信支付商户平台-产品中心,开通付款到零钱(资质暂不支持小微商户、个体工商户。)。
转账流程
1、微信文档地址
产品介绍:
https://pay.weixin.qq.com/docs/merchant/products/batch-transfer-to-balance/introduction.html
API文档地址:
https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-batch/initiate-batch-transfer.html
2、前期准备
2.1、微信支付
2.1.1、商户号
商户可登录微信商户平台,在【账户中心】->【商户信息】找到商户号
2.1.2、商户证书
商户可登录微信商户平台,在【账户中心】->【API安全】目录下载证书。
2.1.3、apiV3key
商户可登录微信商户平台,进入【账户中心 > API安全 】目录,设置APIV3密钥。
2.2、支付载体申请(这里是微信小程序和APP)
微信支付的产品体系全部搭载于微信的社交体系之上,所以普通商户或服务商商户接入微信支付之前,都需要有一个微信社交载体
,该载体对应的ID即为AppID。
对于普通商户,该社交载体可以是公众号、小程序或App等。
各类社交载体一旦申请成功后,可以登录对应平台查看账号信息以获取对应的AppID和相关秘钥等信息。
2.3、绑定AppID及mchid
商户可登录微信商户平台> 产品中心 > APPID账号管理 > 我关联的APPID账号
AppID和mchid全部申请完毕后,需要建立两者之间的绑定关系。
普通商户模式下,AppID与mchid之间的关系为多对多,即一个AppID下可以绑定多个mchid,而一个mchid也可以绑定多个AppID。
2.4、商户开通商家转账到零钱。
商户可登录微信商户平台> 产品中心 > 运营工具 > 商家转账到零钱。
微信接入步骤文档地址:
https://pay.weixin.qq.com/docs/merchant/products/batch-transfer-to-balance/preparation.html
3、接口开发
3.1、引入相关依赖
maven依赖
微信支付官方推荐的SDK
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.15</version>
</dependency>
3.2、微信支付配置类
yaml配置
wechat:
pay:
# 微信支付商户号
merchantId: **********
# 商户证书路径
certPemPath: /cert/apiclient_cert.pem
# 商户API私钥路径
privateKeyPath: /cert/apiclient_key.pem
# 商户APIv3密钥
apiV3key: 07****************************47
证书文件
在resource下新建一个cert文件,将商户证书放在cert文件中,如下
当前我们yaml中配置的是相对路径的地址,因为我们是放在项目的resource目录
中的,如果要用绝对路径,将WechatPayAutoConfiguration
类中的CLASS_PATH
改为"file:"
就行
classpath
: 是从类路径加载资源,通常用于获取项目内嵌的资源(例如存放在 resources 目录下的文件),并不依赖于文件系统的具体位置。file
: 是从文件系统加载资源,路径需要指定在本地或网络文件系统中可以访问的具体位置。
微信支付配置类
微信支付配置类WechatPayProperties
用于读取上方application.yml
文件中以wechat.pay
为前缀的配置信息,并将这些配置映射到类的字段中。
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author: zhoujinchuan
* @Description: (微信支付配置类)
* @Date: 2024-12-02 14:10:40
*/
@Data
@Component
@ConfigurationProperties(prefix = "wechat.pay")
public class WechatPayProperties {
/**
* 微信支付商户号
*/
private String merchantId;
/**
* 商户证书路径
*/
private String certPemPath;
/**
* 商户API私钥路径
*/
private String privateKeyPath;
/**
* 商户APIv3密钥
*/
private String apiV3key;
/**
* 支付回调通知地址--微信支付的
*/
private String payNotifyUrl;
}
3.3、微信支付相关自动配置
这个类WechatPayAutoConfiguration
主要用于微信支付的自动配置,提供了微信支付相关的配置和服务初始化。它通过 Spring 的@Configuration
注解表示这是一个配置类,负责设置和管理微信支付所需的各种配置信息,并通过@Bean
注解暴露出不同的 Bean 供 Spring 容器管理。
Config
:该方法读取微信支付的证书和私钥文件,配置微信支付所需的证书信息(如证书序列号、私钥等)TransferBatchService
:这是一个用于处理微信支付转账的服务。该服务需要Config
配置对象作为构造参数。NotificationParser
:用于解析这些回调信息,提取出支付状态等数据,便于商户系统处理。
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.cert.*;
/**
* @Author: zhoujinchuan
* @Description: (微信支付相关自动配置)
* @Date: 2024-12-02 14:10:40
*/
@Slf4j
@Configuration
public class WechatPayAutoConfiguration {
@Autowired
private WechatPayProperties properties;
@Autowired
private ResourceLoader resourceLoader;
private static final String CLASS_PATH = "classpath:";
/**
* 自动更新证书
*
* @return RSAAutoCertificateConfig
*/
@Bean
public Config config() throws IOException {
String path = CLASS_PATH + properties.getCertPemPath();
Resource resourceCert = resourceLoader.getResource(path);
X509Certificate certificate = getCertificate(resourceCert.getInputStream());
String merchantSerialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
log.info("==========证书序列号:{},商户信息:{}", merchantSerialNumber, certificate.getSubjectDN());
String privatePath = CLASS_PATH + properties.getPrivateKeyPath();
Resource resourcePrivate = resourceLoader.getResource(privatePath);
String privateKey = inputStreamToString(resourcePrivate.getInputStream());
log.info("==========加载微信私钥配置:{}", privateKey);
RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
.merchantId(properties.getMerchantId())
.privateKey(privateKey)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(properties.getApiV3key())
.build();
return config;
}
/**
* 微信转账对象
* @param config Config
* @return JsapiServiceExtension
*/
@Bean
public TransferBatchService transferBatchService(Config config){
log.info("==========加载微信转账对象");
TransferBatchService service = new TransferBatchService.Builder().config(config).build();
return service;
}
/**
* 微信回调对象
*
* @param config Config
* @return NotificationParser
*/
@Bean
public NotificationParser notificationParser(Config config) {
log.info("==========加载微信回调解析对象");
NotificationParser parser = new NotificationParser((NotificationConfig) config);
return parser;
}
/**
* 读取私钥文件,将文件流读取成string
*
* @param inputStream
* @return
* @throws IOException
*/
public String inputStreamToString(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
reader.close();
return stringBuilder.toString();
}
/**
* 获取证书 将文件流转成证书文件
*
* @param inputStream 证书文件
* @return {@link X509Certificate} 获取证书
*/
public static X509Certificate getCertificate(InputStream inputStream) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
cert.checkValidity();
return cert;
} catch (CertificateExpiredException e) {
throw new RuntimeException("证书已过期", e);
} catch (CertificateNotYetValidException e) {
throw new RuntimeException("证书尚未生效", e);
} catch (CertificateException e) {
throw new RuntimeException("无效的证书", e);
}
}
}
另外,这里还可以注入一些其他的服务,这里列举一些这些常见的微信支付的服务,都可以用对应Service的Builder构建所需要的对象
3.4、支付方法
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
/**
* @Author: zhoujinchuan
* @Description: ()
* @Date: 2024/12/4 17:09
*/
@Service
public class WxTransferServiceImpl implements IWxTransferService {
private static final Logger logger = LoggerFactory.getLogger(WxTransferServiceImpl.class);
@Resource
private TransferBatchService transferBatchService;
@Override
public void pay(String type) {
// 发起转账------------------
//批次编号,批次名称,批次备注
String outBatchNo = RandomUtil.randomNumbers(10);
String batchName = outBatchNo;
String batchRemark = outBatchNo;
//创建批次对象
InitiateBatchTransferRequest batchesRequest = new InitiateBatchTransferRequest();
//【商户appid】 申请商户号的appid或商户号绑定的appid(企业号corpid即为此appid)
String appId = "wx****************";
batchesRequest.setAppid(appId);
//【商家批次单号】 商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
batchesRequest.setOutBatchNo(outBatchNo);
//【批次名称】 该笔批量转账的名称
batchesRequest.setBatchName(batchName);
//【批次备注】 转账说明,UTF8编码,最多允许32个字符
batchesRequest.setBatchRemark(batchRemark);
//【转账总笔数】 一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致,否则无法发起转账操作
batchesRequest.setTotalNum(1);
//【转账明细列表】
ArrayList<TransferDetailInput> transferDetails = new ArrayList<>();
BigDecimal totalAmount = BigDecimal.ZERO;
for (int i = 0; i < 1; i++) {
TransferDetailInput transferDetail = new TransferDetailInput();
String outDetailNo = RandomUtil.generateTxNo(10);
//【商家明细单号】 商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成
transferDetail.setOutDetailNo(outDetailNo);
//【转账金额】 转账金额单位为“分”
transferDetail.setTransferAmount(new BigDecimal("0.3").multiply(BigDecimal.valueOf(100)).longValue());
//【转账备注】 单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符
transferDetail.setTransferRemark("提现佣金到账");
//【收款用户openid】以实际对应载体的openid为准
transferDetail.setOpenid("oolmK6-gkW93ib-kUd5km0LLJJbo");
//【收款用户姓名】 收款方真实姓名
transferDetail.setUserName("周某");
//把收款人对象放到批次里面
transferDetails.add(transferDetail);
//累计总金额
totalAmount = totalAmount.add(new BigDecimal("0.3"));
}
batchesRequest.setTransferDetailList(transferDetails);
//【转账总金额】 转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致,否则无法发起转账操作
batchesRequest.setTotalAmount(totalAmount.multiply(BigDecimal.valueOf(100)).longValue());
//该批次转账使用的转账场景
//batchesRequest.setTransferSceneId();
InitiateBatchTransferResponse transferBatchesResult = null;
logger.error("请求参数:{}", JSONUtil.toJsonStr(batchesRequest));
try {
transferBatchesResult = transferBatchService.initiateBatchTransfer(batchesRequest);
logger.error("返回参数: {}", JSONUtil.toJsonStr(transferBatchesResult));
}catch (ServiceException e){
e.printStackTrace();
logger.error("企业支付失败:[msg:{}]", e.getMessage());
}
logger.error("企业支付完成:[msg:{}]", transferBatchesResult);
// 转账结束 --------------
}
}
appid:这里对应这第二步支付绑定的载体的appid。比如这里我用的微信小程序,就是微信小程序的appId
,(企业号corpid
即为此appid
)。
openid:是微信用来标识某个用户在特定载体下的唯一身份的标识符。它能唯一标识微信用户在该应用中的身份。企业号用户需要使用企业号userid
转openid
接口将企业成员的userid
转换成openid
。
唯一性
:在同一个应用(载体)下,openid 唯一对应某个微信用户。隔离性
:如果同一个微信用户在不同的应用下,openid 是不同的。这是为了保护用户隐私和避免跨应用关联用户。
注意:多个载体的情况,批次appId的是用的哪个appId,下方明细中的openid就要对应到对应载体中获取的openid
例如:
String appId = "";
//模拟多个载体
if(true){
//小程序
appId = "wx****************";
}else{
//APP
appId = "wx****************";
}
batchesRequest.setAppid(appId);
获取openid的方法
user_name:收款方真实姓名。支持标准RSA算法和国密算法,公钥由微信侧提供,微信SDK已经封装了加密,这里只需填写明文就行。
- 明细转账金额
<0.3
元时,不允许填写收款用户姓名。 - 明细转账金额
>= 2,000元
时,该笔明细必须填写收款用户姓名。 - 同一批次转账明细中的姓名字段传入规则需保持一致,也即全部填写、或全部不填写。
- 若商户传入收款用户姓名,微信支付会校验用户
openid
与姓名是否一致,并提供电子回单
transfer_scene_id:该批次转账使用的转账场景,如不填写则使用商家的默认场景,如无默认场景可为空,可前往“商家转账到零钱-前往功能
”中申请。如:1001-现金营销
notify_url:转账通知,这里和支付通知不一样,需要再转账请求中传入参数notify_url
,但是在当前wechatpay-java
SDK中没有包含设置通知地址的地方(SDK提交了相关issues)。当前是通过定时任务定时去手动请求通过商家明细单号查询明细单接口来查询转账的状态。
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.15</version>
</dependency>
<新版本中好像已经包含了notify_url,但是我这里还是用的主动查询的方式>
3.5、查询转账明细
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import com.wechat.pay.java.service.transferbatch.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
/**
* @Author: zhoujinchuan
* @Description: ()
* @Date: 2024/12/13 11:42
*/
@Service
public class WxTransferServiceImpl implements IWxTransferService {
private static final Logger logger = LoggerFactory.getLogger(WxTransferServiceImpl.class);
@Resource
private TransferBatchService transferBatchService;
/**
* 通过商家明细单号查询明细单
* @param outBatchNo
* @param outDetailNo
*/
public void getTransferDetail(String outBatchNo,String outDetailNo){
GetTransferDetailByOutNoRequest request = new GetTransferDetailByOutNoRequest();
request.setOutBatchNo(outBatchNo);
request.setOutDetailNo(outDetailNo);
TransferDetailEntity result = transferBatchService.getTransferDetailByOutNo(request);
if (result != null){
String detailStatus = result.getDetailStatus();
WxZzBatchDetailStatusEnum statusEnum = WxZzBatchDetailStatusEnum.fromCode(detailStatus);
//明细最后一次状态变更的时间
Date resultUpdateTime = DateUtil.parse(result.getUpdateTime(),"yyyy-MM-dd'T'HH:mm:ssXXX");
if (WxZzBatchDetailStatusEnum.SUCCESS.equals(statusEnum)) {
//转账成功处理
} else if (WxZzBatchDetailStatusEnum.FAIL.equals(statusEnum)) {
//转账失败处理
//明细失败原因枚举
FailReasonType failReason = result.getFailReason();
//明细失败原因中文转译
String failReasonCh = WeChatPayFailReasonEnum.getLabelByFailReasonType(failReason);
} else {
logger.error("查询明细结果----其他状态:{},{}", detailStatus,statusEnum);
}
}else {
logger.error("查询明细结果----响应异常");
}
}
}
detail_status:明细状态。
INIT
:初始态。 系统转账校验中WAIT_PAY
:待确认。待商户确认, 符合免密条件时, 系统会自动扭转为转账中PROCESSING
:转账中。正在处理中,转账结果尚未明确SUCCESS
:转账成功FAIL
:转账失败。需要确认失败原因后,再决定是否重新发起对该笔明细单的转账(并非整个转账批次单)
明细状态的自定义枚举类WxZzBatchDetailStatusEnum
/**
* @Author: zhoujinchuan
* @Description: ()
* @Date: 2024/12/4 9:19
*/
public enum WxZzBatchDetailStatusEnum {
/**
* 微信转账到用户明细状态枚举
*/
INIT("INIT", "初始态"),
WAIT_PAY("WAIT_PAY", "待确认"),
PROCESSING("PROCESSING", "转账中"),
SUCCESS("SUCCESS", "转账成功"),
FAIL("FAIL", "转账失败"),
;
private String code;
private String label;
WxZzBatchDetailStatusEnum(String code, String label) {
this.code = code;
this.label = label;
}
public String getCode() {
return code;
}
public String getLabel() {
return label;
}
/**
* 通过code获取枚举
* @param code
* @return
*/
public static WxZzBatchDetailStatusEnum fromCode(String code) {
for (WxZzBatchDetailStatusEnum status : WxZzBatchDetailStatusEnum.values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
}
fail_reason:明细失败原因,如果转账失败则有失败原因。
ACCOUNT_FROZEN
:该用户账户被冻结REAL_NAME_CHECK_FAIL
:收款人未实名认证,需要用户完成微信实名认证NAME_NOT_CORRECT
:收款人姓名校验不通过,请核实信息OPENID_INVALID
:Openid格式错误或者不属于商家公众账号TRANSFER_QUOTA_EXCEED
:超过用户单笔收款额度,核实产品设置是否准确DAY_RECEIVED_QUOTA_EXCEED
:超过用户单日收款额度,核实产品设置是否准确MONTH_RECEIVED_QUOTA_EXCEED
:超过用户单月收款额度,核实产品设置是否准确DAY_RECEIVED_COUNT_EXCEED
:超过用户单日收款次数,核实产品设置是否准确PRODUCT_AUTH_CHECK_FAIL
:未开通该权限或权限被冻结,请核实产品权限状态OVERDUE_CLOSE
:超过系统重试期,系统自动关闭ID_CARD_NOT_CORRECT
:收款人身份证校验不通过,请核实信息ACCOUNT_NOT_EXIST
:该用户账户不存在TRANSFER_RISK
:该笔转账可能存在风险,已被微信拦截OTHER_FAIL_REASON_TYPE
:其它失败原因REALNAME_ACCOUNT_RECEIVED_QUOTA_EXCEED
:用户账户收款受限,请引导用户在微信支付查看详情RECEIVE_ACCOUNT_NOT_PERMMIT
:未配置该用户为转账收款人,请在产品设置中调整,添加该用户为收款人PAYEE_ACCOUNT_ABNORMAL
:用户账户收款异常,请联系用户完善其在微信支付的身份信息以继续收款PAYER_ACCOUNT_ABNORMAL
:商户账户付款受限,可前往商户平台获取解除功能限制指引TRANSFER_SCENE_UNAVAILABLE
:该转账场景暂不可用,请确认转账场景ID是否正确TRANSFER_SCENE_INVALID
:你尚未获取该转账场景,请确认转账场景ID是否正确TRANSFER_REMARK_SET_FAIL
:转账备注设置失败, 请调整后重新再试RECEIVE_ACCOUNT_NOT_CONFIGURE
:请前往商户平台-商家转账到零钱-前往功能-转账场景中添加BLOCK_B2C_USERLIMITAMOUNT_BSRULE_MONTH
:超出用户单月转账收款20w限额,本月不支持继续向该用户付款BLOCK_B2C_USERLIMITAMOUNT_MONTH
:用户账户存在风险收款受限,本月不支持继续向该用户付款MERCHANT_REJECT
:商户员工(转账验密人)已驳回转账MERCHANT_NOT_CONFIRM
:商户员工(转账验密人)超时未验密
转账明细查询返回的是FailReasonType
枚举类,但是没有中文转译,我我这边自定义了一个失败原因枚举类WeChatPayFailReasonEnum
进行中文原因转译
import com.wechat.pay.java.service.transferbatch.model.FailReasonType;
/**
* @Author: zhoujinchuan
* @Description: 枚举类,包含微信支付失败原因
* @Date: 2024-12-02 14:14:40
*/
public enum WeChatPayFailReasonEnum {
/**
* 微信转账失败原因枚举
*/
ACCOUNT_FROZEN("ACCOUNT_FROZEN", "该用户账户被冻结"),
REAL_NAME_CHECK_FAIL("REAL_NAME_CHECK_FAIL", "收款人未实名认证,需要用户完成微信实名认证"),
NAME_NOT_CORRECT("NAME_NOT_CORRECT", "收款人姓名校验不通过,请核实信息"),
OPENID_INVALID("OPENID_INVALID", "Openid格式错误或者不属于商家公众账号"),
TRANSFER_QUOTA_EXCEED("TRANSFER_QUOTA_EXCEED", "超过用户单笔收款额度,核实产品设置是否准确"),
DAY_RECEIVED_QUOTA_EXCEED("DAY_RECEIVED_QUOTA_EXCEED", "超过用户单日收款额度,核实产品设置是否准确"),
MONTH_RECEIVED_QUOTA_EXCEED("MONTH_RECEIVED_QUOTA_EXCEED", "超过用户单月收款额度,核实产品设置是否准确"),
DAY_RECEIVED_COUNT_EXCEED("DAY_RECEIVED_COUNT_EXCEED", "超过用户单日收款次数,核实产品设置是否准确"),
PRODUCT_AUTH_CHECK_FAIL("PRODUCT_AUTH_CHECK_FAIL", "未开通该权限或权限被冻结,请核实产品权限状态"),
OVERDUE_CLOSE("OVERDUE_CLOSE", "超过系统重试期,系统自动关闭"),
ID_CARD_NOT_CORRECT("ID_CARD_NOT_CORRECT", "收款人身份证校验不通过,请核实信息"),
ACCOUNT_NOT_EXIST("ACCOUNT_NOT_EXIST", "该用户账户不存在"),
TRANSFER_RISK("TRANSFER_RISK", "该笔转账可能存在风险,已被微信拦截"),
OTHER_FAIL_REASON_TYPE("OTHER_FAIL_REASON_TYPE", "其它失败原因"),
REALNAME_ACCOUNT_RECEIVED_QUOTA_EXCEED("REALNAME_ACCOUNT_RECEIVED_QUOTA_EXCEED", "用户账户收款受限,请引导用户在微信支付查看详情"),
RECEIVE_ACCOUNT_NOT_PERMMIT("RECEIVE_ACCOUNT_NOT_PERMMIT", "未配置该用户为转账收款人,请在产品设置中调整,添加该用户为收款人"),
PAYEE_ACCOUNT_ABNORMAL("PAYEE_ACCOUNT_ABNORMAL", "用户账户收款异常,请联系用户完善其在微信支付的身份信息以继续收款"),
PAYER_ACCOUNT_ABNORMAL("PAYER_ACCOUNT_ABNORMAL", "商户账户付款受限,可前往商户平台获取解除功能限制指引"),
TRANSFER_SCENE_UNAVAILABLE("TRANSFER_SCENE_UNAVAILABLE", "该转账场景暂不可用,请确认转账场景ID是否正确"),
TRANSFER_SCENE_INVALID("TRANSFER_SCENE_INVALID", "你尚未获取该转账场景,请确认转账场景ID是否正确"),
TRANSFER_REMARK_SET_FAIL("TRANSFER_REMARK_SET_FAIL", "转账备注设置失败,请调整后重新再试"),
RECEIVE_ACCOUNT_NOT_CONFIGURE("RECEIVE_ACCOUNT_NOT_CONFIGURE", "请前往商户平台-商家转账到零钱-前往功能-转账场景中添加"),
BLOCK_B2C_USERLIMITAMOUNT_BSRULE_MONTH("BLOCK_B2C_USERLIMITAMOUNT_BSRULE_MONTH", "超出用户单月转账收款20w限额,本月不支持继续向该用户付款"),
BLOCK_B2C_USERLIMITAMOUNT_MONTH("BLOCK_B2C_USERLIMITAMOUNT_MONTH", "用户账户存在风险收款受限,本月不支持继续向该用户付款"),
MERCHANT_REJECT("MERCHANT_REJECT", "商户员工(转账验密人)已驳回转账"),
MERCHANT_NOT_CONFIRM("MERCHANT_NOT_CONFIRM", "商户员工(转账验密人)超时未验密");
private String code;
private String label;
WeChatPayFailReasonEnum(String code, String label) {
this.code = code;
this.label = label;
}
public String getCode() {
return code;
}
public String getLabel() {
return label;
}
public static String getLabelByFailReasonType(FailReasonType failReason){
for (WeChatPayFailReasonEnum value : values()) {
if (value.getCode().equals(String.valueOf(failReason))) {
return value.getLabel();
}
}
return "未知原因";
}
}