重复报名
This commit is contained in:
parent
12562f962c
commit
e03ad5eb46
@ -923,13 +923,13 @@ public class EventClientController : IDynamicApiController
|
|||||||
else if (now >= reg.MatchStart && now <= reg.MatchEnd) status = EventStatus.Ongoing;
|
else if (now >= reg.MatchStart && now <= reg.MatchEnd) status = EventStatus.Ongoing;
|
||||||
else if (now > reg.MatchEnd) status = EventStatus.Ended;
|
else if (now > reg.MatchEnd) status = EventStatus.Ended;
|
||||||
|
|
||||||
// 获取 Items 和 Persons
|
// 获取 Items 和 Persons - 只获取未被软删除的
|
||||||
var items = await _registrationItemRepository.AsQueryable()
|
var items = await _registrationItemRepository.AsQueryable()
|
||||||
.Where(i => i.RegistrationId == registrationId)
|
.Where(i => i.RegistrationId == registrationId && !i.DeleteMark)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
var persons = await _personRepository.AsQueryable()
|
var persons = await _personRepository.AsQueryable()
|
||||||
.Where(p => p.RegistrationId == registrationId)
|
.Where(p => p.RegistrationId == registrationId && !p.DeleteMark)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
// 计算退款金额和获取退款规则
|
// 计算退款金额和获取退款规则
|
||||||
|
|||||||
@ -184,9 +184,35 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
registration.UpdatedTime = DateTime.Now;
|
registration.UpdatedTime = DateTime.Now;
|
||||||
registration.UpdatedUserId = input.CreatedUserId;
|
registration.UpdatedUserId = input.CreatedUserId;
|
||||||
|
|
||||||
// 删除旧的明细和人员
|
// 软删除旧的明细和人员(保留历史记录,与取消报名逻辑一致)
|
||||||
await _registrationItemRepository.DeleteAsync(x => x.RegistrationId == registration.Id);
|
var oldItems = await _registrationItemRepository.GetListAsync(x => x.RegistrationId == registration.Id && !x.DeleteMark);
|
||||||
await _registrationPersonRepository.DeleteAsync(x => x.RegistrationId == registration.Id);
|
var oldPersons = await _registrationPersonRepository.GetListAsync(x => x.RegistrationId == registration.Id && !x.DeleteMark);
|
||||||
|
|
||||||
|
var now = DateTime.Now;
|
||||||
|
|
||||||
|
if (oldItems.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in oldItems)
|
||||||
|
{
|
||||||
|
item.DeleteMark = true;
|
||||||
|
item.UpdatedUserId = input.CreatedUserId;
|
||||||
|
item.UpdatedTime = now;
|
||||||
|
}
|
||||||
|
await _registrationItemRepository.UpdateRangeAsync(oldItems);
|
||||||
|
_logger.LogInformation("重新报名,软删除旧项目:报名ID={RegistrationId}, 项目数={Count}", registration.Id, oldItems.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldPersons.Any())
|
||||||
|
{
|
||||||
|
foreach (var person in oldPersons)
|
||||||
|
{
|
||||||
|
person.DeleteMark = true;
|
||||||
|
person.UpdatedUserId = input.CreatedUserId;
|
||||||
|
person.UpdatedTime = now;
|
||||||
|
}
|
||||||
|
await _registrationPersonRepository.UpdateRangeAsync(oldPersons);
|
||||||
|
_logger.LogInformation("重新报名,软删除旧人员:报名ID={RegistrationId}, 人数={Count}", registration.Id, oldPersons.Count);
|
||||||
|
}
|
||||||
|
|
||||||
return registration;
|
return registration;
|
||||||
}
|
}
|
||||||
@ -2792,13 +2818,17 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
projects = projectList.ToDictionary(x => x.Id);
|
projects = projectList.ToDictionary(x => x.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询订单获取实际支付金额(考虑优惠券抵扣)
|
||||||
|
var order = await _orderRepository.GetFirstAsync(x => x.RegistrationId == registrationId && x.OrderType == 1 && !x.DeleteMark);
|
||||||
|
var actualPaidAmount = order?.ActualAmount ?? registration.TotalAmount;
|
||||||
|
|
||||||
var output = new CancelPreviewOutput
|
var output = new CancelPreviewOutput
|
||||||
{
|
{
|
||||||
RegistrationId = registration.Id,
|
RegistrationId = registration.Id,
|
||||||
EventName = eventInfo?.EventName ?? "",
|
EventName = eventInfo?.EventName ?? "",
|
||||||
TeamName = registration.TeamName ?? "",
|
TeamName = registration.TeamName ?? "",
|
||||||
ChargeMode = (int)eventInfo.ChargeMode,
|
ChargeMode = (int)eventInfo.ChargeMode,
|
||||||
ActualPaidAmount = registration.TotalAmount,
|
ActualPaidAmount = actualPaidAmount,
|
||||||
RefundableAmount = refundableAmount,
|
RefundableAmount = refundableAmount,
|
||||||
RefundedAmount = refundedAmount,
|
RefundedAmount = refundedAmount,
|
||||||
CurrentRefundAmount = refundableAmount,
|
CurrentRefundAmount = refundableAmount,
|
||||||
@ -2807,7 +2837,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
NeedPayeeInfo = registration.PaymentMethod == 1 && registration.PaymentStatus == 1
|
NeedPayeeInfo = registration.PaymentMethod == 1 && registration.PaymentStatus == 1
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items.Where(x => !x.DeleteMark))
|
||||||
{
|
{
|
||||||
output.Projects.Add(new CancelPreviewProjectDto
|
output.Projects.Add(new CancelPreviewProjectDto
|
||||||
{
|
{
|
||||||
@ -2819,7 +2849,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var person in persons)
|
foreach (var person in persons.Where(x => !x.DeleteMark))
|
||||||
{
|
{
|
||||||
output.Members.Add(new CancelPreviewMemberDto
|
output.Members.Add(new CancelPreviewMemberDto
|
||||||
{
|
{
|
||||||
@ -2830,7 +2860,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建新版详细数据结构(按项目 -> 组别 -> 团队 -> 队员分类)
|
// 构建新版详细数据结构(按项目 -> 组别 -> 团队 -> 队员分类)
|
||||||
var itemGroups = items.GroupBy(x => x.ProjectId);
|
var itemGroups = items.Where(x => !x.DeleteMark).GroupBy(x => x.ProjectId);
|
||||||
foreach (var itemGroup in itemGroups)
|
foreach (var itemGroup in itemGroups)
|
||||||
{
|
{
|
||||||
var firstItem = itemGroup.First();
|
var firstItem = itemGroup.First();
|
||||||
@ -2879,8 +2909,8 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
int teamIndex = 0;
|
int teamIndex = 0;
|
||||||
foreach (var item in groupGroup)
|
foreach (var item in groupGroup)
|
||||||
{
|
{
|
||||||
// 获取该报名项目下的所有队员
|
// 获取该报名项目下的所有队员 - 只获取未被软删除的
|
||||||
var itemPersons = persons.Where(p => p.RegistrationItemId == item.Id).ToList();
|
var itemPersons = persons.Where(p => p.RegistrationItemId == item.Id && !p.DeleteMark).ToList();
|
||||||
|
|
||||||
// 每个报名项作为一个独立的团队条目
|
// 每个报名项作为一个独立的团队条目
|
||||||
var teamDto = new CancelPreviewTeamDto
|
var teamDto = new CancelPreviewTeamDto
|
||||||
@ -3025,12 +3055,16 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
remainingRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
remainingRefundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询订单获取实际支付金额(考虑优惠券抵扣)
|
||||||
|
var order = await _orderRepository.GetFirstAsync(x => x.RegistrationId == input.RegistrationId && x.OrderType == 1 && !x.DeleteMark);
|
||||||
|
var actualPaidAmount = order?.ActualAmount ?? registration.TotalAmount;
|
||||||
|
|
||||||
return new CalculateRefundAmountOutput
|
return new CalculateRefundAmountOutput
|
||||||
{
|
{
|
||||||
refundAmount = refundAmount,
|
refundAmount = refundAmount,
|
||||||
refundableAmount = remainingRefundableAmount,
|
refundableAmount = remainingRefundableAmount,
|
||||||
refundedAmount = refundedAmount,
|
refundedAmount = refundedAmount,
|
||||||
actualPaidAmount = registration.TotalAmount
|
actualPaidAmount = actualPaidAmount
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3328,9 +3362,20 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
// 计算实际退款金额
|
// 计算实际退款金额
|
||||||
// 【重要】始终信任后端计算结果,前端计算只用于展示
|
// 【重要】始终信任后端计算结果,前端计算只用于展示
|
||||||
// 不接受前端传递的退款金额,避免资金风险
|
// 不接受前端传递的退款金额,避免资金风险
|
||||||
decimal actualRefundAmount = await CalculateActualRefundAmountAsync(input, registration, eventInfo, items, persons);
|
var order = await _orderRepository.GetFirstAsync(o => o.RegistrationId == registration.Id && o.OrderType == 1 && !o.DeleteMark);
|
||||||
_logger.LogInformation("统一退款金额计算:报名ID={RegistrationId}, 总金额={TotalAmount}, 退款金额={ActualRefundAmount}",
|
var actualPaidAmount = order?.ActualAmount ?? registration.TotalAmount;
|
||||||
registration.Id, registration.TotalAmount, actualRefundAmount);
|
var originalAmount = registration.TotalAmount;
|
||||||
|
|
||||||
|
// 先计算按原价应该退多少
|
||||||
|
decimal originalRefundAmount = await CalculateActualRefundAmountAsync(input, registration, eventInfo, items, persons);
|
||||||
|
|
||||||
|
// 然后按比例计算实际退款金额(考虑优惠券折扣)
|
||||||
|
decimal actualRefundAmount = originalAmount > 0 ? originalRefundAmount * (actualPaidAmount / originalAmount) : 0;
|
||||||
|
// 确保退款金额不超过实际支付金额
|
||||||
|
actualRefundAmount = Math.Min(actualRefundAmount, actualPaidAmount);
|
||||||
|
|
||||||
|
_logger.LogInformation("统一退款金额计算:报名ID={RegistrationId}, 原价={OriginalAmount}, 实付={ActualPaidAmount}, 按原价应退={OriginalRefundAmount}, 实际退款={ActualRefundAmount}",
|
||||||
|
registration.Id, originalAmount, actualPaidAmount, originalRefundAmount, actualRefundAmount);
|
||||||
|
|
||||||
bool isPartialCancel = input.CancelType == 1;
|
bool isPartialCancel = input.CancelType == 1;
|
||||||
|
|
||||||
@ -3489,12 +3534,12 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
registration.PaymentStatus = 3;
|
registration.PaymentStatus = 4; // 已取消(与线下支付保持一致)
|
||||||
registration.UpdatedUserId = operatorUserId;
|
registration.UpdatedUserId = operatorUserId;
|
||||||
registration.UpdatedTime = now;
|
registration.UpdatedTime = now;
|
||||||
registration.RegistrationRemark = input.CancelReason;
|
registration.RegistrationRemark = input.CancelReason;
|
||||||
await _registrationRepository.UpdateAsync(registration);
|
await _registrationRepository.UpdateAsync(registration);
|
||||||
_logger.LogInformation("统一所有人员已退款,更新报名状态为已退款:报名ID={RegistrationId}", registration.Id);
|
_logger.LogInformation("统一所有人员已退款,更新报名状态为已取消:报名ID={RegistrationId}", registration.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3510,7 +3555,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
await SoftDeleteItemsAsync(items.Select(i => i.Id).ToList(), operatorUserId, now);
|
await SoftDeleteItemsAsync(items.Select(i => i.Id).ToList(), operatorUserId, now);
|
||||||
_logger.LogInformation("已软删除所有项目:报名ID={RegistrationId}", registration.Id);
|
_logger.LogInformation("已软删除所有项目:报名ID={RegistrationId}", registration.Id);
|
||||||
|
|
||||||
registration.PaymentStatus = 3;
|
registration.PaymentStatus = 4; // 已取消(与线下支付保持一致)
|
||||||
registration.UpdatedUserId = operatorUserId;
|
registration.UpdatedUserId = operatorUserId;
|
||||||
registration.UpdatedTime = now;
|
registration.UpdatedTime = now;
|
||||||
registration.RegistrationRemark = input.CancelReason;
|
registration.RegistrationRemark = input.CancelReason;
|
||||||
@ -3568,7 +3613,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
|
|
||||||
// 创建线下支付退款记录
|
// 创建线下支付退款记录
|
||||||
await CreateRefundRecordAsync(registration, eventInfo, null, refundOrder.OrderNo,
|
await CreateRefundRecordAsync(registration, eventInfo, null, refundOrder.OrderNo,
|
||||||
null, actualRefundAmount, registration.TotalAmount, input.CancelReason, operatorUserId,
|
null, actualRefundAmount, actualPaidAmount, input.CancelReason, operatorUserId,
|
||||||
input.PayeeName, input.PayeeBankName, input.PayeeBankAccount);
|
input.PayeeName, input.PayeeBankName, input.PayeeBankAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3624,7 +3669,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
OutTradeNo = registration.OrderNo,
|
OutTradeNo = registration.OrderNo,
|
||||||
OutRefundNo = outRefundNo,
|
OutRefundNo = outRefundNo,
|
||||||
RefundAmount = AmountHelper.YuanToFen(actualRefundAmount),
|
RefundAmount = AmountHelper.YuanToFen(actualRefundAmount),
|
||||||
TotalAmount = AmountHelper.YuanToFen(registration.TotalAmount),
|
TotalAmount = AmountHelper.YuanToFen(actualPaidAmount), // 使用实际支付金额作为总金额
|
||||||
Reason = input.CancelReason
|
Reason = input.CancelReason
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3642,7 +3687,7 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
}
|
}
|
||||||
|
|
||||||
await CreateRefundRecordAsync(registration, eventInfo, wechatConfig, outRefundNo,
|
await CreateRefundRecordAsync(registration, eventInfo, wechatConfig, outRefundNo,
|
||||||
refundResult.RefundId, actualRefundAmount, registration.TotalAmount, input.CancelReason, operatorUserId);
|
refundResult.RefundId, actualRefundAmount, actualPaidAmount, input.CancelReason, operatorUserId);
|
||||||
|
|
||||||
_logger.LogInformation("统一退款成功:报名ID={RegistrationId}, 退款单号={RefundNo}, 退款金额={Amount}",
|
_logger.LogInformation("统一退款成功:报名ID={RegistrationId}, 退款单号={RefundNo}, 退款金额={Amount}",
|
||||||
registration.Id, outRefundNo, actualRefundAmount);
|
registration.Id, outRefundNo, actualRefundAmount);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user