mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-08 13:37:35 +00:00
fix 退款修复时完成时间为空, 通道退款订单可退余额不正确问题修复
This commit is contained in:
@@ -14,6 +14,8 @@ import java.time.LocalDateTime;
|
||||
@Accessors(chain = true)
|
||||
public class RequestLocal {
|
||||
|
||||
/** 接口信息 */
|
||||
|
||||
/** 客户端ip */
|
||||
private String clientIp;
|
||||
|
||||
|
@@ -47,13 +47,14 @@ public class AliPayRefundService {
|
||||
log.error("网关返回退款失败: {}", response.getSubMsg());
|
||||
throw new PayFailureException(response.getSubMsg());
|
||||
}
|
||||
// 接口返回fund_change=Y为退款成功,fund_change=N或无此字段值返回时需通过退款查询接口进一步确认退款状态
|
||||
if (response.getFundChange().equals("Y")){
|
||||
// refundInfo.setStatus(RefundStatusEnum.SUCCESS)
|
||||
// .setGatewayOrderNo(response.getTradeNo());
|
||||
}
|
||||
// 默认为退款中状态
|
||||
refundInfo.setStatus(RefundStatusEnum.PROGRESS)
|
||||
.setGatewayOrderNo(response.getTradeNo());
|
||||
|
||||
// 接口返回fund_change=Y为退款成功,fund_change=N或无此字段值返回时需通过退款查询接口进一步确认退款状态
|
||||
if (response.getFundChange().equals("Y")){
|
||||
refundInfo.setStatus(RefundStatusEnum.SUCCESS);
|
||||
}
|
||||
}
|
||||
catch (AlipayApiException e) {
|
||||
log.error("订单退款失败:", e);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.pay.convert;
|
||||
|
||||
import cn.bootx.platform.daxpay.result.order.PayOrderChannelResult;
|
||||
import cn.bootx.platform.daxpay.result.order.PayChannelOrderResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
|
||||
@@ -25,5 +25,5 @@ public interface PayOrderConvert {
|
||||
|
||||
PayChannelOrderDto convert(PayChannelOrder in);
|
||||
|
||||
PayOrderChannelResult convertResult(PayChannelOrder in);
|
||||
PayChannelOrderResult convertResult(PayChannelOrder in);
|
||||
}
|
||||
|
@@ -87,12 +87,10 @@ public class PayChannelOrderService {
|
||||
* 更新异步支付通道退款余额和状态
|
||||
*/
|
||||
public void updateAsyncPayRefund(PayChannelOrder payChannelOrder, PayRefundChannelOrder refundChannelOrder){
|
||||
// 支付通道订单可退余额
|
||||
int refundableBalance = payChannelOrder.getRefundableBalance() - refundChannelOrder.getAmount();
|
||||
payChannelOrder.setRefundableBalance(refundableBalance);
|
||||
// 支付通道订单状态
|
||||
if (Objects.equals(refundChannelOrder.getStatus(), RefundStatusEnum.SUCCESS.getCode())){
|
||||
PayStatusEnum status = refundableBalance == 0 ? PayStatusEnum.REFUNDED : PayStatusEnum.PARTIAL_REFUND;
|
||||
// 如果可退金额为0说明已经全部退款
|
||||
PayStatusEnum status = payChannelOrder.getRefundableBalance() == 0 ? PayStatusEnum.REFUNDED : PayStatusEnum.PARTIAL_REFUND;
|
||||
payChannelOrder.setStatus(status.getCode());
|
||||
refundChannelOrder.setRefundTime(LocalDateTime.now());
|
||||
} else {
|
||||
|
@@ -7,7 +7,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.QueryPayParam;
|
||||
import cn.bootx.platform.daxpay.result.order.PayOrderChannelResult;
|
||||
import cn.bootx.platform.daxpay.result.order.PayChannelOrderResult;
|
||||
import cn.bootx.platform.daxpay.result.order.PayOrderResult;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.convert.PayOrderConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
@@ -92,12 +92,13 @@ public class PayOrderQueryService {
|
||||
// 查询通道数据
|
||||
List<PayChannelOrder> orderChannelList = payChannelOrderManager.findAllByPaymentId(payOrder.getId());
|
||||
|
||||
List<PayOrderChannelResult> channels = orderChannelList.stream()
|
||||
List<PayChannelOrderResult> channels = orderChannelList.stream()
|
||||
.map(PayOrderConvert.CONVERT::convertResult)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PayOrderResult payOrderResult = new PayOrderResult();
|
||||
BeanUtil.copyProperties(payOrder, payOrderResult);
|
||||
payOrderResult.setPaymentId(payOrder.getId());
|
||||
payOrderResult.setDescription(payOrderExtra.getDescription())
|
||||
.setChannels(channels);
|
||||
|
||||
|
@@ -102,6 +102,7 @@ public class PayRefundOrderQueryService {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
RefundOrderResult refundOrderResult = PayRefundOrderConvert.CONVERT.convertResult(refundOrder);
|
||||
refundOrderResult.setRefundId(refundOrder.getId());
|
||||
refundOrderResult.setChannels(channels);
|
||||
return refundOrderResult;
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.common.aop;
|
||||
|
||||
import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.service.annotation.PaymentApi;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.common.service.PaymentSignService;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayCommonParam;
|
||||
import cn.bootx.platform.daxpay.service.annotation.PaymentApi;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.common.service.PaymentSignService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
@@ -23,7 +23,6 @@ import java.util.Objects;
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentSignService {
|
||||
|
||||
|
||||
private final PaymentAssistService paymentAssistService;;
|
||||
|
||||
/**
|
||||
|
@@ -98,9 +98,9 @@ public class PayRefundAssistService {
|
||||
if (CollUtil.isEmpty(param.getRefundChannels())) {
|
||||
throw new ValidationFailedException("退款通道参数不能为空");
|
||||
}
|
||||
if (Objects.isNull(param.getRefundNo())) {
|
||||
throw new ValidationFailedException("部分退款时退款单号必传");
|
||||
}
|
||||
// if (Objects.isNull(param.getRefundNo())) {
|
||||
// throw new ValidationFailedException("部分退款时退款单号必传");
|
||||
// }
|
||||
}
|
||||
|
||||
// 简单退款校验
|
||||
|
@@ -152,8 +152,8 @@ public class PayRefundService {
|
||||
refundStrategy.initRefundParam(payOrder, refundParam, payChannelOrder);
|
||||
}
|
||||
|
||||
// 对通道支付订单进行预扣款
|
||||
payRefundStrategies.forEach(AbsRefundStrategy::doPreDeductOrderHandler);
|
||||
// 生成通道退款订单对象
|
||||
payRefundStrategies.forEach(AbsRefundStrategy::generateChannelOrder);
|
||||
|
||||
// 退款操作的预处理, 使用独立的新事物进行发起, 返回创建成功的退款订单, 成功后才可以进行下一阶段的操作
|
||||
PayRefundOrder refundOrder = SpringUtil.getBean(this.getClass()).preRefundMethod(refundParam, payOrder, payRefundStrategies);
|
||||
@@ -193,7 +193,7 @@ public class PayRefundService {
|
||||
public PayRefundOrder preRefundMethod(RefundParam refundParam, PayOrder payOrder, List<AbsRefundStrategy> payRefundStrategies) {
|
||||
// --------------------------- 支付订单 -------------------------------------
|
||||
// 预扣支付相关订单要退款的金额并进行更新
|
||||
payRefundStrategies.forEach(AbsRefundStrategy::generateChannelOrder);
|
||||
payRefundStrategies.forEach(AbsRefundStrategy::doPreDeductOrderHandler);
|
||||
List<PayChannelOrder> channelOrders = payRefundStrategies.stream()
|
||||
.map(AbsRefundStrategy::getPayChannelOrder)
|
||||
.collect(Collectors.toList());
|
||||
|
@@ -1,10 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.repair.service;
|
||||
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.RefundRepairWayEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.context.RepairLocal;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
|
||||
@@ -102,7 +103,7 @@ public class RefundRepairService {
|
||||
* 退款成功, 更新退款单和支付单
|
||||
*/
|
||||
private RefundRepairResult success(PayRefundOrder refundOrder, PayOrder payOrder, List<AbsRefundRepairStrategy> repairStrategies) {
|
||||
|
||||
RepairLocal repairInfo = PaymentContextLocal.get().getRepairInfo();
|
||||
// 订单相关状态
|
||||
PayStatusEnum beforePayStatus = PayStatusEnum.findByCode(refundOrder.getStatus());
|
||||
PayStatusEnum afterPayRefundStatus;
|
||||
@@ -114,8 +115,9 @@ public class RefundRepairService {
|
||||
} else {
|
||||
afterPayRefundStatus = PayStatusEnum.PARTIAL_REFUND;
|
||||
}
|
||||
// 设置退款为完成状态
|
||||
refundOrder.setStatus(RefundStatusEnum.SUCCESS.getCode());
|
||||
// 设置退款为完成状态和完成时间
|
||||
refundOrder.setStatus(RefundStatusEnum.SUCCESS.getCode())
|
||||
.setRefundTime(repairInfo.getFinishTime());
|
||||
payOrder.setStatus(afterPayRefundStatus.getCode());
|
||||
|
||||
// 执行退款成功逻辑
|
||||
|
@@ -1,12 +1,15 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.repair.strategy.refund;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsRefundRepairStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
@@ -27,4 +30,18 @@ public class AliRefundRepairStrategy extends AbsRefundRepairStrategy {
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.ALI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款成功修复
|
||||
*/
|
||||
@Override
|
||||
public void doSuccessHandler() {
|
||||
LocalDateTime finishTime = PaymentContextLocal.get()
|
||||
.getRepairInfo()
|
||||
.getFinishTime();
|
||||
// 首先执行父类的修复逻辑
|
||||
super.doSuccessHandler();
|
||||
// 异步支付需要追加完成时间
|
||||
this.getRefundChannelOrder().setRefundTime(finishTime);
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,15 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.repair.strategy.refund;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsRefundRepairStrategy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
@@ -26,4 +29,18 @@ public class WeChatRefundRepairStrategy extends AbsRefundRepairStrategy {
|
||||
public PayChannelEnum getChannel() {
|
||||
return PayChannelEnum.WECHAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款成功修复
|
||||
*/
|
||||
@Override
|
||||
public void doSuccessHandler() {
|
||||
LocalDateTime finishTime = PaymentContextLocal.get()
|
||||
.getRepairInfo()
|
||||
.getFinishTime();
|
||||
// 首先执行父类的修复逻辑
|
||||
super.doSuccessHandler();
|
||||
// 异步支付需要追加完成时间
|
||||
this.getRefundChannelOrder().setRefundTime(finishTime);
|
||||
}
|
||||
}
|
||||
|
@@ -64,11 +64,13 @@ public class PayRefundSyncService {
|
||||
}
|
||||
// 如果不是异步支付, 直接返回返回
|
||||
if (!refundOrder.isAsyncPay()){
|
||||
return new SyncResult().setSuccess(false).setRepair(false).setErrorMsg("订单没有异步通道的退款,不需要同步");
|
||||
// return new SyncResult().setSuccess(false).setRepair(false).setErrorMsg("订单没有异步通道的退款,不需要同步");
|
||||
throw new PayFailureException("订单没有异步通道的退款,不需要同步");
|
||||
}
|
||||
// 如果订单已经关闭, 直接返回失败
|
||||
if (Objects.equals(refundOrder.getStatus(), RefundStatusEnum.CLOSE.getCode())){
|
||||
return new SyncResult().setSuccess(false).setRepair(false).setErrorMsg("订单已经关闭,不需要同步");
|
||||
// return new SyncResult().setSuccess(false).setRepair(false). setErrorMsg("订单已经关闭,不需要同步");
|
||||
throw new PayFailureException("订单已经关闭,不需要同步");
|
||||
}
|
||||
return this.syncRefundOrder(refundOrder);
|
||||
}
|
||||
@@ -95,7 +97,9 @@ public class PayRefundSyncService {
|
||||
// 判断是否同步成功
|
||||
if (Objects.equals(syncResult.getSyncStatus(), RefundSyncStatusEnum.FAIL)) {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
return new SyncResult().setErrorMsg(syncResult.getErrorMsg());
|
||||
// return new SyncResult().setErrorMsg(syncResult.getErrorMsg());
|
||||
this.saveRecord(refundOrder, syncResult, false, null, syncResult.getErrorMsg());
|
||||
throw new PayFailureException(syncResult.getErrorMsg());
|
||||
}
|
||||
// 支付订单的网关订单号是否一致, 不一致进行更新
|
||||
if (Objects.nonNull(syncResult.getGatewayOrderNo()) && !Objects.equals(syncResult.getGatewayOrderNo(), refundOrder.getGatewayOrderNo())){
|
||||
@@ -120,13 +124,12 @@ public class PayRefundSyncService {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
syncResult.setSyncStatus(RefundSyncStatusEnum.FAIL);
|
||||
this.saveRecord(refundOrder, syncResult, false, null, e.getMessage());
|
||||
return new SyncResult().setErrorMsg(e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
// 同步成功记录日志
|
||||
this.saveRecord(refundOrder, syncResult, !statusSync, repairResult.getRepairNo(), null);
|
||||
return new SyncResult()
|
||||
.setGatewayStatus(syncResult.getSyncStatus().getCode())
|
||||
.setSuccess(true)
|
||||
.setRepair(!statusSync)
|
||||
.setRepairOrderNo(repairResult.getRepairNo());
|
||||
} finally {
|
||||
@@ -175,7 +178,7 @@ public class PayRefundSyncService {
|
||||
repair = repairService.repair(order, RefundRepairWayEnum.SUCCESS);
|
||||
break;
|
||||
case PROGRESS:
|
||||
// 不进行处理 TODO 添加重试
|
||||
// 不进行处理
|
||||
log.warn("退款状态同步接口调用出错");
|
||||
break;
|
||||
case FAIL: {
|
||||
|
@@ -74,7 +74,8 @@ public class PaySyncService {
|
||||
}
|
||||
// 如果不是异步支付, 直接返回返回
|
||||
if (!payOrder.isAsyncPay()){
|
||||
return new SyncResult().setSuccess(false).setRepair(false).setErrorMsg("订单没有异步支付方式,不需要同步");
|
||||
// return new SyncResult().setSuccess(false).setRepair(false).setErrorMsg("订单没有异步支付方式,不需要同步");
|
||||
throw new PayFailureException("订单没有异步支付方式,不需要同步");
|
||||
}
|
||||
// 执行订单同步逻辑
|
||||
return this.syncPayOrder(payOrder);
|
||||
@@ -103,7 +104,8 @@ public class PaySyncService {
|
||||
if (Objects.equals(syncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
this.saveRecord(payOrder, syncResult, false, null, syncResult.getErrorMsg());
|
||||
return new SyncResult().setErrorMsg(syncResult.getErrorMsg());
|
||||
// return new SyncResult().setErrorMsg(syncResult.getErrorMsg());
|
||||
throw new PayFailureException(syncResult.getErrorMsg());
|
||||
}
|
||||
// 支付订单的网关订单号是否一致, 不一致进行更新
|
||||
if (Objects.nonNull(syncResult.getGatewayOrderNo()) && !Objects.equals(syncResult.getGatewayOrderNo(), payOrder.getGatewayOrderNo())){
|
||||
@@ -129,14 +131,14 @@ public class PaySyncService {
|
||||
// 同步失败, 返回失败响应, 同时记录失败的日志
|
||||
syncResult.setSyncStatus(PaySyncStatusEnum.FAIL);
|
||||
this.saveRecord(payOrder, syncResult, false, null, e.getMessage());
|
||||
return new SyncResult().setErrorMsg(e.getMessage());
|
||||
// return new SyncResult().setErrorMsg(e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 同步成功记录日志
|
||||
this.saveRecord( payOrder, syncResult, !statusSync, repairResult.getRepairNo(), null);
|
||||
return new SyncResult()
|
||||
.setGatewayStatus(syncResult.getSyncStatus().getCode())
|
||||
.setSuccess(true)
|
||||
.setRepair(!statusSync)
|
||||
.setRepairOrderNo(repairResult.getRepairNo());
|
||||
} finally {
|
||||
@@ -180,7 +182,7 @@ public class PaySyncService {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO 退款比对
|
||||
// 退款比对状态不做额外处理, 需要通过退款接口进行处理
|
||||
if (orderStatus.equals(PayStatusEnum.REFUNDED.getCode()) && syncStatus.equals(PaySyncStatusEnum.REFUND)){
|
||||
return true;
|
||||
}
|
||||
@@ -221,7 +223,7 @@ public class PaySyncService {
|
||||
}
|
||||
// 调用出错
|
||||
case FAIL: {
|
||||
// 不进行处理 TODO 添加重试
|
||||
// 不进行处理
|
||||
log.warn("支付状态同步接口调用出错");
|
||||
break;
|
||||
}
|
||||
|
@@ -75,12 +75,14 @@ public abstract class AbsRefundStrategy implements PayStrategy{
|
||||
* 退款发起成功操作, 异步支付通道需要进行重写
|
||||
*/
|
||||
public void doSuccessHandler() {
|
||||
// 更新退款订单数据状态
|
||||
this.refundChannelOrder.setStatus(RefundStatusEnum.SUCCESS.getCode()).setRefundTime(LocalDateTime.now());
|
||||
// 更新退款订单数据状态和完成时间
|
||||
this.refundChannelOrder
|
||||
.setStatus(RefundStatusEnum.SUCCESS.getCode()).
|
||||
setRefundTime(LocalDateTime.now());
|
||||
|
||||
// 支付通道订单可退余额
|
||||
int refundableBalance = this.getPayChannelOrder().getRefundableBalance() - this.refundChannelOrder.getAmount();
|
||||
// 支付通道订单状态
|
||||
// 如果可退金额为0说明已经全部退款
|
||||
PayStatusEnum status = refundableBalance == 0 ? PayStatusEnum.REFUNDED : PayStatusEnum.PARTIAL_REFUND;
|
||||
this.payChannelOrder.setRefundableBalance(refundableBalance)
|
||||
.setStatus(status.getCode());
|
||||
|
Reference in New Issue
Block a user