YD_Event.Admin/YD_Event.Core/Domain/Pricing/EventPricingService.cs

256 lines
8.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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} 元");
}
}