修复bug

This commit is contained in:
马梓彭 2026-04-29 09:33:33 +08:00
parent daf573b94d
commit 4bd2585680
5 changed files with 98 additions and 20 deletions

View File

@ -225,6 +225,11 @@ public class CancelPreviewOutput
/// </summary> /// </summary>
public decimal RefundableAmount { get; set; } public decimal RefundableAmount { get; set; }
/// <summary>
/// 历史已退款金额
/// </summary>
public decimal RefundedAmount { get; set; }
/// <summary> /// <summary>
/// 当前选择的退款金额(动态计算) /// 当前选择的退款金额(动态计算)
/// </summary> /// </summary>

View File

@ -319,29 +319,59 @@ namespace YD_Event.Application.Event;
// 计算项目总时长(在查询前计算,避免在SQL中使用C#方法) // 计算项目总时长(在查询前计算,避免在SQL中使用C#方法)
int projTotalDuration = proj.GetTotalDurationInSeconds(); int projTotalDuration = proj.GetTotalDurationInSeconds();
// 获取参赛人员,并关联用户和单位认证信息 // 第一步:先查询主要数据和相关的 MerchantCertificationId
var persons = await _personRepository.AsQueryable() var basicPersons = await _personRepository.AsQueryable()
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id) .InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
.LeftJoin<MerchantCertification>((p, r, m) => r.MerchantCertificationId == m.Id) .Where((p, r) => p.ProjectId == eventProj.Id
.Where((p, r, m) => p.ProjectId == eventProj.Id
&& r.PaymentStatus != 4 && r.PaymentStatus != 4
&& !p.DeleteMark && !p.DeleteMark
&& p.PersonType == PersonType.Athlete) && p.PersonType == PersonType.Athlete)
.OrderBy(p => p.GroupName) .OrderBy(p => p.GroupName)
.OrderBy(p => p.Id) .OrderBy(p => p.Id)
.Select((p, r, m) => new { .Select((p, r) => new {
Id = p.Id, // 添加 Id 属性 Id = p.Id,
RegistrationItemId = p.RegistrationItemId, RegistrationItemId = p.RegistrationItemId,
p.UserId, p.UserId,
p.Name, p.Name,
p.GroupName, p.GroupName,
r.TeamName, r.TeamName,
MerchantName = m.MerchantName ?? "", r.MerchantCertificationId,
m.AuditStatus,
Duration = projTotalDuration Duration = projTotalDuration
}) })
.ToListAsync(); .ToListAsync();
// 第二步:收集所有需要查询的 MerchantCertificationId
var merchantCertIds = basicPersons
.Where(x => x.MerchantCertificationId.HasValue)
.Select(x => x.MerchantCertificationId.Value)
.Distinct()
.ToList();
// 第三步:批量查询 MerchantCertification
Dictionary<long, MerchantCertification> merchantDict = new Dictionary<long, MerchantCertification>();
if (merchantCertIds.Any())
{
var merchants = await _merchantCertificationRepository.GetListAsync(x => merchantCertIds.Contains(x.Id));
merchantDict = merchants.ToDictionary(x => x.Id, x => x);
}
// 第四步:在内存中合并数据
var persons = basicPersons.Select(bp => new {
bp.Id,
bp.RegistrationItemId,
bp.UserId,
bp.Name,
bp.GroupName,
bp.TeamName,
MerchantName = bp.MerchantCertificationId.HasValue && merchantDict.ContainsKey(bp.MerchantCertificationId.Value)
? merchantDict[bp.MerchantCertificationId.Value].MerchantName
: null,
AuditStatus = bp.MerchantCertificationId.HasValue && merchantDict.ContainsKey(bp.MerchantCertificationId.Value)
? merchantDict[bp.MerchantCertificationId.Value].AuditStatus
: (AuditStatus?)null,
bp.Duration
}).ToList();
if (!persons.Any()) continue; if (!persons.Any()) continue;
// 计算项目总时长 // 计算项目总时长
@ -471,7 +501,14 @@ namespace YD_Event.Application.Event;
var teamNameProp = personData.GetType().GetProperty("TeamName"); var teamNameProp = personData.GetType().GetProperty("TeamName");
string? merchantName = merchantNameProp?.GetValue(personData) as string; string? merchantName = merchantNameProp?.GetValue(personData) as string;
AuditStatus? auditStatus = auditStatusProp?.GetValue(personData) as AuditStatus?; var auditStatusValue = auditStatusProp?.GetValue(personData);
AuditStatus? auditStatus = null;
if (auditStatusValue != null && auditStatusValue is AuditStatus status)
{
auditStatus = status;
}
string? teamName = teamNameProp?.GetValue(personData) as string; string? teamName = teamNameProp?.GetValue(personData) as string;
// 优先使用认证通过的单位名称 // 优先使用认证通过的单位名称

