Revert "实付金额0退款流程优化"

This reverts commit 8d812bf3df2862cc461d29db87399fc7250d54f4.
This commit is contained in:
马梓彭 2026-08-07 10:41:09 +08:00
parent 03a3d175b9
commit 26750d9bf1

View File

@ -997,9 +997,6 @@ public class UnifiedRegistrationService : ITransient
var now = DateTime.Now; var now = DateTime.Now;
// 1. 确保有订单号(预报名创建时 OrderNo 为空字符串) // 1. 确保有订单号(预报名创建时 OrderNo 为空字符串)
// 注意:0元成交不涉及外部支付接口,订单号首次生成后复用即可。
// 与付费支付的"强制重新生成"策略不同,因为无需应对微信支付的参数一致性约束。
// 幂等保护已在 ProcessPaymentAsync:L299 完成,此处实际每个报名订单只执行一次。
if (string.IsNullOrEmpty(registration.OrderNo)) if (string.IsNullOrEmpty(registration.OrderNo))
{ {
registration.OrderNo = await _orderNoGeneratorService.GenerateOrderNoAsync(); registration.OrderNo = await _orderNoGeneratorService.GenerateOrderNoAsync();
@ -3769,29 +3766,13 @@ public class UnifiedRegistrationService : ITransient
var actualPaidAmount = order?.ActualAmount ?? registration.TotalAmount; var actualPaidAmount = order?.ActualAmount ?? registration.TotalAmount;
var originalAmount = registration.TotalAmount; var originalAmount = registration.TotalAmount;
decimal originalRefundAmount;
decimal actualRefundAmount;
// 0 元成交(优惠券全额抵扣 / 免费赛事):实付为 0,无款可退,直接短路。
// 不走按比例折算,避免 originalAmount>0 而 actualPaidAmount 取值异常时算出正的退款额造成资损。
// 注意:优惠券已核销,按"使用后不予退还"规则不做回退。
if (actualPaidAmount <= 0)
{
originalRefundAmount = 0;
actualRefundAmount = 0;
_logger.LogInformation("0元成交无需退款:报名ID={RegistrationId}, 原价={OriginalAmount}, 实付=0",
registration.Id, originalAmount);
}
else
{
// 先计算按原价应该退多少 // 先计算按原价应该退多少
originalRefundAmount = await CalculateActualRefundAmountAsync(input, registration, eventInfo, items, persons); decimal originalRefundAmount = await CalculateActualRefundAmountAsync(input, registration, eventInfo, items, persons);
// 按比例计算实际退款金额 // 按比例计算实际退款金额
actualRefundAmount = originalAmount > 0 ? originalRefundAmount * (actualPaidAmount / originalAmount) : 0; decimal actualRefundAmount = originalAmount > 0 ? originalRefundAmount * (actualPaidAmount / originalAmount) : 0;
actualRefundAmount = RoundUpToTwoDecimalPlaces(actualRefundAmount); actualRefundAmount = RoundUpToTwoDecimalPlaces(actualRefundAmount);
actualRefundAmount = Math.Max(0, Math.Min(actualRefundAmount, actualPaidAmount)); actualRefundAmount = Math.Min(actualRefundAmount, actualPaidAmount);
}
_logger.LogInformation("统一退款金额计算:报名ID={RegistrationId}, 原价={OriginalAmount}, 实付={ActualPaidAmount}, 按原价应退={OriginalRefundAmount}, 实际退款={ActualRefundAmount}", _logger.LogInformation("统一退款金额计算:报名ID={RegistrationId}, 原价={OriginalAmount}, 实付={ActualPaidAmount}, 按原价应退={OriginalRefundAmount}, 实际退款={ActualRefundAmount}",
registration.Id, originalAmount, actualPaidAmount, originalRefundAmount, actualRefundAmount); registration.Id, originalAmount, actualPaidAmount, originalRefundAmount, actualRefundAmount);
@ -3837,29 +3818,26 @@ public class UnifiedRegistrationService : ITransient
long? refundOrderId = null; long? refundOrderId = null;
string? refundOrderNo = null; string? refundOrderNo = null;
// 第一步:先创建退款订单 // 第一步:先创建退款订单(如果有退款金额的话)
// 只要是"有金额"的报名单(原价 > 0),取消时一律建退款订单(OrderType=2),即使实退为 0。 if (registration.TotalAmount > 0 && !string.IsNullOrEmpty(registration.OrderNo) && actualRefundAmount > 0)
// 原因:OrderType==2 是订单列表/详情展示退款轨迹的唯一依据,且软删除的人员、项目要挂到 {
// refundOrderId 上才能追溯。券全额抵扣(实付 0、实退 0)若不建单,取消后无据可查 —— 与 var originalOrder = await _orderRepository.GetFirstAsync(o => o.OrderNo == registration.OrderNo);
// 0 元成交不建订单是同一类状态孤岛。是否真正打款由第二步按 actualRefundAmount > 0 判断,与建单解耦。 if (originalOrder != null)
// 复用上面已按 OrderType==1 && !DeleteMark 过滤好的 order,避免按 OrderNo 反查捞到退款单。
if (registration.TotalAmount > 0 && order != null)
{ {
var newRefundOrder = new Core.Entities.Order var newRefundOrder = new Core.Entities.Order
{ {
Id = _idGenerator.NewLong(), Id = _idGenerator.NewLong(),
OrderNo = await _orderNoGeneratorService.GenerateRefundOrderNoAsync(), OrderNo = await _orderNoGeneratorService.GenerateRefundOrderNoAsync(),
OrderType = 2, OrderType = 2,
MerchantId = order.MerchantId, MerchantId = originalOrder.MerchantId,
MerchantCertificationId = order.MerchantCertificationId, MerchantCertificationId = originalOrder.MerchantCertificationId,
EventId = order.EventId, EventId = originalOrder.EventId,
RegistrationId = order.RegistrationId, RegistrationId = originalOrder.RegistrationId,
RelatedOrderId = order.Id, RelatedOrderId = originalOrder.Id,
OriginalAmount = order.ActualAmount, OriginalAmount = originalOrder.ActualAmount,
ActualAmount = actualRefundAmount, ActualAmount = actualRefundAmount,
DiscountAmount = 0, DiscountAmount = 0,
// 实退 0 记为"已取消",与真实退款区分,避免对账时把 0 元单误读为已退款 OrderStatus = OrderStatus.Refunded,
OrderStatus = actualRefundAmount > 0 ? OrderStatus.Refunded : OrderStatus.Cancelled,
PaymentTime = now, PaymentTime = now,
Remark = input.CancelReason, Remark = input.CancelReason,
CreatedTime = now, CreatedTime = now,
@ -3880,13 +3858,9 @@ public class UnifiedRegistrationService : ITransient
refundOrderNo = newRefundOrder.OrderNo; refundOrderNo = newRefundOrder.OrderNo;
output.RefundNo = newRefundOrder.OrderNo; output.RefundNo = newRefundOrder.OrderNo;
_logger.LogInformation("退款订单创建成功:报名ID={RegistrationId}, 原订单号={OriginalOrderNo}, 退款订单号={RefundOrderNo}, 退款金额={Amount}, 订单状态={OrderStatus}", _logger.LogInformation("退款订单创建成功:报名ID={RegistrationId}, 原订单号={OriginalOrderNo}, 退款订单号={RefundOrderNo}, 退款金额={Amount}",
registration.Id, order.OrderNo, newRefundOrder.OrderNo, actualRefundAmount, newRefundOrder.OrderStatus); registration.Id, originalOrder.OrderNo, newRefundOrder.OrderNo, actualRefundAmount);
} }
else if (registration.TotalAmount > 0)
{
_logger.LogWarning("未找到原订单,无法创建退款订单:报名ID={RegistrationId}, 订单号={OrderNo}",
registration.Id, registration.OrderNo);
} }
if (registration.PaymentMethod == 1) if (registration.PaymentMethod == 1)
@ -4046,10 +4020,8 @@ public class UnifiedRegistrationService : ITransient
} }
} }
// 第二步:执行实际打款并创建退款流水记录 // 第二步:创建退款记录和执行微信退款(如果是线上支付)
// 退款单据在第一步已经落库(含实退 0 的留痕单),这里只负责真正的资金动作: if (!string.IsNullOrEmpty(refundOrderNo))
// actualRefundAmount == 0 时不得调用微信退款接口(金额 0 会被微信拒绝),也无需退款流水。
if (!string.IsNullOrEmpty(refundOrderNo) && actualRefundAmount > 0)
{ {
if (registration.PaymentMethod == 1) if (registration.PaymentMethod == 1)
{ {
@ -4057,11 +4029,14 @@ public class UnifiedRegistrationService : ITransient
_logger.LogInformation("线下支付创建退款记录:报名ID={RegistrationId}, 退款订单号={RefundOrderNo}, 退款金额={RefundAmount}", _logger.LogInformation("线下支付创建退款记录:报名ID={RegistrationId}, 退款订单号={RefundOrderNo}, 退款金额={RefundAmount}",
registration.Id, refundOrderNo, actualRefundAmount); registration.Id, refundOrderNo, actualRefundAmount);
if (registration.TotalAmount > 0 && !string.IsNullOrEmpty(registration.OrderNo) && actualRefundAmount > 0)
{
// 创建线下支付退款记录 // 创建线下支付退款记录
await CreateRefundRecordAsync(registration, eventInfo, null, refundOrderNo, await CreateRefundRecordAsync(registration, eventInfo, null, refundOrderNo,
null, actualRefundAmount, actualPaidAmount, input.CancelReason, operatorUserId, null, actualRefundAmount, actualPaidAmount, input.CancelReason, operatorUserId,
input.PayeeName, input.PayeeBankName, input.PayeeBankAccount); input.PayeeName, input.PayeeBankName, input.PayeeBankAccount);
} }
}
else else
{ {
// 线上支付:执行微信退款 // 线上支付:执行微信退款
@ -4104,12 +4079,6 @@ public class UnifiedRegistrationService : ITransient
} }
} }
} }
else if (!string.IsNullOrEmpty(refundOrderNo))
{
// 实退为 0(优惠券全额抵扣、或按规则本次不退款):只保留退款单据留痕,不动资金
_logger.LogInformation("退款金额为0,仅生成退款单据不调用支付渠道:报名ID={RegistrationId}, 退款订单号={RefundOrderNo}, 实付={ActualPaidAmount}",
registration.Id, refundOrderNo, actualPaidAmount);
}
// 不修改原订单状态,只创建退款订单记录 // 不修改原订单状态,只创建退款订单记录
// if (!isPartialCancel || registration.PaymentStatus == 3 || registration.PaymentStatus == 4) // if (!isPartialCancel || registration.PaymentStatus == 3 || registration.PaymentStatus == 4)