优惠劵使用流程变更

This commit is contained in:
马梓彭 2026-05-18 00:19:45 +08:00
parent da2f865a5e
commit 1a62270421
4 changed files with 150 additions and 25 deletions

View File

@ -651,6 +651,11 @@ public class ValidateCouponOutput
/// </summary>
public long? CouponId { get; set; }
/// <summary>
/// 用户优惠券ID
/// </summary>
public long? UserCouponId { get; set; }
/// <summary>
/// 优惠券名称
/// </summary>

View File

@ -1265,6 +1265,58 @@ public class UnifiedRegistrationService : ITransient
};
}
// 如果订单使用了优惠券,标记为已使用
if (!string.IsNullOrEmpty(registration.OrderNo))
{
var order = await _orderRepository.GetFirstAsync(o => o.OrderNo == registration.OrderNo && !o.DeleteMark);
if (order != null && order.CouponId.HasValue)
{
var userCoupon = await _userCouponRepository.GetFirstAsync(uc =>
uc.CouponId == order.CouponId.Value &&
uc.UserId == registration.CreatedUserId &&
uc.Status == 0 &&
!uc.DeleteMark);
if (userCoupon != null)
{
userCoupon.Status = 1;
userCoupon.UseTime = DateTime.Now;
userCoupon.OrderId = order.Id;
userCoupon.UpdatedTime = DateTime.Now;
userCoupon.UpdatedUserId = operatorUserId;
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 = DateTime.Now;
redemptionCode.UpdatedTime = DateTime.Now;
redemptionCode.UpdatedUserId = operatorUserId;
await _redemptionCodeRepository.UpdateAsync(redemptionCode);
}
}
// 更新优惠券的已使用数量
var coupon = await _couponRepository.GetFirstAsync(c => c.Id == order.CouponId.Value && !c.DeleteMark);
if (coupon != null)
{
coupon.UsedQuantity++;
coupon.UpdatedTime = DateTime.Now;
coupon.UpdatedUserId = operatorUserId;
await _couponRepository.UpdateAsync(coupon);
}
}
}
}
// 更新报名记录状态为待审核 - 正式创建报名记录
registration.PaymentProofUrl = input.PaymentProofUrl ?? registration.PaymentProofUrl;
registration.PaymentStatus = 0; // 待审核 - 正式报名记录
@ -2346,13 +2398,36 @@ public class UnifiedRegistrationService : ITransient
userCoupon.Status = 1;
userCoupon.UseTime = successTime ?? DateTime.Now;
userCoupon.OrderId = order.Id;
userCoupon.UpdatedTime = DateTime.Now;
userCoupon.UpdatedUserId = operatorUserId;
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 = DateTime.Now;
redemptionCode.UpdatedTime = DateTime.Now;
redemptionCode.UpdatedUserId = operatorUserId;
await _redemptionCodeRepository.UpdateAsync(redemptionCode);
_logger.LogInformation($"兑换码已标记为已使用,兑换码ID={redemptionCode.Id}");
}
}
// 更新优惠券的已使用数量
var coupon = await _couponRepository.GetByIdAsync(order.CouponId.Value);
if (coupon != null)
{
coupon.UsedQuantity++;
coupon.UpdatedTime = DateTime.Now;
coupon.UpdatedUserId = operatorUserId;
await _couponRepository.UpdateAsync(coupon);
}
@ -2365,6 +2440,7 @@ public class UnifiedRegistrationService : ITransient
/// <summary>
/// 取消报名
/// </summary>
[UnitOfWork]
public async Task<bool> CancelRegistrationAsync(long registrationId, long operatorUserId)
{
var reg = await _registrationRepository.GetFirstAsync(r => r.Id == registrationId && r.CreatedUserId == operatorUserId);
@ -2566,14 +2642,14 @@ public class UnifiedRegistrationService : ITransient
// 如果用户没有该优惠券,检查是否可以直接领取(假设可以直接通过兑换码领取)
if (userCoupon == null)
{
// 创建用户优惠券记录
// 创建用户优惠券记录,但不立即标记为已使用
userCoupon = new YD_Event.Core.Entities.UserCoupon
{
Id = _idGenerator.NewLong(),
UserId = userId,
CouponId = coupon.Id,
ClaimTime = DateTime.Now,
Status = 0,
Status = 0, // 保持未使用状态
RedemptionCodeId = redemptionCode.Id,
RedemptionCode = redemptionCode.Code,
CreatedUserId = userId,
@ -2582,15 +2658,7 @@ public class UnifiedRegistrationService : ITransient
};
await _userCouponRepository.InsertAsync(userCoupon);
// 更新兑换码状态和关联
redemptionCode.Status = 1;
redemptionCode.UsedTime = DateTime.Now;
redemptionCode.UserCouponId = userCoupon.Id;
await _redemptionCodeRepository.UpdateAsync(redemptionCode);
// 更新优惠券已领取数量
coupon.ClaimedQuantity += 1;
await _couponRepository.UpdateAsync(coupon);
// 注意:不立即更新兑换码状态,也不增加已领取数量,等支付完成后再做
}
// 计算优惠金额
@ -2598,6 +2666,7 @@ public class UnifiedRegistrationService : ITransient
result.IsValid = true;
result.CouponId = coupon.Id;
result.UserCouponId = userCoupon.Id;
result.CouponName = coupon.Name ?? "优惠券";
result.DiscountType = coupon.Type;
result.DiscountValue = coupon.Value;
@ -4209,6 +4278,61 @@ public class UnifiedRegistrationService : ITransient
await SoftDeleteItemsAsync(items.Select(i => i.Id).ToList(), operatorUserId, now, refundOrder.Id);
}
_logger.LogInformation("开始执行优惠券和兑换码回滚:报名ID={RegistrationId}, 订单号={OrderNo}",
registrationId, registration.OrderNo);
if (order.CouponId.HasValue)
{
var userCoupon = await _userCouponRepository.GetFirstAsync(uc =>
uc.CouponId == order.CouponId.Value &&
uc.OrderId == order.Id &&
uc.Status == 1 &&
!uc.DeleteMark);
if (userCoupon != null)
{
// 回滚用户优惠券状态
userCoupon.Status = 0;
userCoupon.UseTime = null;
userCoupon.OrderId = null;
userCoupon.UpdatedTime = now;
userCoupon.UpdatedUserId = operatorUserId;
await _userCouponRepository.UpdateAsync(userCoupon);
_logger.LogInformation("用户优惠券回滚成功:用户优惠券ID={UserCouponId}", userCoupon.Id);
// 如果有兑换码,回滚兑换码
if (userCoupon.RedemptionCodeId.HasValue)
{
var redemptionCode = await _redemptionCodeRepository.GetFirstAsync(rc =>
rc.Id == userCoupon.RedemptionCodeId.Value &&
rc.Status == 1 &&
!rc.DeleteMark);
if (redemptionCode != null)
{
redemptionCode.Status = 0;
redemptionCode.UsedTime = null;
redemptionCode.UpdatedTime = now;
redemptionCode.UpdatedUserId = operatorUserId;
await _redemptionCodeRepository.UpdateAsync(redemptionCode);
_logger.LogInformation("兑换码回滚成功:兑换码ID={RedemptionCodeId}", redemptionCode.Id);
}
}
// 更新优惠券的已使用数量
var coupon = await _couponRepository.GetFirstAsync(c => c.Id == order.CouponId.Value && !c.DeleteMark);
if (coupon != null)
{
coupon.UsedQuantity = Math.Max(0, coupon.UsedQuantity - 1);
coupon.UpdatedTime = now;
coupon.UpdatedUserId = operatorUserId;
await _couponRepository.UpdateAsync(coupon);
_logger.LogInformation("优惠券已使用数量更新成功:优惠券ID={CouponId}, 原使用数量={OldUsed}, 新使用数量={NewUsed}",
coupon.Id, coupon.UsedQuantity + 1, coupon.UsedQuantity);
}
}
}
_logger.LogInformation("报名失败退款处理成功,报名ID={RegistrationId}, 退款金额={Amount}, 退款单号={RefundNo}",
registrationId, order.ActualAmount, refundOrderNo);

