mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-10-13 21:30:25 +00:00
feat 对各种交易增加新的同步失败异常处理, 防止同步失败后无限进行同步
This commit is contained in:
@@ -4,14 +4,14 @@
|
||||
- [ ] 同步回调页
|
||||
- [ ] 收银台功能优化
|
||||
- [ ] 支持配置背景色和图标
|
||||
- [ ] 对各种交易增加新的同步失败异常处理, 防止同步失败后无限进行同步
|
||||
- [x] 对各种交易增加新的同步失败异常处理, 防止同步失败后无限进行同步
|
||||
- [ ] 增加首页驾驶舱功能
|
||||
- [ ] 商户应用要有类似删除的功能, 实现停用冻结, 但不影响数据的关联
|
||||
- [ ] 同步接口优化, 返回同步完的数据
|
||||
- [ ] 服务商支付支持
|
||||
- [x] 服务商支付支持
|
||||
- [x] 支付宝
|
||||
- [ ] 微信
|
||||
- [ ] 微信增加公钥证书方式
|
||||
- [x] 微信
|
||||
- [x] 微信增加公钥证书方式
|
||||
- [ ] 分账重试
|
||||
## 3.0.0.bate3: 分账
|
||||
- [x] SDK接口
|
||||
|
@@ -83,12 +83,6 @@ public class PaySyncService {
|
||||
try {
|
||||
// 执行操作, 获取支付网关同步的结果
|
||||
PaySyncResultBo syncResult = syncPayStrategy.doSync();
|
||||
// 判断是否同步成功
|
||||
if (!syncResult.isSyncSuccess()){
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(payOrder, syncResult, false);
|
||||
throw new OperationFailException(syncResult.getSyncErrorMsg());
|
||||
}
|
||||
// 支付订单的网关订单号是否一致, 不一致进行更新
|
||||
if (!Objects.equals(syncResult.getOutOrderNo(), payOrder.getOutOrderNo())){
|
||||
payOrder.setOutOrderNo(syncResult.getOutOrderNo());
|
||||
@@ -101,14 +95,17 @@ public class PaySyncService {
|
||||
if (!statusSync){
|
||||
this.adjustHandler(syncResult, payOrder);
|
||||
}
|
||||
} catch (PayFailureException e) {
|
||||
} catch (Exception e) {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
syncResult.setSyncSuccess(false);
|
||||
this.saveRecord(payOrder, syncResult, false);
|
||||
throw e;
|
||||
syncResult.setSyncSuccess(false).setSyncErrorMsg(e.getMessage());
|
||||
}
|
||||
if (syncResult.isSyncSuccess()){
|
||||
// 同步成功记录日志
|
||||
this.saveRecord(payOrder, syncResult, !statusSync);
|
||||
} else {
|
||||
// 同步失败记录日志
|
||||
this.saveRecord(payOrder, syncResult, true);
|
||||
}
|
||||
// 同步成功记录日志
|
||||
this.saveRecord(payOrder, syncResult, !statusSync);
|
||||
return new PaySyncResult()
|
||||
.setOrderStatus(payOrder.getStatus())
|
||||
.setAdjust(statusSync);
|
||||
@@ -125,7 +122,10 @@ public class PaySyncService {
|
||||
private boolean checkAndAdjust(PaySyncResultBo payRemoteSyncResult, PayOrder order){
|
||||
var payStatus = payRemoteSyncResult.getPayStatus();
|
||||
String orderStatus = order.getStatus();
|
||||
|
||||
// 如果本地订单为失败时, 直接返回需要进行调整
|
||||
if (orderStatus.equals(FAIL.getCode())){
|
||||
return false;
|
||||
}
|
||||
// 本地订单为支付中时, 对状态进行比较,
|
||||
if (orderStatus.equals(PROGRESS.getCode())){
|
||||
// 如果返回订单也是支付中
|
||||
@@ -157,6 +157,8 @@ public class PaySyncService {
|
||||
case CLOSE, CANCEL -> this.closeLocal(payOrder);
|
||||
// 超时关闭和交易不存在(特殊) 关闭本地支付订单, 同时调用网关进行关闭, 确保后续这个订单不能被支付
|
||||
case TIMEOUT -> this.closeRemote(payOrder);
|
||||
// 同步失败处理
|
||||
case FAIL -> this.failLocal(payOrder,payRemoteSyncResult);
|
||||
default -> throw new SystemUnknownErrorException("代码有问题");
|
||||
}
|
||||
}
|
||||
@@ -187,6 +189,17 @@ public class PaySyncService {
|
||||
payOrderManager.updateById(order);
|
||||
merchantNoticeService.registerPayNotice(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步失败
|
||||
* 同步失败后, 讲订单设置为失败状态, 预防无限重试, 失败不会触发消息通知
|
||||
*/
|
||||
private void failLocal(PayOrder order, PaySyncResultBo syncResult) {
|
||||
// 执行策略的关闭方法
|
||||
order.setStatus(FAIL.getCode()).setErrorMsg(syncResult.getSyncErrorMsg());
|
||||
payOrderManager.updateById(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭网关交易, 同时也会关闭本地支付
|
||||
* 回调: 执行所有的支付通道关闭支付逻辑
|
||||
|
@@ -3,6 +3,9 @@ package org.dromara.daxpay.service.service.trade.refund;
|
||||
import cn.bootx.platform.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.core.exception.ValidationFailedException;
|
||||
import cn.bootx.platform.core.util.BigDecimalUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.core.enums.PayRefundStatusEnum;
|
||||
import org.dromara.daxpay.core.enums.PayStatusEnum;
|
||||
import org.dromara.daxpay.core.enums.RefundStatusEnum;
|
||||
@@ -17,11 +20,7 @@ import org.dromara.daxpay.service.entity.order.pay.PayOrder;
|
||||
import org.dromara.daxpay.service.entity.order.refund.RefundOrder;
|
||||
import org.dromara.daxpay.service.service.notice.MerchantNoticeService;
|
||||
import org.dromara.daxpay.service.service.record.flow.TradeFlowRecordService;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -116,9 +115,9 @@ public class RefundAssistService {
|
||||
/**
|
||||
* 更新退款错误信息
|
||||
*/
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public void updateOrderByError(RefundOrder refundOrder, Exception e){
|
||||
refundOrder.setErrorMsg(e.getMessage());
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateOrderByError(RefundOrder refundOrder, String message){
|
||||
refundOrder.setErrorMsg(message);
|
||||
refundOrder.setStatus(RefundStatusEnum.FAIL.getCode());
|
||||
refundOrderManager.updateById(refundOrder);
|
||||
}
|
||||
|
@@ -111,7 +111,7 @@ public class RefundService {
|
||||
} catch (Exception e) {
|
||||
log.error("退款出现错误", e);
|
||||
// 更新退款失败的记录
|
||||
refundAssistService.updateOrderByError(refundOrder, e);
|
||||
refundAssistService.updateOrderByError(refundOrder, e.getMessage());
|
||||
return refundAssistService.buildResult(refundOrder);
|
||||
}
|
||||
SpringUtil.getBean(this.getClass()).successHandler(refundOrder, payOrder, refundResultBo);
|
||||
@@ -163,7 +163,7 @@ public class RefundService {
|
||||
} catch (Exception e) {
|
||||
log.error("重新退款失败:", e);
|
||||
// 记录退款失败的记录
|
||||
refundAssistService.updateOrderByError(refundOrder, e);
|
||||
refundAssistService.updateOrderByError(refundOrder, e.getMessage());
|
||||
// 返回错误响应对象
|
||||
return refundAssistService.buildResult(refundOrder);
|
||||
}
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package org.dromara.daxpay.service.service.trade.refund;
|
||||
|
||||
import cn.bootx.platform.core.exception.RepetitiveOperationException;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.core.enums.RefundStatusEnum;
|
||||
import org.dromara.daxpay.core.enums.TradeTypeEnum;
|
||||
import org.dromara.daxpay.core.exception.OperationFailException;
|
||||
import org.dromara.daxpay.core.exception.PayFailureException;
|
||||
import org.dromara.daxpay.core.exception.TradeNotExistException;
|
||||
import org.dromara.daxpay.core.param.trade.refund.RefundSyncParam;
|
||||
import org.dromara.daxpay.core.result.trade.refund.RefundSyncResult;
|
||||
@@ -17,16 +19,14 @@ import org.dromara.daxpay.service.service.order.refund.RefundOrderQueryService;
|
||||
import org.dromara.daxpay.service.service.record.sync.TradeSyncRecordService;
|
||||
import org.dromara.daxpay.service.strategy.AbsSyncRefundOrderStrategy;
|
||||
import org.dromara.daxpay.service.util.PaymentStrategyFactory;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.dromara.daxpay.core.enums.TradeStatusEnum.FAIL;
|
||||
|
||||
/**
|
||||
* 支付退款同步服务类
|
||||
* @author xxm
|
||||
@@ -75,35 +75,33 @@ public class RefundSyncService {
|
||||
try {
|
||||
|
||||
// 执行操作, 获取支付网关同步的结果
|
||||
RefundSyncResultBo syncResultBo = syncPayStrategy.doSync();
|
||||
RefundSyncResultBo syncResult = syncPayStrategy.doSync();
|
||||
|
||||
// 判断是否同步成功
|
||||
if (!syncResultBo.isSyncSuccess()) {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(refundOrder, syncResultBo, false);
|
||||
throw new OperationFailException(syncResultBo.getSyncErrorMsg());
|
||||
}
|
||||
// 订单的通道交易号是否一致, 不一致进行更新
|
||||
if (Objects.nonNull(syncResultBo.getOutRefundNo()) && !Objects.equals(syncResultBo.getOutRefundNo(), refundOrder.getOutRefundNo())){
|
||||
refundOrder.setOutRefundNo(syncResultBo.getOutRefundNo());
|
||||
if (Objects.nonNull(syncResult.getOutRefundNo()) && !Objects.equals(syncResult.getOutRefundNo(), refundOrder.getOutRefundNo())){
|
||||
refundOrder.setOutRefundNo(syncResult.getOutRefundNo());
|
||||
refundOrderManager.updateById(refundOrder);
|
||||
}
|
||||
// 判断网关状态是否和支付单一致
|
||||
boolean statusSync = this.checkStatus(syncResultBo, refundOrder);
|
||||
boolean statusSync = this.checkStatus(syncResult, refundOrder);
|
||||
try {
|
||||
// 状态不一致,执行退款单调整逻辑
|
||||
if (!statusSync) {
|
||||
// 如果没有支付来源, 设置支付来源为同步
|
||||
this.adjustHandler(syncResultBo, refundOrder);
|
||||
this.adjustHandler(syncResult, refundOrder);
|
||||
}
|
||||
} catch (PayFailureException e) {
|
||||
} catch (Exception e) {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
syncResultBo.setSyncSuccess(false);
|
||||
this.saveRecord(refundOrder, syncResultBo, false);
|
||||
throw e;
|
||||
syncResult.setSyncSuccess(false).setSyncErrorMsg(e.getMessage());
|
||||
}
|
||||
// 判断是否同步成功
|
||||
if (!syncResult.isSyncSuccess()) {
|
||||
// 同步成功记录日志
|
||||
this.saveRecord(refundOrder, syncResult, !statusSync);
|
||||
} else {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(refundOrder, syncResult, true);
|
||||
}
|
||||
// 同步成功记录日志
|
||||
this.saveRecord(refundOrder, syncResultBo, !statusSync);
|
||||
return new RefundSyncResult()
|
||||
.setOrderStatus(refundOrder.getStatus())
|
||||
.setAdjust(statusSync);
|
||||
@@ -120,6 +118,10 @@ public class RefundSyncService {
|
||||
private boolean checkStatus(RefundSyncResultBo syncResult, RefundOrder order){
|
||||
var syncStatus = syncResult.getRefundStatus();
|
||||
String orderStatus = order.getStatus();
|
||||
// 如果本地订单为失败时, 直接返回需要进行调整
|
||||
if (orderStatus.equals(FAIL.getCode())){
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果订单为退款中, 对状态进行比较
|
||||
if (Objects.equals(orderStatus, RefundStatusEnum.SUCCESS.getCode())){
|
||||
@@ -148,7 +150,8 @@ public class RefundSyncService {
|
||||
switch (refundStatus) {
|
||||
case SUCCESS -> refundAssistService.success(order, syncResult.getFinishTime());
|
||||
case PROGRESS -> {}
|
||||
case FAIL, CLOSE-> refundAssistService.close(order);
|
||||
case CLOSE-> refundAssistService.close(order);
|
||||
case FAIL -> refundAssistService.updateOrderByError(order, syncResult.getSyncErrorMsg());
|
||||
default -> log.error("退款同步结果未知, 退款单号:{}, 错误信息:{}", order.getRefundNo(), syncResult.getSyncErrorMsg());
|
||||
}
|
||||
}
|
||||
|
@@ -52,6 +52,16 @@ public class TransferAssistService {
|
||||
return transferOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新转账错误信息
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateOrderByError(TransferOrder transferOrder, String message){
|
||||
transferOrder.setErrorMsg(message);
|
||||
transferOrder.setStatus(TransferStatusEnum.FAIL.getCode());
|
||||
transferOrderManager.updateById(transferOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转账关闭
|
||||
*/
|
||||
|
@@ -89,8 +89,7 @@ public class TransferService {
|
||||
} catch (Exception e) {
|
||||
log.error("转账出现错误", e);
|
||||
// 更新转账失败的记录
|
||||
order.setStatus(TransferStatusEnum.FAIL.getCode()).setErrorMsg(e.getMessage());
|
||||
transferOrderManager.updateById(order);
|
||||
transferAssistService.updateOrderByError(order,e.getMessage());
|
||||
return transferAssistService.buildResult(order);
|
||||
}
|
||||
SpringUtil.getBean(this.getClass()).successHandler(order, transferResultBo);
|
||||
@@ -119,8 +118,7 @@ public class TransferService {
|
||||
} catch (Exception e) {
|
||||
log.error("重现转账出现错误", e);
|
||||
// 更新转账失败的记录
|
||||
order.setStatus(TransferStatusEnum.FAIL.getCode()).setErrorMsg(e.getMessage());
|
||||
transferOrderManager.updateById(order);
|
||||
transferAssistService.updateOrderByError(order,e.getMessage());
|
||||
return transferAssistService.buildResult(order);
|
||||
}
|
||||
SpringUtil.getBean(this.getClass()).successHandler(order, transferResultBo);
|
||||
|
@@ -2,10 +2,14 @@ package org.dromara.daxpay.service.service.trade.transfer;
|
||||
|
||||
import cn.bootx.platform.core.exception.BizException;
|
||||
import cn.bootx.platform.core.exception.RepetitiveOperationException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.core.enums.TradeTypeEnum;
|
||||
import org.dromara.daxpay.core.enums.TransferStatusEnum;
|
||||
import org.dromara.daxpay.core.exception.OperationFailException;
|
||||
import org.dromara.daxpay.core.exception.PayFailureException;
|
||||
import org.dromara.daxpay.core.exception.TradeNotExistException;
|
||||
import org.dromara.daxpay.core.param.trade.transfer.TransferSyncParam;
|
||||
import org.dromara.daxpay.core.result.trade.transfer.TransferSyncResult;
|
||||
@@ -20,17 +24,13 @@ import org.dromara.daxpay.service.service.record.flow.TradeFlowRecordService;
|
||||
import org.dromara.daxpay.service.service.record.sync.TradeSyncRecordService;
|
||||
import org.dromara.daxpay.service.strategy.AbsSyncTransferOrderStrategy;
|
||||
import org.dromara.daxpay.service.util.PaymentStrategyFactory;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.dromara.daxpay.core.enums.TradeStatusEnum.FAIL;
|
||||
|
||||
/**
|
||||
* 转账同步接口
|
||||
* @author xxm
|
||||
@@ -54,7 +54,7 @@ public class TransferSyncService {
|
||||
*/
|
||||
public TransferSyncResult sync(TransferSyncParam param) {
|
||||
TransferOrder transferOrder = transferOrderService.findByBizOrTransferNo(param.getTransferNo(), param.getBizTransferNo(),param.getAppId())
|
||||
.orElseThrow(() -> new TradeNotExistException("退款订单不存在"));
|
||||
.orElseThrow(() -> new TradeNotExistException("转账订单不存在"));
|
||||
// 执行订单同步逻辑
|
||||
return this.syncTransferOrder(transferOrder);
|
||||
}
|
||||
@@ -76,12 +76,6 @@ public class TransferSyncService {
|
||||
try {
|
||||
// 执行操作, 获取支付网关同步的结果
|
||||
var syncResult = syncPayStrategy.doSync();
|
||||
// 判断是否同步成功
|
||||
if (!syncResult.isSyncSuccess()){
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(transferOrder, syncResult, false);
|
||||
throw new OperationFailException(syncResult.getSyncErrorMsg());
|
||||
}
|
||||
// 转账订单的网关订单号是否一致, 不一致进行更新
|
||||
if (!Objects.equals(syncResult.getOutTransferNo(), transferOrder.getOutTransferNo())){
|
||||
transferOrder.setOutTransferNo(syncResult.getOutTransferNo());
|
||||
@@ -94,14 +88,20 @@ public class TransferSyncService {
|
||||
if (!statusSync){
|
||||
this.adjustHandler(syncResult, transferOrder);
|
||||
}
|
||||
} catch (PayFailureException e) {
|
||||
} catch (Exception e) {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
syncResult.setSyncSuccess(false);
|
||||
this.saveRecord(transferOrder, syncResult, false);
|
||||
throw e;
|
||||
}
|
||||
// 同步成功记录日志
|
||||
this.saveRecord(transferOrder, syncResult, statusSync);
|
||||
// 判断是否同步成功
|
||||
if (syncResult.isSyncSuccess()){
|
||||
// 同步成功
|
||||
this.saveRecord(transferOrder, syncResult, statusSync);
|
||||
} else {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(transferOrder, syncResult, true);
|
||||
}
|
||||
return new TransferSyncResult()
|
||||
.setOrderStatus(transferOrder.getStatus())
|
||||
.setAdjust(statusSync);
|
||||
@@ -113,13 +113,16 @@ public class TransferSyncService {
|
||||
|
||||
/**
|
||||
* 检查状态是否一致
|
||||
* @see TransferStatusEnum 退款单状态
|
||||
* @see TransferStatusEnum 转账单状态
|
||||
*/
|
||||
private boolean checkStatus(TransferSyncResultBo syncResult, TransferOrder order){
|
||||
var syncStatus = syncResult.getTransferStatus();
|
||||
String orderStatus = order.getStatus();
|
||||
|
||||
// 如果订单为退款中, 对状态进行比较
|
||||
// 如果本地订单为失败时, 直接返回需要进行调整
|
||||
if (orderStatus.equals(FAIL.getCode())){
|
||||
return false;
|
||||
}
|
||||
// 如果订单为转账中, 对状态进行比较
|
||||
if (Objects.equals(orderStatus, TransferStatusEnum.SUCCESS.getCode())){
|
||||
// 转账完成
|
||||
if (Objects.equals(syncStatus, TransferStatusEnum.SUCCESS)) {
|
||||
@@ -138,7 +141,7 @@ public class TransferSyncService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行退款订单和支付订单的调整
|
||||
* 进行转账订单和支付订单的调整
|
||||
*/
|
||||
private void adjustHandler(TransferSyncResultBo syncResult, TransferOrder order){
|
||||
var syncStatusEnum = syncResult.getTransferStatus();
|
||||
@@ -146,14 +149,15 @@ public class TransferSyncService {
|
||||
switch (syncStatusEnum) {
|
||||
case SUCCESS -> SpringUtil.getBean(this.getClass()).success(order, syncResult);
|
||||
case PROGRESS -> {}
|
||||
case FAIL,CLOSE -> transferAssistService.close(order,syncResult.getFinishTime());
|
||||
case CLOSE -> transferAssistService.close(order,syncResult.getFinishTime());
|
||||
case FAIL -> transferAssistService.updateOrderByError(order,syncResult.getSyncErrorMsg());
|
||||
default -> throw new BizException("代码有问题");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 退款成功, 更新退款单和支付单
|
||||
* 转账成功, 更新转账单和支付单
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void success(TransferOrder order, TransferSyncResultBo syncResult) {
|
||||
|
Reference in New Issue
Block a user