mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 23:31:52 +08:00
转账 - 增加转账定时任务
This commit is contained in:
parent
09d45e6393
commit
15313c2992
@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
|||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -86,4 +87,12 @@ public interface PayClient {
|
|||||||
*/
|
*/
|
||||||
PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO);
|
PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得转账订单信息
|
||||||
|
*
|
||||||
|
* @param outTradeNo 外部订单号
|
||||||
|
* @param type 转账类型
|
||||||
|
* @return 转账信息
|
||||||
|
*/
|
||||||
|
PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type);
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,24 @@ public class PayTransferRespDTO {
|
|||||||
/**
|
/**
|
||||||
* 创建【WAITING】状态的转账返回
|
* 创建【WAITING】状态的转账返回
|
||||||
*/
|
*/
|
||||||
public static PayTransferRespDTO waitingOf(String channelOrderNo,
|
public static PayTransferRespDTO waitingOf(String channelTransferNo,
|
||||||
String outTransferNo, Object rawData) {
|
String outTransferNo, Object rawData) {
|
||||||
PayTransferRespDTO respDTO = new PayTransferRespDTO();
|
PayTransferRespDTO respDTO = new PayTransferRespDTO();
|
||||||
respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus();
|
respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus();
|
||||||
respDTO.channelTransferNo = channelOrderNo;
|
respDTO.channelTransferNo = channelTransferNo;
|
||||||
|
respDTO.outTransferNo = outTransferNo;
|
||||||
|
respDTO.rawData = rawData;
|
||||||
|
return respDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建【IN_PROGRESS】状态的转账返回
|
||||||
|
*/
|
||||||
|
public static PayTransferRespDTO dealingOf(String channelTransferNo,
|
||||||
|
String outTransferNo, Object rawData) {
|
||||||
|
PayTransferRespDTO respDTO = new PayTransferRespDTO();
|
||||||
|
respDTO.status = PayTransferStatusRespEnum.IN_PROGRESS.getStatus();
|
||||||
|
respDTO.channelTransferNo = channelTransferNo;
|
||||||
respDTO.outTransferNo = outTransferNo;
|
respDTO.outTransferNo = outTransferNo;
|
||||||
respDTO.rawData = rawData;
|
respDTO.rawData = rawData;
|
||||||
return respDTO;
|
return respDTO;
|
||||||
|
@ -188,11 +188,11 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
|
public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
|
||||||
|
validatePayTransferReqDTO(reqDTO);
|
||||||
PayTransferRespDTO resp;
|
PayTransferRespDTO resp;
|
||||||
try{
|
try {
|
||||||
validatePayTransferReqDTO(reqDTO);
|
|
||||||
resp = doUnifiedTransfer(reqDTO);
|
resp = doUnifiedTransfer(reqDTO);
|
||||||
}catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
// 系统异常,则包装成 PayException 异常抛出
|
// 系统异常,则包装成 PayException 异常抛出
|
||||||
@ -219,9 +219,25 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) {
|
||||||
|
try {
|
||||||
|
return doGetTransfer(outTradeNo, type);
|
||||||
|
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
|
||||||
|
throw ex;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("[getTransfer][客户端({}) outTradeNo({}) type({}) 查询转账单异常]",
|
||||||
|
getId(), outTradeNo, type, ex);
|
||||||
|
throw buildPayException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO)
|
protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO)
|
||||||
throws Throwable;
|
throws Throwable;
|
||||||
|
|
||||||
|
protected abstract PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type)
|
||||||
|
throws Throwable;
|
||||||
|
|
||||||
// ========== 各种工具方法 ==========
|
// ========== 各种工具方法 ==========
|
||||||
|
|
||||||
private PayException buildPayException(Throwable ex) {
|
private PayException buildPayException(Throwable ex) {
|
||||||
|
@ -23,14 +23,8 @@ import com.alipay.api.AlipayResponse;
|
|||||||
import com.alipay.api.DefaultAlipayClient;
|
import com.alipay.api.DefaultAlipayClient;
|
||||||
import com.alipay.api.domain.*;
|
import com.alipay.api.domain.*;
|
||||||
import com.alipay.api.internal.util.AlipaySignature;
|
import com.alipay.api.internal.util.AlipaySignature;
|
||||||
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
|
import com.alipay.api.request.*;
|
||||||
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
|
import com.alipay.api.response.*;
|
||||||
import com.alipay.api.request.AlipayTradeQueryRequest;
|
|
||||||
import com.alipay.api.request.AlipayTradeRefundRequest;
|
|
||||||
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
|
|
||||||
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
|
|
||||||
import com.alipay.api.response.AlipayTradeQueryResponse;
|
|
||||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -126,7 +120,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
|||||||
}
|
}
|
||||||
// 2.2 解析订单的状态
|
// 2.2 解析订单的状态
|
||||||
Integer status = parseStatus(response.getTradeStatus());
|
Integer status = parseStatus(response.getTradeStatus());
|
||||||
Assert.notNull(status, () -> {
|
Assert.notNull(status, () -> {
|
||||||
throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody()));
|
throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody()));
|
||||||
});
|
});
|
||||||
return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()),
|
return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()),
|
||||||
@ -228,7 +222,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
|||||||
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
|
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
|
||||||
// 1.1 校验公钥类型 必须使用公钥证书模式
|
// 1.1 校验公钥类型 必须使用公钥证书模式
|
||||||
if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
|
if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
|
||||||
throw exception0(ERROR_CONFIGURATION.getCode(),"支付宝单笔转账必须使用公钥证书模式");
|
throw exception0(ERROR_CONFIGURATION.getCode(), "支付宝单笔转账必须使用公钥证书模式");
|
||||||
}
|
}
|
||||||
// 1.2 构建 AlipayFundTransUniTransferModel
|
// 1.2 构建 AlipayFundTransUniTransferModel
|
||||||
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
|
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
|
||||||
@ -238,45 +232,97 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
|
|||||||
model.setOutBizNo(reqDTO.getOutTransferNo());
|
model.setOutBizNo(reqDTO.getOutTransferNo());
|
||||||
model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
|
model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
|
||||||
model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER
|
model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER
|
||||||
model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));
|
if (reqDTO.getChannelExtras() != null) {
|
||||||
|
model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));
|
||||||
|
}
|
||||||
|
// ② 个性化的参数
|
||||||
|
Participant payeeInfo = new Participant();
|
||||||
PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType());
|
PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType());
|
||||||
switch (transferType) {
|
switch (transferType) {
|
||||||
// TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦?
|
// TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦?
|
||||||
// @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试??
|
// @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试??
|
||||||
case ALIPAY_BALANCE: {
|
case ALIPAY_BALANCE: {
|
||||||
// ② 个性化的参数
|
|
||||||
Participant payeeInfo = new Participant();
|
|
||||||
payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
|
payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
|
||||||
payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号
|
payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号
|
||||||
payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名
|
payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名
|
||||||
model.setPayeeInfo(payeeInfo);
|
model.setPayeeInfo(payeeInfo);
|
||||||
// 1.3 构建 AlipayFundTransUniTransferRequest
|
break;
|
||||||
AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
|
|
||||||
request.setBizModel(model);
|
|
||||||
// 执行请求
|
|
||||||
AlipayFundTransUniTransferResponse response = client.certificateExecute(request);
|
|
||||||
// 处理结果
|
|
||||||
if (!response.isSuccess()) {
|
|
||||||
// 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询
|
|
||||||
if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
|
|
||||||
return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);
|
|
||||||
}
|
|
||||||
return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
|
|
||||||
reqDTO.getOutTransferNo(), response);
|
|
||||||
}
|
|
||||||
return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
|
|
||||||
response.getOutBizNo(), response);
|
|
||||||
}
|
}
|
||||||
case BANK_CARD: {
|
case BANK_CARD: {
|
||||||
Participant payeeInfo = new Participant();
|
|
||||||
payeeInfo.setIdentityType("BANKCARD_ACCOUNT");
|
payeeInfo.setIdentityType("BANKCARD_ACCOUNT");
|
||||||
// TODO 待实现
|
// TODO 待实现
|
||||||
throw exception(NOT_IMPLEMENTED);
|
throw exception(NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw exception0(BAD_REQUEST.getCode(),"不正确的转账类型: {}",transferType);
|
throw exception0(BAD_REQUEST.getCode(), "不正确的转账类型: {}", transferType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 1.3 构建 AlipayFundTransUniTransferRequest
|
||||||
|
AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
|
||||||
|
request.setBizModel(model);
|
||||||
|
// 执行请求
|
||||||
|
AlipayFundTransUniTransferResponse response = client.certificateExecute(request);
|
||||||
|
// 处理结果
|
||||||
|
if (!response.isSuccess()) {
|
||||||
|
// 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询,或相同 outBizNo 重新发起转账
|
||||||
|
// 发现 outBizNo 相同 两次请求参数相同. 会返回 "PAYMENT_INFO_INCONSISTENCY", 不知道哪里的问题. 暂时返回 WAIT. 后续job 会轮询
|
||||||
|
if (ObjectUtils.equalsAny(response.getSubCode(),"PAYMENT_INFO_INCONSISTENCY", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
|
||||||
|
return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);
|
||||||
|
}
|
||||||
|
return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
|
||||||
|
reqDTO.getOutTransferNo(), response);
|
||||||
|
} else {
|
||||||
|
if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL"
|
||||||
|
return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
|
||||||
|
reqDTO.getOutTransferNo(), response);
|
||||||
|
}
|
||||||
|
if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中
|
||||||
|
return PayTransferRespDTO.dealingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response);
|
||||||
|
}
|
||||||
|
return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
|
||||||
|
response.getOutBizNo(), response);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) throws Throwable {
|
||||||
|
// 1.1 构建 AlipayFundTransCommonQueryModel
|
||||||
|
AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel();
|
||||||
|
model.setProductCode(type == PayTransferTypeEnum.BANK_CARD ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD");
|
||||||
|
model.setBizScene("DIRECT_TRANSFER"); //业务场景
|
||||||
|
model.setOutBizNo(outTradeNo);
|
||||||
|
// 1.2 构建 AlipayFundTransCommonQueryRequest
|
||||||
|
AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest();
|
||||||
|
request.setBizModel(model);
|
||||||
|
|
||||||
|
// 2.1 执行请求
|
||||||
|
AlipayFundTransCommonQueryResponse response;
|
||||||
|
if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式
|
||||||
|
response = client.certificateExecute(request);
|
||||||
|
} else {
|
||||||
|
response = client.execute(request);
|
||||||
|
}
|
||||||
|
// 2.2 处理返回结果
|
||||||
|
if (response.isSuccess()) {
|
||||||
|
if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL"
|
||||||
|
return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
|
||||||
|
outTradeNo, response);
|
||||||
|
}
|
||||||
|
if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中
|
||||||
|
return PayTransferRespDTO.dealingOf(response.getOrderId(), outTradeNo, response);
|
||||||
|
}
|
||||||
|
return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getPayDate()),
|
||||||
|
response.getOutBizNo(), response);
|
||||||
|
} else {
|
||||||
|
// 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账
|
||||||
|
// 当出现 ORDER_NOT_EXIST 可能是转账还在处理中,也可能是转账处理失败. 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账
|
||||||
|
if (ObjectUtils.equalsAny(response.getSubCode(), "ORDER_NOT_EXIST", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
|
||||||
|
return PayTransferRespDTO.waitingOf(null, outTradeNo, response);
|
||||||
|
}
|
||||||
|
return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
|
||||||
|
outTradeNo, response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 各种工具方法 ==========
|
// ========== 各种工具方法 ==========
|
||||||
|
@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifie
|
|||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -71,4 +72,9 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
|
|||||||
throw new UnsupportedOperationException("待实现");
|
throw new UnsupportedOperationException("待实现");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) {
|
||||||
|
throw new UnsupportedOperationException("待实现");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDT
|
|||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
|
||||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
||||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
|
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
|
||||||
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
|
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
|
||||||
@ -431,6 +432,12 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
|||||||
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
|
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
|
||||||
throw new UnsupportedOperationException("待实现");
|
throw new UnsupportedOperationException("待实现");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) {
|
||||||
|
throw new UnsupportedOperationException("待实现");
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 各种工具方法 ==========
|
// ========== 各种工具方法 ==========
|
||||||
|
|
||||||
static String formatDateV2(LocalDateTime time) {
|
static String formatDateV2(LocalDateTime time) {
|
||||||
|
@ -38,4 +38,8 @@ public enum PayTransferStatusRespEnum {
|
|||||||
public static boolean isClosed(Integer status) {
|
public static boolean isClosed(Integer status) {
|
||||||
return Objects.equals(status, CLOSED.getStatus());
|
return Objects.equals(status, CLOSED.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isInProgress(Integer status) {
|
||||||
|
return Objects.equals(status, IN_PROGRESS.getStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,9 +66,9 @@ public interface ErrorCodeConstants {
|
|||||||
// ========== 转账模块 1-007-009-000 ==========
|
// ========== 转账模块 1-007-009-000 ==========
|
||||||
ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}");
|
ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}");
|
||||||
ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在");
|
ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在");
|
||||||
ErrorCode PAY_TRANSFER_STATUS_IS_SUCCESS = new ErrorCode(1_007_009_002, "转账单已成功转账");
|
ErrorCode PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH = new ErrorCode(1_007_009_002, "两次相同转账请求的类型不匹配");
|
||||||
ErrorCode PAY_TRANSFER_EXISTS = new ErrorCode(1_007_009_003, "已经存在转账单");
|
ErrorCode PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "两次相同转账请求的金额不匹配");
|
||||||
ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询转账订单相关状态");
|
ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经发起,请查询转账订单相关状态");
|
||||||
ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账");
|
ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账");
|
||||||
ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中");
|
ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中");
|
||||||
|
|
||||||
|
@ -40,9 +40,13 @@ public enum PayTransferStatusEnum {
|
|||||||
public static boolean isClosed(Integer status) {
|
public static boolean isClosed(Integer status) {
|
||||||
return Objects.equals(status, CLOSED.getStatus());
|
return Objects.equals(status, CLOSED.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWaiting(Integer status) {
|
public static boolean isWaiting(Integer status) {
|
||||||
return Objects.equals(status, WAITING.getStatus());
|
return Objects.equals(status, WAITING.getStatus());
|
||||||
}
|
}
|
||||||
|
public static boolean isInProgress(Integer status) {
|
||||||
|
return Objects.equals(status, IN_PROGRESS.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否处于待转账或者转账中的状态
|
* 是否处于待转账或者转账中的状态
|
||||||
|
@ -18,7 +18,7 @@ public interface PayTransferConvert {
|
|||||||
|
|
||||||
PayTransferDO convert(PayTransferCreateReqDTO dto);
|
PayTransferDO convert(PayTransferCreateReqDTO dto);
|
||||||
|
|
||||||
PayTransferUnifiedReqDTO convert2(PayTransferCreateReqDTO dto);
|
PayTransferUnifiedReqDTO convert2(PayTransferDO dto);
|
||||||
|
|
||||||
PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo);
|
PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo);
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package cn.iocoder.yudao.module.pay.dal.mysql.transfer;
|
package cn.iocoder.yudao.module.pay.dal.mysql.transfer;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -40,6 +40,10 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> {
|
|||||||
.betweenIfPresent(PayTransferDO::getCreateTime, reqVO.getCreateTime())
|
.betweenIfPresent(PayTransferDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.orderByDesc(PayTransferDO::getId));
|
.orderByDesc(PayTransferDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<PayTransferDO> selectListByStatus(Integer status){
|
||||||
|
return selectList(PayTransferDO::getStatus, status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
|||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
|
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
|
||||||
@ -181,4 +182,9 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
|
|||||||
throw new UnsupportedOperationException("待实现");
|
throw new UnsupportedOperationException("待实现");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) {
|
||||||
|
throw new UnsupportedOperationException("待实现");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package cn.iocoder.yudao.module.pay.job.transfer;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转账订单的同步 Job
|
||||||
|
*
|
||||||
|
* 由于转账订单的转账结果,有些渠道是异步通知进行同步的,考虑到异步通知可能会失败(小概率),所以需要定时进行同步。
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PayTransferSyncJob implements JobHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayTransferService transferService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantJob
|
||||||
|
public String execute(String param) {
|
||||||
|
int count = transferService.syncTransfer();
|
||||||
|
return StrUtil.format("同步转账订单 {} 个", count);
|
||||||
|
}
|
||||||
|
}
|
@ -48,4 +48,10 @@ public interface PayTransferService {
|
|||||||
*/
|
*/
|
||||||
PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO);
|
PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步渠道转账单状态
|
||||||
|
*
|
||||||
|
* @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的
|
||||||
|
*/
|
||||||
|
int syncTransfer();
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.transfer;
|
package cn.iocoder.yudao.module.pay.service.transfer;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||||
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
|
||||||
@ -18,6 +20,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
|
|||||||
import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
|
||||||
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
@ -27,7 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
import java.util.Objects;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE;
|
import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE;
|
||||||
@ -75,56 +78,60 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
|
public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
|
||||||
// 1.1 校验转账单是否可以提交
|
// 1.1 校验 App
|
||||||
validateTransferCanCreate(reqDTO.getAppId(), reqDTO.getMerchantTransferId());
|
|
||||||
// 1.2 校验 App
|
|
||||||
PayAppDO payApp = appService.validPayApp(reqDTO.getAppId());
|
PayAppDO payApp = appService.validPayApp(reqDTO.getAppId());
|
||||||
// 1.3 校验支付渠道是否有效
|
// 1.2 校验支付渠道是否有效
|
||||||
PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
|
PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
|
||||||
PayClient client = channelService.getPayClient(channel.getId());
|
PayClient client = channelService.getPayClient(channel.getId());
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||||
throw exception(CHANNEL_NOT_FOUND);
|
throw exception(CHANNEL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 2.创建转账单
|
// 1.3 校验转账单已经发起过转账。
|
||||||
String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);
|
PayTransferDO transfer = validateTransferCanCreate(reqDTO);
|
||||||
PayTransferDO transfer = INSTANCE.convert(reqDTO)
|
|
||||||
.setChannelId(channel.getId())
|
if (transfer == null) {
|
||||||
.setNo(no).setStatus(WAITING.getStatus())
|
// 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账
|
||||||
.setNotifyUrl(payApp.getTransferNotifyUrl());
|
String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);
|
||||||
transferMapper.insert(transfer);
|
transfer = INSTANCE.convert(reqDTO)
|
||||||
PayTransferRespDTO unifiedTransferResp = null;
|
.setChannelId(channel.getId())
|
||||||
|
.setNo(no).setStatus(WAITING.getStatus())
|
||||||
|
.setNotifyUrl(payApp.getTransferNotifyUrl());
|
||||||
|
transferMapper.insert(transfer);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// 3. 调用三方渠道发起转账
|
// 3. 调用三方渠道发起转账
|
||||||
PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(reqDTO)
|
PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
|
||||||
.setOutTransferNo(no);
|
.setOutTransferNo(transfer.getNo());
|
||||||
unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
|
PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
|
||||||
} catch (ServiceException ex) {
|
|
||||||
// 业务异常.直接返回转账失败的结果
|
|
||||||
log.error("[createTransfer][转账 id({}) requestDTO({}) 发生业务异常]", transfer.getId(), reqDTO, ex);
|
|
||||||
unifiedTransferResp = PayTransferRespDTO.closedOf("", "", no, ex);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
// 注意这里仅打印异常,不进行抛出。
|
|
||||||
// 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续通过转账回调、或者转账轮询可以拿到。
|
|
||||||
// TODO 需要加转账回调业务接口 和 转账轮询未实现
|
|
||||||
// 最终,在异常的情况下,支付中心会异步回调业务的转账回调接口,提供转账结果
|
|
||||||
log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(unifiedTransferResp)) {
|
|
||||||
// 4. 通知转账结果
|
// 4. 通知转账结果
|
||||||
getSelf().notifyTransfer(channel, unifiedTransferResp);
|
getSelf().notifyTransfer(channel, unifiedTransferResp);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 注意这里仅打印异常,不进行抛出。
|
||||||
|
// 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续转账轮询可以拿到。
|
||||||
|
// 或者使用相同 no 再次发起转账请求
|
||||||
|
log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return transfer.getId();
|
return transfer.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto) {
|
||||||
public PayTransferDO getTransfer(Long id) {
|
PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(dto.getAppId(), dto.getMerchantTransferId());
|
||||||
return transferMapper.selectById(id);
|
if (transfer != null) {
|
||||||
}
|
// 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果.
|
||||||
|
if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
|
||||||
@Override
|
throw exception(PAY_MERCHANT_TRANSFER_EXISTS);
|
||||||
public PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO) {
|
}
|
||||||
return transferMapper.selectPage(pageReqVO);
|
if (ObjectUtil.notEqual(dto.getPrice(), transfer.getPrice())) {
|
||||||
|
throw exception(PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.notEqual(dto.getType(), transfer.getType())) {
|
||||||
|
throw exception(PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果状态为等待状态。不知道渠道转账是否发起成功。 允许使用相同的 no 再次发起转账,渠道会保证幂等
|
||||||
|
return transfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@ -138,17 +145,40 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|||||||
if (PayTransferStatusRespEnum.isClosed(notify.getStatus())) {
|
if (PayTransferStatusRespEnum.isClosed(notify.getStatus())) {
|
||||||
notifyTransferClosed(channel, notify);
|
notifyTransferClosed(channel, notify);
|
||||||
}
|
}
|
||||||
|
// 转账处理中的回调
|
||||||
|
if (PayTransferStatusRespEnum.isInProgress(notify.getStatus())) {
|
||||||
|
notifyTransferInProgress(channel, notify);
|
||||||
|
}
|
||||||
// WAITING 状态无需处理
|
// WAITING 状态无需处理
|
||||||
// TODO IN_PROGRESS 待处理
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateTransferCanCreate(Long appId, String merchantTransferId) {
|
private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) {
|
||||||
PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, merchantTransferId);
|
// 1.校验
|
||||||
if (transfer != null) { // 是否存在
|
PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
|
||||||
throw exception(PAY_MERCHANT_TRANSFER_EXISTS);
|
if (transfer == null) {
|
||||||
|
throw exception(PAY_TRANSFER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
if (isInProgress(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isWaiting(transfer.getStatus())) {
|
||||||
|
throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
// 2.更新
|
||||||
|
int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(),
|
||||||
|
CollUtil.newArrayList(WAITING.getStatus()),
|
||||||
|
new PayTransferDO().setStatus(IN_PROGRESS.getStatus()));
|
||||||
|
if (updateCounts == 0) {
|
||||||
|
throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId());
|
||||||
|
|
||||||
|
// 3. 插入转账通知记录
|
||||||
|
notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
|
||||||
|
transfer.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
|
private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
|
||||||
// 1.校验
|
// 1.校验
|
||||||
PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
|
PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo());
|
||||||
@ -210,6 +240,56 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PayTransferDO getTransfer(Long id) {
|
||||||
|
return transferMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO) {
|
||||||
|
return transferMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int syncTransfer() {
|
||||||
|
List<PayTransferDO> list = transferMapper.selectListByStatus(WAITING.getStatus());
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (PayTransferDO transfer : list) {
|
||||||
|
count += syncTransfer(transfer) ? 1 : 0;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean syncTransfer(PayTransferDO transfer) {
|
||||||
|
try {
|
||||||
|
// 1. 查询转账订单信息
|
||||||
|
PayClient payClient = channelService.getPayClient(transfer.getChannelId());
|
||||||
|
if (payClient == null) {
|
||||||
|
log.error("[syncTransfer][渠道编号({}) 找不到对应的支付客户端]", transfer.getChannelId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PayTransferRespDTO resp = payClient.getTransfer(transfer.getNo(),
|
||||||
|
PayTransferTypeEnum.typeOf(transfer.getType()));
|
||||||
|
|
||||||
|
// 2. 回调转账结果
|
||||||
|
notifyTransfer(transfer.getChannelId(), resp);
|
||||||
|
return true;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("[syncTransfer][transfer({}) 同步转账单状态异常]", transfer.getId(), ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyTransfer(Long channelId, PayTransferRespDTO notify) {
|
||||||
|
// 校验渠道是否有效
|
||||||
|
PayChannelDO channel = channelService.validPayChannel(channelId);
|
||||||
|
// 通知转账结果给对应的业务
|
||||||
|
TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyTransfer(channel, notify));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得自身的代理对象,解决 AOP 生效问题
|
* 获得自身的代理对象,解决 AOP 生效问题
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user