View File

@ -966,20 +966,11 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
if (queryResult.Success && queryResult.TradeState == "SUCCESS")
{
orderInfo.Order.OrderStatus = OrderStatus.Paid;
orderInfo.Order.PaymentTime = queryResult.SuccessTime?.DateTime;
if (queryResult.PayerAmount.HasValue)
{
orderInfo.Order.ActualAmount = queryResult.PayerAmount.Value / 100m;
}
await _orderRepository.UpdateAsync(orderInfo.Order);
var registration = await _registrationRepository.GetByIdAsync(orderInfo.Order.RegistrationId);
if (registration != null && registration.PaymentStatus != 1)
{
registration.PaymentStatus = 1;
await _registrationRepository.UpdateAsync(registration);
}
await _unifiedRegistrationService.HandlePaymentSuccessAsync(
orderNo,
queryResult.TransactionId,
queryResult.SuccessTime?.DateTime,
orderInfo.Order.CreatedUserId);
_logger.LogInformation("查询订单支付状态 - 订单已更新为已支付,订单号:{OrderNo}", orderNo);
return 1;
}

View File

@ -7923,6 +7923,11 @@
优惠券ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ValidateCouponOutput.UserCouponId">
<summary>
用户优惠券ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ValidateCouponOutput.CouponName">
<summary>
优惠券名称