|
|
@@ -5,13 +5,13 @@ import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.extra.spring.SpringUtil;
|
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|
|
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
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.PayTransferUnifiedReqDTO;
|
|
|
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
|
|
|
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.controller.admin.transfer.vo.PayTransferCreateReqVO;
|
|
|
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
|
|
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
|
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
|
|
@@ -25,7 +25,6 @@ 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.notify.PayNotifyService;
|
|
|
import jakarta.annotation.Resource;
|
|
|
-import jakarta.validation.Validator;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
@@ -33,9 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
import java.util.List;
|
|
|
|
|
|
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.enums.ErrorCodeConstants.*;
|
|
|
-import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.*;
|
|
|
|
|
|
// TODO @jason:等彻底实现完,单测写写;
|
|
|
|
|
|
@@ -63,21 +60,6 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|
|
private PayNotifyService notifyService;
|
|
|
@Resource
|
|
|
private PayNoRedisDAO noRedisDAO;
|
|
|
- @Resource
|
|
|
- private Validator validator;
|
|
|
-
|
|
|
- @Override
|
|
|
- public PayTransferDO createTransfer(PayTransferCreateReqVO reqVO, String userIp) {
|
|
|
- // 1. 校验参数
|
|
|
- reqVO.validate(validator);
|
|
|
-
|
|
|
- // 2. 创建转账单,发起转账
|
|
|
- PayTransferCreateReqDTO req = INSTANCE.convert(reqVO).setUserIp(userIp);
|
|
|
- Long transferId = createTransfer(req);
|
|
|
-
|
|
|
- // 3. 返回转账单
|
|
|
- return getTransfer(transferId);
|
|
|
- }
|
|
|
|
|
|
@Override
|
|
|
public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
|
|
|
@@ -90,34 +72,32 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|
|
log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
|
|
throw exception(CHANNEL_NOT_FOUND);
|
|
|
}
|
|
|
- // 1.3 校验转账单已经发起过转账。
|
|
|
+ // 1.3 校验转账单已经发起过转账
|
|
|
PayTransferDO transfer = validateTransferCanCreate(reqDTO, payApp.getId());
|
|
|
|
|
|
+ // 2. 不存在创建转账单,否则允许使用相同的 no 再次发起转账
|
|
|
if (transfer == null) {
|
|
|
- // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账
|
|
|
String no = noRedisDAO.generate(TRANSFER_NO_PREFIX);
|
|
|
- transfer = INSTANCE.convert(reqDTO)
|
|
|
- .setChannelId(channel.getId())
|
|
|
- .setNo(no).setStatus(WAITING.getStatus())
|
|
|
- .setNotifyUrl(payApp.getTransferNotifyUrl())
|
|
|
- .setAppId(channel.getAppId());
|
|
|
+ transfer = BeanUtils.toBean(reqDTO, PayTransferDO.class)
|
|
|
+ .setAppId(channel.getAppId()).setChannelId(channel.getId())
|
|
|
+ .setNo(no).setStatus(PayTransferStatusEnum.WAITING.getStatus())
|
|
|
+ .setNotifyUrl(payApp.getTransferNotifyUrl());
|
|
|
transferMapper.insert(transfer);
|
|
|
}
|
|
|
try {
|
|
|
// 3. 调用三方渠道发起转账
|
|
|
- PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
|
|
|
- .setOutTransferNo(transfer.getNo());
|
|
|
- transferUnifiedReq.setNotifyUrl(genChannelTransferNotifyUrl(channel));
|
|
|
+ PayTransferUnifiedReqDTO transferUnifiedReq = BeanUtils.toBean(reqDTO, PayTransferUnifiedReqDTO.class)
|
|
|
+ .setOutTransferNo(transfer.getNo())
|
|
|
+ .setNotifyUrl(genChannelTransferNotifyUrl(channel));
|
|
|
PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
|
|
|
// 4. 通知转账结果
|
|
|
getSelf().notifyTransfer(channel, unifiedTransferResp);
|
|
|
} catch (Throwable e) {
|
|
|
// 注意这里仅打印异常,不进行抛出。
|
|
|
// 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续转账轮询可以拿到。
|
|
|
- // 或者使用相同 no 再次发起转账请求
|
|
|
- log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
|
|
|
+ // 或者,使用相同 no 再次发起转账请求
|
|
|
+ log.error("[createTransfer][转账编号({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e);
|
|
|
}
|
|
|
-
|
|
|
return transfer.getId();
|
|
|
}
|
|
|
|
|
|
@@ -131,21 +111,23 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|
|
return payProperties.getTransferNotifyUrl() + "/" + channel.getId();
|
|
|
}
|
|
|
|
|
|
- private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) {
|
|
|
- PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId());
|
|
|
+ private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO reqDTO, Long appId) {
|
|
|
+ PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, reqDTO.getMerchantTransferId());
|
|
|
if (transfer != null) {
|
|
|
- // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果.
|
|
|
+ // 已经存在,并且状态不为等待状态:说明已经调用渠道转账并返回结果
|
|
|
if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
|
|
|
- throw exception(PAY_MERCHANT_TRANSFER_EXISTS);
|
|
|
+ throw exception(PAY_TRANSFER_CREATE_MERCHANT_EXISTS);
|
|
|
}
|
|
|
- if (ObjectUtil.notEqual(dto.getPrice(), transfer.getPrice())) {
|
|
|
- throw exception(PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH);
|
|
|
+ // 校验参数是否一致
|
|
|
+ if (ObjectUtil.notEqual(reqDTO.getPrice(), transfer.getPrice())) {
|
|
|
+ throw exception(PAY_TRANSFER_CREATE_PRICE_NOT_MATCH);
|
|
|
}
|
|
|
- if (ObjectUtil.notEqual(dto.getType(), transfer.getType())) {
|
|
|
- throw exception(PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH);
|
|
|
+ if (ObjectUtil.notEqual(reqDTO.getChannelCode(), transfer.getChannelCode())) {
|
|
|
+ throw exception(PAY_TRANSFER_CREATE_CHANNEL_NOT_MATCH);
|
|
|
}
|
|
|
}
|
|
|
- // 如果状态为等待状态。不知道渠道转账是否发起成功。 允许使用相同的 no 再次发起转账,渠道会保证幂等
|
|
|
+ // 如果状态为等待状态:不知道渠道转账是否发起成功
|
|
|
+ // 特殊:允许使用相同的 no 再次发起转账,渠道会保证幂等
|
|
|
return transfer;
|
|
|
}
|
|
|
|
|
|
@@ -161,94 +143,94 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|
|
notifyTransferClosed(channel, notify);
|
|
|
}
|
|
|
// 转账处理中的回调
|
|
|
- if (PayTransferStatusRespEnum.isInProgress(notify.getStatus())) {
|
|
|
- notifyTransferInProgress(channel, notify);
|
|
|
+ if (PayTransferStatusRespEnum.isProcessing(notify.getStatus())) {
|
|
|
+ notifyTransferProgressing(channel, notify);
|
|
|
}
|
|
|
// WAITING 状态无需处理
|
|
|
}
|
|
|
|
|
|
- private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) {
|
|
|
+ private void notifyTransferProgressing(PayChannelDO channel, PayTransferRespDTO notify) {
|
|
|
// 1.校验
|
|
|
PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
|
|
|
if (transfer == null) {
|
|
|
throw exception(PAY_TRANSFER_NOT_FOUND);
|
|
|
}
|
|
|
- if (isInProgress(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新
|
|
|
+ if (PayTransferStatusEnum.isProgressing(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新
|
|
|
+ log.info("[notifyTransferProgressing][transfer({}) 已经是转账中状态,无需更新]", transfer.getId());
|
|
|
return;
|
|
|
}
|
|
|
- if (!isWaiting(transfer.getStatus())) {
|
|
|
+ if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
|
|
|
throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
|
|
|
}
|
|
|
- // 2.更新
|
|
|
+
|
|
|
+ // 2. 更新状态
|
|
|
int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(),
|
|
|
- CollUtil.newArrayList(WAITING.getStatus()),
|
|
|
- new PayTransferDO().setStatus(IN_PROGRESS.getStatus()));
|
|
|
+ PayTransferStatusEnum.WAITING.getStatus(),
|
|
|
+ new PayTransferDO().setStatus(PayTransferStatusEnum.PROCESSING.getStatus()));
|
|
|
if (updateCounts == 0) {
|
|
|
throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
|
|
|
}
|
|
|
- log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId());
|
|
|
+ log.info("[notifyTransferProgressing][transfer({}) 更新为转账进行中状态]", transfer.getId());
|
|
|
}
|
|
|
|
|
|
-
|
|
|
private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
|
|
|
- // 1.校验
|
|
|
+ // 1. 校验状态
|
|
|
PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
|
|
|
if (transfer == null) {
|
|
|
throw exception(PAY_TRANSFER_NOT_FOUND);
|
|
|
}
|
|
|
- if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新
|
|
|
+ if (PayTransferStatusEnum.isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新
|
|
|
+ log.info("[notifyTransferSuccess][transfer({}) 已经是成功状态,无需更新]", transfer.getId());
|
|
|
return;
|
|
|
}
|
|
|
- if (!isPendingStatus(transfer.getStatus())) {
|
|
|
- throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
|
|
|
+ if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
|
|
|
+ throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
|
|
|
}
|
|
|
- // 2.更新
|
|
|
+
|
|
|
+ // 2. 更新状态
|
|
|
int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(),
|
|
|
- CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
|
|
|
- new PayTransferDO().setStatus(SUCCESS.getStatus()).setSuccessTime(notify.getSuccessTime())
|
|
|
+ CollUtil.newArrayList(PayTransferStatusEnum.WAITING.getStatus(), PayTransferStatusEnum.PROCESSING.getStatus()),
|
|
|
+ new PayTransferDO().setStatus(PayTransferStatusEnum.SUCCESS.getStatus())
|
|
|
+ .setSuccessTime(notify.getSuccessTime())
|
|
|
.setChannelTransferNo(notify.getChannelTransferNo())
|
|
|
- .setChannelId(channel.getId()).setChannelCode(channel.getCode())
|
|
|
.setChannelNotifyData(JsonUtils.toJsonString(notify)));
|
|
|
if (updateCounts == 0) {
|
|
|
- throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
|
|
|
+ throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
|
|
|
}
|
|
|
- log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
|
|
|
+ log.info("[notifyTransferSuccess][transfer({}) 更新为已转账]", transfer.getId());
|
|
|
|
|
|
// 3. 插入转账通知记录
|
|
|
- notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
|
|
|
- transfer.getId());
|
|
|
+ notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), transfer.getId());
|
|
|
}
|
|
|
|
|
|
private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
|
|
|
- // 1.校验
|
|
|
+ // 1. 校验状态
|
|
|
PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
|
|
|
if (transfer == null) {
|
|
|
throw exception(PAY_TRANSFER_NOT_FOUND);
|
|
|
}
|
|
|
- if (isClosed(transfer.getStatus())) { // 如果已是关闭状态,直接返回,不用重复更新
|
|
|
- log.info("[updateTransferClosed][transfer({}) 已经是关闭状态,无需更新]", transfer.getId());
|
|
|
+ if (PayTransferStatusEnum.isClosed(transfer.getStatus())) { // 如果已是关闭状态,直接返回,不用重复更新
|
|
|
+ log.info("[notifyTransferClosed][transfer({}) 已经是关闭状态,无需更新]", transfer.getId());
|
|
|
return;
|
|
|
}
|
|
|
- if (!isPendingStatus(transfer.getStatus())) {
|
|
|
- throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
|
|
|
+ if (!PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) {
|
|
|
+ throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
|
|
|
}
|
|
|
|
|
|
- // 2.更新
|
|
|
+ // 2. 更新状态
|
|
|
int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(),
|
|
|
- CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
|
|
|
- new PayTransferDO().setStatus(CLOSED.getStatus()).setChannelId(channel.getId())
|
|
|
- .setChannelCode(channel.getCode()).setChannelTransferNo(notify.getChannelTransferNo())
|
|
|
- .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg())
|
|
|
- .setChannelNotifyData(JsonUtils.toJsonString(notify)));
|
|
|
+ CollUtil.newArrayList(PayTransferStatusEnum.WAITING.getStatus(), PayTransferStatusEnum.PROCESSING.getStatus()),
|
|
|
+ new PayTransferDO().setStatus(PayTransferStatusEnum.CLOSED.getStatus())
|
|
|
+ .setChannelTransferNo(notify.getChannelTransferNo())
|
|
|
+ .setChannelNotifyData(JsonUtils.toJsonString(notify))
|
|
|
+ .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()));
|
|
|
if (updateCount == 0) {
|
|
|
- throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
|
|
|
+ throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING_OR_PROCESSING);
|
|
|
}
|
|
|
- log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
|
|
|
+ log.info("[notifyTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId());
|
|
|
|
|
|
// 3. 插入转账通知记录
|
|
|
- notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
|
|
|
- transfer.getId());
|
|
|
-
|
|
|
+ notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), transfer.getId());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -263,7 +245,8 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|
|
|
|
|
@Override
|
|
|
public int syncTransfer() {
|
|
|
- List<PayTransferDO> list = transferMapper.selectListByStatus(WAITING.getStatus());
|
|
|
+ List<PayTransferDO> list = transferMapper.selectListByStatus(CollUtil.newArrayList(
|
|
|
+ PayTransferStatusEnum.WAITING.getStatus(), PayTransferStatusEnum.PROCESSING.getStatus()));
|
|
|
if (CollUtil.isEmpty(list)) {
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -308,4 +291,5 @@ public class PayTransferServiceImpl implements PayTransferService {
|
|
|
private PayTransferServiceImpl getSelf() {
|
|
|
return SpringUtil.getBean(getClass());
|
|
|
}
|
|
|
+
|
|
|
}
|