diff --git a/YD_Event.Application/Event/UnifiedRegistrationService.cs b/YD_Event.Application/Event/UnifiedRegistrationService.cs index cdc8fc2..306f28c 100644 --- a/YD_Event.Application/Event/UnifiedRegistrationService.cs +++ b/YD_Event.Application/Event/UnifiedRegistrationService.cs @@ -156,17 +156,11 @@ public class UnifiedRegistrationService : ITransient registration.TotalPersonCount = totalPersonCount; await _registrationRepository.UpdateAsync(registration); - // 5. 如果是免费赛事,直接完成支付(无优惠券,原价即0) + // 5. 如果是免费赛事,直接完成支付 if (totalAmount <= 0) { _logger.LogInformation("免费赛事,直接完成支付,报名ID: {RegistrationId}", registration.Id); - var eventInfo = await _eventRepository.GetByIdAsync(registration.EventId); - if (eventInfo == null) - { - throw Oops.Bah("赛事信息不存在"); - } - await HandleFreePaymentAsync(registration, eventInfo, totalAmount, 0, - null, null, null, input.CreatedUserId); + await HandleFreePaymentAsync(registration, null, input.CreatedUserId); } _logger.LogInformation("统一报名处理完成,报名ID: {RegistrationId}", registration.Id); @@ -292,28 +286,6 @@ public class UnifiedRegistrationService : ITransient throw Oops.Bah("赛事信息不存在"); } - // 2.1 幂等短路:已成交(含 0 元券全额抵扣)直接返回。 - // 关键:必须在重新计算金额之前短路。0 元成交时优惠券已被核销(Status=1), - // 若重入再走 CalculateFinalAmountAsync,会因查不到可用券而把 finalAmount 回退为原价, - // 从而落入付费分支:覆盖 PaymentStatus(1→0)、重复建单、重复调起微信支付 → 重复扣款/列表不显示。 - if (registration.PaymentStatus == 1) - { - _logger.LogInformation("报名已成交,幂等返回,报名ID: {RegistrationId}", registration.Id); - var paidOrder = await _orderRepository.GetFirstAsync(o => - o.RegistrationId == registration.Id && !o.DeleteMark); - var paidAmount = paidOrder?.ActualAmount ?? 0; - return new UnifiedPaymentOutput - { - RegistrationId = registration.Id, - OrderNo = registration.OrderNo, - OriginalAmount = paidOrder?.OriginalAmount ?? registration.TotalAmount, - DiscountAmount = paidOrder?.DiscountAmount ?? 0, - ActualAmount = paidAmount, - PaymentStatus = 1, - IsFree = paidAmount <= 0 - }; - } - // 3. 计算优惠后金额(每次都重新计算,确保金额正确) var calculateResult = await CalculateFinalAmountAsync( registration.TotalAmount, input.CouponId, input.OperatorUserId); @@ -336,15 +308,13 @@ public class UnifiedRegistrationService : ITransient CouponRuleNote = usedCoupon != null ? "优惠券使用后不予退还" : null }; - // 6. 处理免费情况(0 元券全额抵扣等):与付费成交对齐——生成订单+支付流水并完成核销,避免状态孤岛 + // 6. 处理免费情况 if (finalAmount <= 0) { if (registration.PaymentStatus != 1) { - await HandleFreePaymentAsync(registration, eventInfo, originalAmount, discountAmount, - input.CouponId, usedCoupon, usedUserCoupon, input.OperatorUserId); + await HandleFreePaymentAsync(registration, usedUserCoupon, input.OperatorUserId); } - output.OrderNo = registration.OrderNo; output.PaymentStatus = 1; return output; } @@ -984,98 +954,24 @@ public class UnifiedRegistrationService : ITransient } /// - /// 处理免费支付(0 元券全额抵扣 / 免费赛事成交) - /// 与线上支付回调 对齐: - /// 生成订单(已支付)+支付流水(金额0),并完整核销优惠券,避免“付了钱但查不到”的状态孤岛。 + /// 处理免费支付 /// - private async Task HandleFreePaymentAsync( - EventRegistration registration, EventInfo eventInfo, - decimal originalAmount, decimal discountAmount, - long? couponId, YD_Event.Core.Entities.Coupon? coupon, - YD_Event.Core.Entities.UserCoupon? userCoupon, long operatorUserId) + private async Task HandleFreePaymentAsync(EventRegistration registration, YD_Event.Core.Entities.UserCoupon? userCoupon, long operatorUserId) { - var now = DateTime.Now; - - // 1. 确保有订单号(预报名创建时 OrderNo 为空字符串) - if (string.IsNullOrEmpty(registration.OrderNo)) - { - registration.OrderNo = await _orderNoGeneratorService.GenerateOrderNoAsync(); - } - - // 2. 报名记录置为已支付(免费成交) - registration.PaymentStatus = 1; - registration.PaymentMethod = 2; // 免费赛事统一按线上支付方式,满足小程序列表放行条件 - registration.PaymentMethodType = PaymentMethodType.WeChatPay; - registration.PaymentTime = now; - registration.UpdatedTime = now; - registration.UpdatedUserId = operatorUserId; - await _registrationRepository.UpdateAsync(registration); - - // 3. 生成订单并标记为已支付(实付 0),消除状态孤岛 - var order = await CreateOrderAsync(registration, eventInfo, originalAmount, discountAmount, - 0, couponId, operatorUserId); - order.OrderStatus = OrderStatus.Paid; - order.PaymentTime = now; - order.UpdatedTime = now; - await _orderRepository.UpdateAsync(order); - - // 4. 写支付流水(金额 0),与微信回调路径保持一致 - var payment = new EventRegistrationPayment - { - Id = _idGenerator.NewLong(), - RegistrationId = registration.Id, - TransactionNo = "", - PaymentChannel = 1, - PaymentAmount = 0, - PaymentTime = now, - PaymentStatus = 1, - RefundStatus = 0, - PayeeAccount = "", - CreatedUserId = registration.CreatedUserId, - CreatedTime = now - }; - await _paymentRepository.InsertAsync(payment); - - // 5. 完整核销优惠券(补齐 OrderId / UsedQuantity / 兑换码,与银行转账、微信回调路径一致) if (userCoupon != null) { userCoupon.Status = 1; - userCoupon.UseTime = now; - userCoupon.OrderId = order.Id; - userCoupon.UpdatedTime = now; - userCoupon.UpdatedUserId = operatorUserId; + userCoupon.UseTime = DateTime.Now; await _userCouponRepository.UpdateAsync(userCoupon); - - // 兑换码标记已使用 - if (userCoupon.RedemptionCodeId.HasValue) - { - var redemptionCode = await _redemptionCodeRepository.GetFirstAsync(rc => - rc.Id == userCoupon.RedemptionCodeId.Value && rc.Status == 0 && !rc.DeleteMark); - if (redemptionCode != null) - { - redemptionCode.Status = 1; - redemptionCode.UsedTime = now; - redemptionCode.UpdatedTime = now; - redemptionCode.UpdatedUserId = operatorUserId; - await _redemptionCodeRepository.UpdateAsync(redemptionCode); - } - } - - // 优惠券已使用数量 +1 - var couponEntity = coupon ?? (couponId.HasValue - ? await _couponRepository.GetByIdAsync(couponId.Value) - : null); - if (couponEntity != null) - { - couponEntity.UsedQuantity++; - couponEntity.UpdatedTime = now; - couponEntity.UpdatedUserId = operatorUserId; - await _couponRepository.UpdateAsync(couponEntity); - } } - _logger.LogInformation("免费成交处理完成(0元/券全额抵扣),报名ID: {RegistrationId}, 订单号: {OrderNo}", - registration.Id, registration.OrderNo); + registration.PaymentStatus = 1; + registration.PaymentMethod = 2; // 免费赛事设置为线上支付方式 + registration.PaymentMethodType = PaymentMethodType.WeChatPay; // 默认微信支付 + registration.PaymentTime = DateTime.Now; + registration.UpdatedTime = DateTime.Now; + registration.UpdatedUserId = operatorUserId; + await _registrationRepository.UpdateAsync(registration); } ///