View File

@ -2468,10 +2468,21 @@ public class UnifiedRegistrationService : ITransient
var items = await _db.Queryable<EventRegistrationItem>().Where(x => x.RegistrationId == registrationId).ToListAsync(); var items = await _db.Queryable<EventRegistrationItem>().Where(x => x.RegistrationId == registrationId).ToListAsync();
var persons = await _registrationPersonRepository.GetListAsync(x => x.RegistrationId == registrationId); var persons = await _registrationPersonRepository.GetListAsync(x => x.RegistrationId == registrationId);
var refundableAmount = await CalculateRefundAmountAsync(registration.TotalAmount, eventInfo.MatchStartTime); // 查询历史已退款金额
var historyRefunds = await _refundRecordRepository.GetListAsync(x => x.RegistrationId == registrationId && x.RefundStatus == 1);
var refundedAmount = historyRefunds.Sum(x => x.RefundAmount);
// 计算剩余未退款的原始金额
var remainingOriginalAmount = registration.TotalAmount - refundedAmount;
// 基于剩余金额计算可退款金额
var refundableAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
// 确保可退款金额不小于0
refundableAmount = Math.Max(0, refundableAmount);
_logger.LogInformation("统一取消报名预览:报名ID={RegistrationId}, 赛事名称={EventName}, 实际支付={ActualAmount}, 可退款={RefundAmount}, 支付方式={PaymentMethod}", _logger.LogInformation("统一取消报名预览:报名ID={RegistrationId}, 赛事名称={EventName}, 实际支付={ActualAmount}, 已退款={RefundedAmount}, 剩余可退款={RefundAmount}, 支付方式={PaymentMethod}",
registrationId, eventInfo?.EventName, registration.TotalAmount, refundableAmount, registration.PaymentMethod); registrationId, eventInfo?.EventName, registration.TotalAmount, refundedAmount, refundableAmount, registration.PaymentMethod);
// 获取组别信息(年龄和性别限制) // 获取组别信息(年龄和性别限制)
var groupIds = items.Where(x => x.EventProjectGroupId.HasValue).Select(x => x.EventProjectGroupId.Value).Distinct().ToList(); var groupIds = items.Where(x => x.EventProjectGroupId.HasValue).Select(x => x.EventProjectGroupId.Value).Distinct().ToList();
@ -2501,6 +2512,7 @@ public class UnifiedRegistrationService : ITransient
ChargeMode = (int)eventInfo.ChargeMode, ChargeMode = (int)eventInfo.ChargeMode,
ActualPaidAmount = registration.TotalAmount, ActualPaidAmount = registration.TotalAmount,
RefundableAmount = refundableAmount, RefundableAmount = refundableAmount,
RefundedAmount = refundedAmount,
CurrentRefundAmount = refundableAmount, CurrentRefundAmount = refundableAmount,
PaymentMethod = registration.PaymentMethod, PaymentMethod = registration.PaymentMethod,
PaymentStatus = registration.PaymentStatus, PaymentStatus = registration.PaymentStatus,
@ -2669,15 +2681,28 @@ public class UnifiedRegistrationService : ITransient
return 0; return 0;
} }
// 查询历史已退款金额
var historyRefunds = await _refundRecordRepository.GetListAsync(x => x.RegistrationId == registration.Id && x.RefundStatus == 1);
var refundedAmount = historyRefunds.Sum(x => x.RefundAmount);
// 计算剩余的原始未退款金额
var remainingOriginalAmount = registration.TotalAmount - refundedAmount;
// 如果没有剩余可退,直接返回0
if (remainingOriginalAmount <= 0)
{
return 0;
}
// 全部取消 // 全部取消
if (input.CancelType == 0) if (input.CancelType == 0)
{ {
return await CalculateRefundAmountAsync(registration.TotalAmount, eventInfo.MatchStartTime); return await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
} }
// 部分取消 // 部分取消
var baseRefundAmount = await CalculateRefundAmountAsync(registration.TotalAmount, eventInfo.MatchStartTime); var baseRefundAmount = await CalculateRefundAmountAsync(remainingOriginalAmount, eventInfo.MatchStartTime);
var refundRatio = registration.TotalAmount > 0 ? baseRefundAmount / registration.TotalAmount : 1; var refundRatio = remainingOriginalAmount > 0 ? baseRefundAmount / remainingOriginalAmount : 1;
var cancelMemberIds = input.PersonIds ?? new List<long>(); var cancelMemberIds = input.PersonIds ?? new List<long>();
var cancelTeams = input.CancelTeams ?? new List<string>(); var cancelTeams = input.CancelTeams ?? new List<string>();
@ -2712,7 +2737,9 @@ public class UnifiedRegistrationService : ITransient
return baseRefundAmount; return baseRefundAmount;
} }
// 否则,按人数比例退款 // 否则,按人数比例退款
return baseRefundAmount * (decimal)cancelTeamMemberCount / persons.Count; var fixedPriceCalculated = baseRefundAmount * (decimal)cancelTeamMemberCount / persons.Count;
// 确保不超过剩余可退款金额
return Math.Min(fixedPriceCalculated, baseRefundAmount);
case ChargeMode.UnitPriceEvent: case ChargeMode.UnitPriceEvent:
// 单价(赛事):按取消人数计算 // 单价(赛事):按取消人数计算
@ -2732,8 +2759,10 @@ public class UnifiedRegistrationService : ITransient
} }
var cancelCount = allCancelMemberIds.Count; var cancelCount = allCancelMemberIds.Count;
var unitPrice = persons.Count > 0 ? registration.TotalAmount / persons.Count : 0; var unitPrice = persons.Count > 0 ? remainingOriginalAmount / persons.Count : 0;
return unitPrice * cancelCount * refundRatio; var calculatedAmount = unitPrice * cancelCount * refundRatio;
// 确保不超过剩余可退款金额
return Math.Min(calculatedAmount, baseRefundAmount);
case ChargeMode.UnitPriceProject: case ChargeMode.UnitPriceProject:
// 单价(项目):按每个项目的人数计算 // 单价(项目):按每个项目的人数计算
@ -2766,7 +2795,9 @@ public class UnifiedRegistrationService : ITransient
} }
} }
return totalCancelAmount * refundRatio; var projectCalculatedAmount = totalCancelAmount * refundRatio;
// 确保不超过剩余可退款金额
return Math.Min(projectCalculatedAmount, baseRefundAmount);
default: default:
return 0; return 0;

View File

@ -5034,6 +5034,11 @@
可退款金额(全部取消时) 可退款金额(全部取消时)
</summary> </summary>
</member> </member>
<member name="P:YD_Event.Application.Event.Dtos.CancelPreviewOutput.RefundedAmount">
<summary>
历史已退款金额
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.CancelPreviewOutput.CurrentRefundAmount"> <member name="P:YD_Event.Application.Event.Dtos.CancelPreviewOutput.CurrentRefundAmount">
<summary> <summary>
当前选择的退款金额(动态计算) 当前选择的退款金额(动态计算)

View File

@ -53,7 +53,7 @@
"SleepMs": 300, "SleepMs": 300,
"dbconfig": { "dbconfig": {
"ConnectionStrings": [ "ConnectionStrings": [
"8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=7,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false", "8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=7,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false"
//"8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=8,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false" //"8.153.108.90,Password=yd708090,SyncTimeout=15000,ConnectTimeout=15000,ResponseTimeout=15000,defaultDatabase=8,poolsize=100,ssl=false,writeBuffer=10240,idleTimeout=30000,connectRetry=3,asyncPipeline=false"
], ],
//"Sentinels": [ //"Sentinels": [