赛事报名费用归总
This commit is contained in:
parent
c86070f138
commit
cf39aba63e
@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using YD_Event.Application.Client.Dtos;
|
using YD_Event.Application.Client.Dtos;
|
||||||
using YD_Event.Core.Entities;
|
using YD_Event.Core.Entities;
|
||||||
using YD_Event.Core.Enum;
|
using YD_Event.Core.Enum;
|
||||||
|
using YD_Event.Core.Domain.Pricing;
|
||||||
using YD_Event.Core.Infrastructure.WeChat;
|
using YD_Event.Core.Infrastructure.WeChat;
|
||||||
using YD_Event.Core.Infrastructure.WeChat.Dto;
|
using YD_Event.Core.Infrastructure.WeChat.Dto;
|
||||||
using YD_Event.Core.Options;
|
using YD_Event.Core.Options;
|
||||||
|
|||||||
@ -656,6 +656,12 @@ public class UserSubmitRegistrationInput
|
|||||||
/// 优惠券ID (可选)
|
/// 优惠券ID (可选)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long? CouponId { get; set; }
|
public long? CouponId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 团队ID (必填)
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public long TeamId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 参赛记录相关 DTOs
|
#region 参赛记录相关 DTOs
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using YD_Event.Application.Event.Dtos;
|
|||||||
using YD_Event.Application.Project;
|
using YD_Event.Application.Project;
|
||||||
using YD_Event.Core.Entities;
|
using YD_Event.Core.Entities;
|
||||||
using YD_Event.Core.Enum;
|
using YD_Event.Core.Enum;
|
||||||
|
using YD_Event.Core.Domain.Pricing;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using YD_Event.Application.Auth;
|
using YD_Event.Application.Auth;
|
||||||
@ -446,7 +447,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
// 验证2:一次报名只能选择单个团队内的运动员
|
// 验证2:一次报名只能选择单个团队内的运动员
|
||||||
if (input.MemberIds != null && input.MemberIds.Count > 0)
|
if (input.MemberIds != null && input.MemberIds.Count > 0)
|
||||||
{
|
{
|
||||||
// 获取所有队员的团队ID
|
// 获取所有队员的团队关系
|
||||||
var teamMembers = await _db.Queryable<TeamMember>()
|
var teamMembers = await _db.Queryable<TeamMember>()
|
||||||
.Where(tm => input.MemberIds.Contains(tm.UserId))
|
.Where(tm => input.MemberIds.Contains(tm.UserId))
|
||||||
.Where(tm => !tm.DeleteMark)
|
.Where(tm => !tm.DeleteMark)
|
||||||
@ -457,11 +458,23 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
throw Oops.Bah("未找到队员信息");
|
throw Oops.Bah("未找到队员信息");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查所有队员是否属于同一个团队
|
// 按用户ID分组,获取每个用户所属的所有团队
|
||||||
var teamIds = teamMembers.Select(tm => tm.TeamId).Distinct().ToList();
|
var userTeamMap = teamMembers
|
||||||
if (teamIds.Count > 1)
|
.GroupBy(tm => tm.UserId)
|
||||||
|
.ToDictionary(g => g.Key, g => g.Select(tm => tm.TeamId).ToList());
|
||||||
|
|
||||||
|
// 检查是否所有用户都有团队信息
|
||||||
|
var missingUsers = input.MemberIds.Except(userTeamMap.Keys).ToList();
|
||||||
|
if (missingUsers.Any())
|
||||||
{
|
{
|
||||||
throw Oops.Bah("一次报名只能选择单个团队内的运动员");
|
throw Oops.Bah("部分队员未找到团队信息");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证所有队员是否都属于指定的 TeamId
|
||||||
|
var allBelongToTeam = userTeamMap.All(ut => ut.Value.Contains(input.TeamId));
|
||||||
|
if (!allBelongToTeam)
|
||||||
|
{
|
||||||
|
throw Oops.Bah("所有选择的运动员必须隶属于同一个团队");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +529,6 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
var baseProjectGroupIds = eventProjectGroups.Select(x => x.ProjectGroupId).Distinct().ToList();
|
var baseProjectGroupIds = eventProjectGroups.Select(x => x.ProjectGroupId).Distinct().ToList();
|
||||||
var baseProjectGroups = await _projectGroupRepository.GetListAsync(x => baseProjectGroupIds.Contains(x.Id));
|
var baseProjectGroups = await _projectGroupRepository.GetListAsync(x => baseProjectGroupIds.Contains(x.Id));
|
||||||
|
|
||||||
decimal totalAmount = 0;
|
|
||||||
int totalPersonCount = 0;
|
int totalPersonCount = 0;
|
||||||
FeeCalculationResult? feeCalculationResult = null;
|
FeeCalculationResult? feeCalculationResult = null;
|
||||||
|
|
||||||
@ -554,7 +566,6 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
};
|
};
|
||||||
await _registrationItemRepository.InsertAsync(item);
|
await _registrationItemRepository.InsertAsync(item);
|
||||||
|
|
||||||
totalAmount += item.TotalPrice;
|
|
||||||
totalPersonCount += item.PersonCount;
|
totalPersonCount += item.PersonCount;
|
||||||
|
|
||||||
foreach (var member in groupMembers)
|
foreach (var member in groupMembers)
|
||||||
@ -603,7 +614,6 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
};
|
};
|
||||||
await _registrationItemRepository.InsertAsync(item);
|
await _registrationItemRepository.InsertAsync(item);
|
||||||
|
|
||||||
totalAmount += item.TotalPrice;
|
|
||||||
totalPersonCount += item.PersonCount;
|
totalPersonCount += item.PersonCount;
|
||||||
|
|
||||||
foreach (var member in members)
|
foreach (var member in members)
|
||||||
@ -640,10 +650,9 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
ParticipantCount = totalPersonCount
|
ParticipantCount = totalPersonCount
|
||||||
};
|
};
|
||||||
feeCalculationResult = await CalculateFeeAsync(feeInput);
|
feeCalculationResult = await CalculateFeeAsync(feeInput);
|
||||||
totalAmount = feeCalculationResult.TotalAmount;
|
registration.TotalAmount = feeCalculationResult.TotalAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
registration.TotalAmount = totalAmount;
|
|
||||||
registration.TotalPersonCount = totalPersonCount;
|
registration.TotalPersonCount = totalPersonCount;
|
||||||
await _registrationRepository.UpdateAsync(registration);
|
await _registrationRepository.UpdateAsync(registration);
|
||||||
|
|
||||||
@ -1354,154 +1363,71 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
_logger.LogInformation("开始计算费用,赛事ID: {EventId}, 项目数: {ProjectCount}, 人数: {ParticipantCount}",
|
_logger.LogInformation("开始计算费用,赛事ID: {EventId}, 项目数: {ProjectCount}, 人数: {ParticipantCount}",
|
||||||
input.EventId, input.EventProjectIds.Count, input.ParticipantCount);
|
input.EventId, input.EventProjectIds.Count, input.ParticipantCount);
|
||||||
|
|
||||||
var result = new FeeCalculationResult
|
|
||||||
{
|
|
||||||
TotalPersonCount = input.ParticipantCount
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取赛事费用配置
|
// 获取赛事费用配置
|
||||||
var feeConfig = await _feeConfigRepository.GetFirstAsync(x => x.EventId == input.EventId);
|
var feeConfig = await _feeConfigRepository.GetFirstAsync(x => x.EventId == input.EventId);
|
||||||
if (feeConfig == null)
|
if (feeConfig == null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("未找到赛事费用配置,赛事ID: {EventId}", input.EventId);
|
_logger.LogWarning("未找到赛事费用配置,赛事ID: {EventId}", input.EventId);
|
||||||
result.ChargeMode = "免费";
|
var freeResult = new FeeCalculationResult
|
||||||
result.TotalAmount = 0;
|
{
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 未找到费用配置,默认免费");
|
ChargeMode = "免费",
|
||||||
return result;
|
TotalAmount = 0,
|
||||||
|
TotalPersonCount = input.ParticipantCount
|
||||||
|
};
|
||||||
|
freeResult.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 未找到费用配置,默认免费");
|
||||||
|
return freeResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.ChargeMode = GetChargeModeDescription(feeConfig.ChargeMode);
|
// 获取项目信息(用于单价项目模式)
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 收费模式: {result.ChargeMode}");
|
|
||||||
|
|
||||||
// 获取项目信息
|
|
||||||
var eventProjects = await _eventProjectRepository.GetListAsync(x => input.EventProjectIds.Contains(x.Id));
|
var eventProjects = await _eventProjectRepository.GetListAsync(x => input.EventProjectIds.Contains(x.Id));
|
||||||
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
|
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
|
||||||
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
|
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
|
||||||
|
|
||||||
switch (feeConfig.ChargeMode)
|
// 构建统一计算服务的输入参数
|
||||||
|
var pricingInput = new EventPricingService.PricingInput
|
||||||
{
|
{
|
||||||
case ChargeMode.Free:
|
ChargeMode = feeConfig.ChargeMode,
|
||||||
result = CalculateFreeMode(result, feeConfig);
|
ParticipantCount = input.ParticipantCount
|
||||||
break;
|
};
|
||||||
case ChargeMode.FixedPrice:
|
|
||||||
result = CalculateFixedPriceMode(result, feeConfig, input.ParticipantCount);
|
|
||||||
break;
|
|
||||||
case ChargeMode.UnitPriceEvent:
|
|
||||||
result = CalculateUnitPriceEventMode(result, feeConfig, input.ParticipantCount);
|
|
||||||
break;
|
|
||||||
case ChargeMode.UnitPriceProject:
|
|
||||||
result = await CalculateUnitPriceProjectMode(result, feeConfig, eventProjects, baseProjects, input.ParticipantCount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保金额精确到分
|
|
||||||
result.TotalAmount = Math.Round(result.TotalAmount, 2, MidpointRounding.AwayFromZero);
|
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 最终总金额: {result.TotalAmount:F2} 元");
|
|
||||||
|
|
||||||
_logger.LogInformation("费用计算完成,总金额: {TotalAmount:F2} 元", result.TotalAmount);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 免费模式
|
|
||||||
/// </summary>
|
|
||||||
private FeeCalculationResult CalculateFreeMode(FeeCalculationResult result, EventFeeConfig feeConfig)
|
|
||||||
{
|
|
||||||
result.TotalAmount = 0;
|
|
||||||
result.FeeDetails.Add(new FeeDetailItem
|
|
||||||
{
|
|
||||||
ItemName = "报名费",
|
|
||||||
UnitPrice = 0,
|
|
||||||
Quantity = 1,
|
|
||||||
Subtotal = 0,
|
|
||||||
Remark = "免费"
|
|
||||||
});
|
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 免费模式,总金额: 0 元");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 定价(赛事)模式:无论个人或单位报名,无论参加多少项目,统一按照固定价格计算
|
|
||||||
/// </summary>
|
|
||||||
private FeeCalculationResult CalculateFixedPriceMode(FeeCalculationResult result, EventFeeConfig feeConfig, int participantCount)
|
|
||||||
{
|
|
||||||
var price = feeConfig.Price / 100m;
|
|
||||||
result.TotalAmount = price;
|
|
||||||
result.FeeDetails.Add(new FeeDetailItem
|
|
||||||
{
|
|
||||||
ItemName = "赛事报名费",
|
|
||||||
UnitPrice = price,
|
|
||||||
Quantity = 1,
|
|
||||||
Subtotal = price,
|
|
||||||
Remark = $"固定价格,参赛人数: {participantCount} 人"
|
|
||||||
});
|
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 定价模式: 固定价格 {price:F2} 元");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单价(赛事)模式:按照单价乘以实际参赛人数计算
|
|
||||||
/// </summary>
|
|
||||||
private FeeCalculationResult CalculateUnitPriceEventMode(FeeCalculationResult result, EventFeeConfig feeConfig, int participantCount)
|
|
||||||
{
|
|
||||||
var unitPrice = feeConfig.Price / 100m;
|
|
||||||
var totalAmount = unitPrice * participantCount;
|
|
||||||
result.TotalAmount = totalAmount;
|
|
||||||
result.FeeDetails.Add(new FeeDetailItem
|
|
||||||
{
|
|
||||||
ItemName = "赛事报名费",
|
|
||||||
UnitPrice = unitPrice,
|
|
||||||
Quantity = participantCount,
|
|
||||||
Subtotal = totalAmount,
|
|
||||||
Remark = $"单价 × 人数 = {unitPrice:F2} × {participantCount}"
|
|
||||||
});
|
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 单价(赛事)模式: {unitPrice:F2} 元/人 × {participantCount} 人 = {totalAmount:F2} 元");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单价(项目)模式:按照各项目单价总和乘以实际参赛人数计算
|
|
||||||
/// </summary>
|
|
||||||
private async Task<FeeCalculationResult> CalculateUnitPriceProjectMode(
|
|
||||||
FeeCalculationResult result,
|
|
||||||
EventFeeConfig feeConfig,
|
|
||||||
List<EventProject> eventProjects,
|
|
||||||
List<YD_Event.Core.Entities.Project> baseProjects,
|
|
||||||
int participantCount)
|
|
||||||
{
|
|
||||||
decimal totalProjectPrice = 0;
|
|
||||||
|
|
||||||
|
// 添加项目信息
|
||||||
foreach (var eventProject in eventProjects)
|
foreach (var eventProject in eventProjects)
|
||||||
{
|
{
|
||||||
var baseProject = baseProjects.FirstOrDefault(p => p.Id == eventProject.ProjectId);
|
var baseProject = baseProjects.FirstOrDefault(p => p.Id == eventProject.ProjectId);
|
||||||
var projectPrice = eventProject.Price / 100m;
|
pricingInput.Projects.Add(new EventPricingService.ProjectPricingInfo
|
||||||
totalProjectPrice += projectPrice;
|
|
||||||
|
|
||||||
result.FeeDetails.Add(new FeeDetailItem
|
|
||||||
{
|
{
|
||||||
ItemName = baseProject?.Name ?? "未知项目",
|
ProjectId = eventProject.ProjectId,
|
||||||
UnitPrice = projectPrice,
|
ProjectName = baseProject?.Name ?? "未知项目",
|
||||||
Quantity = 1,
|
UnitPrice = eventProject.Price / 100m
|
||||||
Subtotal = projectPrice,
|
|
||||||
Remark = "项目单价"
|
|
||||||
});
|
});
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 项目: {baseProject?.Name ?? "未知"}, 单价: {projectPrice:F2} 元");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalAmount = totalProjectPrice * participantCount;
|
// 使用统一计算服务计算费用
|
||||||
result.TotalAmount = totalAmount;
|
var pricingResult = EventPricingService.Calculate(pricingInput);
|
||||||
|
|
||||||
// 添加汇总项
|
// 转换为现有格式的结果
|
||||||
result.FeeDetails.Add(new FeeDetailItem
|
var result = new FeeCalculationResult
|
||||||
{
|
{
|
||||||
ItemName = "项目总价 × 人数",
|
ChargeMode = GetChargeModeDescription(feeConfig.ChargeMode),
|
||||||
UnitPrice = totalProjectPrice,
|
TotalAmount = pricingResult.TotalAmount,
|
||||||
Quantity = participantCount,
|
TotalPersonCount = pricingResult.TotalPersonCount,
|
||||||
Subtotal = totalAmount,
|
CalculationLogs = pricingResult.CalculationLogs
|
||||||
Remark = $"({totalProjectPrice:F2} 元/套) × {participantCount} 人"
|
};
|
||||||
});
|
|
||||||
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 单价(项目)模式: 项目总价 {totalProjectPrice:F2} 元 × {participantCount} 人 = {totalAmount:F2} 元");
|
|
||||||
|
|
||||||
|
// 转换费用明细
|
||||||
|
foreach (var detail in pricingResult.Details)
|
||||||
|
{
|
||||||
|
result.FeeDetails.Add(new FeeDetailItem
|
||||||
|
{
|
||||||
|
ItemName = detail.ItemName,
|
||||||
|
UnitPrice = detail.UnitPrice,
|
||||||
|
Quantity = detail.Quantity,
|
||||||
|
Subtotal = detail.Subtotal,
|
||||||
|
Remark = detail.Remark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("费用计算完成,总金额: {TotalAmount:F2} 元", result.TotalAmount);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1520,13 +1446,4 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 费用计算预览API
|
|
||||||
/// </summary>
|
|
||||||
[DisplayName("费用计算预览")]
|
|
||||||
[HttpPost("fee/preview")]
|
|
||||||
public async Task<FeeCalculationResult> PreviewFee([FromBody] FeeCalculationInput input)
|
|
||||||
{
|
|
||||||
return await CalculateFeeAsync(input);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5596,6 +5596,11 @@
|
|||||||
优惠券ID (可选)
|
优惠券ID (可选)
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:YD_Event.Application.Event.Dtos.UserSubmitRegistrationInput.TeamId">
|
||||||
|
<summary>
|
||||||
|
团队ID (必填)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:YD_Event.Application.Event.Dtos.RegistrationListQueryInput">
|
<member name="T:YD_Event.Application.Event.Dtos.RegistrationListQueryInput">
|
||||||
<summary>
|
<summary>
|
||||||
参赛记录查询输入
|
参赛记录查询输入
|
||||||
@ -6460,36 +6465,11 @@
|
|||||||
<param name="input">费用计算输入</param>
|
<param name="input">费用计算输入</param>
|
||||||
<returns>费用计算结果</returns>
|
<returns>费用计算结果</returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.CalculateFreeMode(YD_Event.Application.Event.Dtos.FeeCalculationResult,YD_Event.Core.Entities.EventFeeConfig)">
|
|
||||||
<summary>
|
|
||||||
免费模式
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.CalculateFixedPriceMode(YD_Event.Application.Event.Dtos.FeeCalculationResult,YD_Event.Core.Entities.EventFeeConfig,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
定价(赛事)模式:无论个人或单位报名,无论参加多少项目,统一按照固定价格计算
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.CalculateUnitPriceEventMode(YD_Event.Application.Event.Dtos.FeeCalculationResult,YD_Event.Core.Entities.EventFeeConfig,System.Int32)">
|
|
||||||
<summary>
|
|
||||||
单价(赛事)模式:按照单价乘以实际参赛人数计算
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.CalculateUnitPriceProjectMode(YD_Event.Application.Event.Dtos.FeeCalculationResult,YD_Event.Core.Entities.EventFeeConfig,System.Collections.Generic.List{YD_Event.Core.Entities.EventProject},System.Collections.Generic.List{YD_Event.Core.Entities.Project},System.Int32)">
|
|
||||||
<summary>
|
|
||||||
单价(项目)模式:按照各项目单价总和乘以实际参赛人数计算
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.GetChargeModeDescription(YD_Event.Core.Enum.ChargeMode)">
|
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.GetChargeModeDescription(YD_Event.Core.Enum.ChargeMode)">
|
||||||
<summary>
|
<summary>
|
||||||
获取收费模式描述
|
获取收费模式描述
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:YD_Event.Application.Event.UserEventRegistrationService.PreviewFee(YD_Event.Application.Event.Dtos.FeeCalculationInput)">
|
|
||||||
<summary>
|
|
||||||
费用计算预览API
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:YD_Event.Application.File.Dtos.UploadFileOutput">
|
<member name="T:YD_Event.Application.File.Dtos.UploadFileOutput">
|
||||||
<summary>
|
<summary>
|
||||||
文件上传输出参数
|
文件上传输出参数
|
||||||
|
|||||||
255
YD_Event.Core/Domain/Pricing/EventPricingService.cs
Normal file
255
YD_Event.Core/Domain/Pricing/EventPricingService.cs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
using YD_Event.Core.Enum;
|
||||||
|
|
||||||
|
namespace YD_Event.Core.Domain.Pricing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 赛事定价计算服务
|
||||||
|
/// 所有金额计算均以此服务为准,确保计算结果的一致性
|
||||||
|
/// </summary>
|
||||||
|
public static class EventPricingService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 赛事基础定价(元)
|
||||||
|
/// </summary>
|
||||||
|
public const decimal EventBasePrice = 1000m;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目A定价(元)
|
||||||
|
/// </summary>
|
||||||
|
public const decimal ProjectAPrice = 500m;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目B定价(元)
|
||||||
|
/// </summary>
|
||||||
|
public const decimal ProjectBPrice = 1000m;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定价计算输入参数
|
||||||
|
/// </summary>
|
||||||
|
public class PricingInput
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 收费模式
|
||||||
|
/// </summary>
|
||||||
|
public ChargeMode ChargeMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参赛人数
|
||||||
|
/// </summary>
|
||||||
|
public int ParticipantCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目列表(单价项目模式使用)
|
||||||
|
/// </summary>
|
||||||
|
public List<ProjectPricingInfo> Projects { get; set; } = new List<ProjectPricingInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目定价信息
|
||||||
|
/// </summary>
|
||||||
|
public class ProjectPricingInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 项目ID
|
||||||
|
/// </summary>
|
||||||
|
public long ProjectId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目名称
|
||||||
|
/// </summary>
|
||||||
|
public string ProjectName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目单价(元)
|
||||||
|
/// </summary>
|
||||||
|
public decimal UnitPrice { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定价计算结果
|
||||||
|
/// </summary>
|
||||||
|
public class PricingResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 总金额(精确到分)
|
||||||
|
/// </summary>
|
||||||
|
public decimal TotalAmount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总人数
|
||||||
|
/// </summary>
|
||||||
|
public int TotalPersonCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 费用明细
|
||||||
|
/// </summary>
|
||||||
|
public List<PricingDetailItem> Details { get; set; } = new List<PricingDetailItem>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算日志(用于审计)
|
||||||
|
/// </summary>
|
||||||
|
public List<string> CalculationLogs { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 费用明细项
|
||||||
|
/// </summary>
|
||||||
|
public class PricingDetailItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 项目名称
|
||||||
|
/// </summary>
|
||||||
|
public string ItemName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单价
|
||||||
|
/// </summary>
|
||||||
|
public decimal UnitPrice { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数量
|
||||||
|
/// </summary>
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 小计
|
||||||
|
/// </summary>
|
||||||
|
public decimal Subtotal { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 备注
|
||||||
|
/// </summary>
|
||||||
|
public string? Remark { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算赛事报名费用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">定价计算输入</param>
|
||||||
|
/// <returns>定价计算结果</returns>
|
||||||
|
public static PricingResult Calculate(PricingInput input)
|
||||||
|
{
|
||||||
|
var result = new PricingResult
|
||||||
|
{
|
||||||
|
TotalPersonCount = input.ParticipantCount
|
||||||
|
};
|
||||||
|
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 开始计算费用,收费模式: {input.ChargeMode}, 人数: {input.ParticipantCount}");
|
||||||
|
|
||||||
|
switch (input.ChargeMode)
|
||||||
|
{
|
||||||
|
case ChargeMode.Free:
|
||||||
|
CalculateFreeMode(result);
|
||||||
|
break;
|
||||||
|
case ChargeMode.FixedPrice:
|
||||||
|
CalculateFixedPriceMode(result, input.ParticipantCount);
|
||||||
|
break;
|
||||||
|
case ChargeMode.UnitPriceEvent:
|
||||||
|
CalculateUnitPriceEventMode(result, input.ParticipantCount);
|
||||||
|
break;
|
||||||
|
case ChargeMode.UnitPriceProject:
|
||||||
|
CalculateUnitPriceProjectMode(result, input.Projects, input.ParticipantCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保金额精确到分
|
||||||
|
result.TotalAmount = Math.Round(result.TotalAmount, 2, MidpointRounding.AwayFromZero);
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 最终总金额: {result.TotalAmount:F2} 元");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 免费模式
|
||||||
|
/// </summary>
|
||||||
|
private static void CalculateFreeMode(PricingResult result)
|
||||||
|
{
|
||||||
|
result.TotalAmount = 0;
|
||||||
|
result.Details.Add(new PricingDetailItem
|
||||||
|
{
|
||||||
|
ItemName = "报名费",
|
||||||
|
UnitPrice = 0,
|
||||||
|
Quantity = 1,
|
||||||
|
Subtotal = 0,
|
||||||
|
Remark = "免费"
|
||||||
|
});
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 免费模式,总金额: 0 元");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定价(赛事)模式:固定为1000元/场,无论参赛主体是个人还是单位,也无论参赛项目数量多少,均统一按1000元计算
|
||||||
|
/// </summary>
|
||||||
|
private static void CalculateFixedPriceMode(PricingResult result, int participantCount)
|
||||||
|
{
|
||||||
|
var price = EventBasePrice;
|
||||||
|
result.TotalAmount = price;
|
||||||
|
result.Details.Add(new PricingDetailItem
|
||||||
|
{
|
||||||
|
ItemName = "赛事报名费",
|
||||||
|
UnitPrice = price,
|
||||||
|
Quantity = 1,
|
||||||
|
Subtotal = price,
|
||||||
|
Remark = $"固定价格 {EventBasePrice:F2} 元/场,参赛人数: {participantCount} 人"
|
||||||
|
});
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 定价(赛事)模式: 固定价格 {EventBasePrice:F2} 元/场");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单价(赛事)模式:赛事基础定价为1000元,个人参赛按1000元计算;团队参赛按人数乘以1000元计算
|
||||||
|
/// </summary>
|
||||||
|
private static void CalculateUnitPriceEventMode(PricingResult result, int participantCount)
|
||||||
|
{
|
||||||
|
var unitPrice = EventBasePrice;
|
||||||
|
var totalAmount = unitPrice * participantCount;
|
||||||
|
result.TotalAmount = totalAmount;
|
||||||
|
result.Details.Add(new PricingDetailItem
|
||||||
|
{
|
||||||
|
ItemName = "赛事报名费",
|
||||||
|
UnitPrice = unitPrice,
|
||||||
|
Quantity = participantCount,
|
||||||
|
Subtotal = totalAmount,
|
||||||
|
Remark = participantCount == 1
|
||||||
|
? $"个人参赛 {unitPrice:F2} 元"
|
||||||
|
: $"团队参赛 {unitPrice:F2} 元/人 × {participantCount} 人"
|
||||||
|
});
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 单价(赛事)模式: {unitPrice:F2} 元/人 × {participantCount} 人 = {totalAmount:F2} 元");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单价(项目)模式:按具体项目定价计算,个人参加多项时,费用为各项单价之和;团队参加多项时,费用为(各项单价之和)×团队人数
|
||||||
|
/// </summary>
|
||||||
|
private static void CalculateUnitPriceProjectMode(PricingResult result, List<ProjectPricingInfo> projects, int participantCount)
|
||||||
|
{
|
||||||
|
decimal totalProjectPrice = 0;
|
||||||
|
|
||||||
|
foreach (var project in projects)
|
||||||
|
{
|
||||||
|
totalProjectPrice += project.UnitPrice;
|
||||||
|
result.Details.Add(new PricingDetailItem
|
||||||
|
{
|
||||||
|
ItemName = project.ProjectName,
|
||||||
|
UnitPrice = project.UnitPrice,
|
||||||
|
Quantity = 1,
|
||||||
|
Subtotal = project.UnitPrice,
|
||||||
|
Remark = "项目单价"
|
||||||
|
});
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 项目: {project.ProjectName}, 单价: {project.UnitPrice:F2} 元");
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalAmount = totalProjectPrice * participantCount;
|
||||||
|
result.TotalAmount = totalAmount;
|
||||||
|
|
||||||
|
// 添加汇总项
|
||||||
|
result.Details.Add(new PricingDetailItem
|
||||||
|
{
|
||||||
|
ItemName = participantCount == 1 ? "项目总价" : "项目总价 × 人数",
|
||||||
|
UnitPrice = totalProjectPrice,
|
||||||
|
Quantity = participantCount,
|
||||||
|
Subtotal = totalAmount,
|
||||||
|
Remark = participantCount == 1
|
||||||
|
? $"个人参赛,项目总价 {totalProjectPrice:F2} 元"
|
||||||
|
: $"团队参赛,({totalProjectPrice:F2} 元) × {participantCount} 人"
|
||||||
|
});
|
||||||
|
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 单价(项目)模式: 项目总价 {totalProjectPrice:F2} 元 × {participantCount} 人 = {totalAmount:F2} 元");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -488,6 +488,149 @@
|
|||||||
执行导出
|
执行导出
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:YD_Event.Core.Domain.Pricing.EventPricingService">
|
||||||
|
<summary>
|
||||||
|
赛事定价计算服务
|
||||||
|
所有金额计算均以此服务为准,确保计算结果的一致性
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:YD_Event.Core.Domain.Pricing.EventPricingService.EventBasePrice">
|
||||||
|
<summary>
|
||||||
|
赛事基础定价(元)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:YD_Event.Core.Domain.Pricing.EventPricingService.ProjectAPrice">
|
||||||
|
<summary>
|
||||||
|
项目A定价(元)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:YD_Event.Core.Domain.Pricing.EventPricingService.ProjectBPrice">
|
||||||
|
<summary>
|
||||||
|
项目B定价(元)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:YD_Event.Core.Domain.Pricing.EventPricingService.PricingInput">
|
||||||
|
<summary>
|
||||||
|
定价计算输入参数
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingInput.ChargeMode">
|
||||||
|
<summary>
|
||||||
|
收费模式
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingInput.ParticipantCount">
|
||||||
|
<summary>
|
||||||
|
参赛人数
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingInput.Projects">
|
||||||
|
<summary>
|
||||||
|
项目列表(单价项目模式使用)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:YD_Event.Core.Domain.Pricing.EventPricingService.ProjectPricingInfo">
|
||||||
|
<summary>
|
||||||
|
项目定价信息
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.ProjectPricingInfo.ProjectId">
|
||||||
|
<summary>
|
||||||
|
项目ID
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.ProjectPricingInfo.ProjectName">
|
||||||
|
<summary>
|
||||||
|
项目名称
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.ProjectPricingInfo.UnitPrice">
|
||||||
|
<summary>
|
||||||
|
项目单价(元)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult">
|
||||||
|
<summary>
|
||||||
|
定价计算结果
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult.TotalAmount">
|
||||||
|
<summary>
|
||||||
|
总金额(精确到分)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult.TotalPersonCount">
|
||||||
|
<summary>
|
||||||
|
总人数
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult.Details">
|
||||||
|
<summary>
|
||||||
|
费用明细
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult.CalculationLogs">
|
||||||
|
<summary>
|
||||||
|
计算日志(用于审计)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:YD_Event.Core.Domain.Pricing.EventPricingService.PricingDetailItem">
|
||||||
|
<summary>
|
||||||
|
费用明细项
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingDetailItem.ItemName">
|
||||||
|
<summary>
|
||||||
|
项目名称
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingDetailItem.UnitPrice">
|
||||||
|
<summary>
|
||||||
|
单价
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingDetailItem.Quantity">
|
||||||
|
<summary>
|
||||||
|
数量
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingDetailItem.Subtotal">
|
||||||
|
<summary>
|
||||||
|
小计
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Core.Domain.Pricing.EventPricingService.PricingDetailItem.Remark">
|
||||||
|
<summary>
|
||||||
|
备注
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Domain.Pricing.EventPricingService.Calculate(YD_Event.Core.Domain.Pricing.EventPricingService.PricingInput)">
|
||||||
|
<summary>
|
||||||
|
计算赛事报名费用
|
||||||
|
</summary>
|
||||||
|
<param name="input">定价计算输入</param>
|
||||||
|
<returns>定价计算结果</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Domain.Pricing.EventPricingService.CalculateFreeMode(YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult)">
|
||||||
|
<summary>
|
||||||
|
免费模式
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Domain.Pricing.EventPricingService.CalculateFixedPriceMode(YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult,System.Int32)">
|
||||||
|
<summary>
|
||||||
|
定价(赛事)模式:固定为1000元/场,无论参赛主体是个人还是单位,也无论参赛项目数量多少,均统一按1000元计算
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Domain.Pricing.EventPricingService.CalculateUnitPriceEventMode(YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult,System.Int32)">
|
||||||
|
<summary>
|
||||||
|
单价(赛事)模式:赛事基础定价为1000元,个人参赛按1000元计算;团队参赛按人数乘以1000元计算
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:YD_Event.Core.Domain.Pricing.EventPricingService.CalculateUnitPriceProjectMode(YD_Event.Core.Domain.Pricing.EventPricingService.PricingResult,System.Collections.Generic.List{YD_Event.Core.Domain.Pricing.EventPricingService.ProjectPricingInfo},System.Int32)">
|
||||||
|
<summary>
|
||||||
|
单价(项目)模式:按具体项目定价计算,个人参加多项时,费用为各项单价之和;团队参加多项时,费用为(各项单价之和)×团队人数
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:YD_Event.Core.Entities.Entity`1">
|
<member name="T:YD_Event.Core.Entities.Entity`1">
|
||||||
<summary>
|
<summary>
|
||||||
表实体继承
|
表实体继承
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user