YD_Event.Admin/YD_Event.Core/Domain/Pricing/EventPricingService.cs
2026-04-09 15:16:43 +08:00

247 lines
8.1 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 class PricingInput
{
/// <summary>
/// 收费模式
/// </summary>
public ChargeMode ChargeMode { get; set; }
/// <summary>
/// 参赛人数
/// </summary>
public int ParticipantCount { get; set; }
/// <summary>
/// 赛事定价(用于定价(赛事)和单价(赛事)模式)
/// </summary>
public decimal EventPrice { 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);
break;
case ChargeMode.UnitPriceEvent:
CalculateUnitPriceEventMode(result, input);
break;
case ChargeMode.UnitPriceProject:
CalculateUnitPriceProjectMode(result, input);
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>
/// 定价(赛事)模式:固定为赛事设定价格/场,无论参赛主体是个人还是单位,也无论参赛项目数量多少,均统一按固定价格计算
/// </summary>
private static void CalculateFixedPriceMode(PricingResult result, PricingInput input)
{
var price = input.EventPrice;
result.TotalAmount = price;
result.Details.Add(new PricingDetailItem
{
ItemName = "赛事报名费",
UnitPrice = price,
Quantity = 1,
Subtotal = price,
Remark = $"固定价格 {price:F2} 元/场,参赛人数: {input.ParticipantCount} 人"
});
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 定价(赛事)模式: 固定价格 {price:F2} 元/场");
}
/// <summary>
/// 单价(赛事)模式:按照赛事设定的单价乘以实际报名人数计算总金额
/// </summary>
private static void CalculateUnitPriceEventMode(PricingResult result, PricingInput input)
{
var unitPrice = input.EventPrice;
var totalAmount = unitPrice * input.ParticipantCount;
result.TotalAmount = totalAmount;
result.Details.Add(new PricingDetailItem
{
ItemName = "赛事报名费",
UnitPrice = unitPrice,
Quantity = input.ParticipantCount,
Subtotal = totalAmount,
Remark = input.ParticipantCount == 1
? $"个人参赛 {unitPrice:F2} 元"
: $"团队参赛 {unitPrice:F2} 元/人 × {input.ParticipantCount} 人"
});
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 单价(赛事)模式: {unitPrice:F2} 元/人 × {input.ParticipantCount} 人 = {totalAmount:F2} 元");
}
/// <summary>
/// 单价(项目)模式:根据每个项目的单独定价和报名人数进行计算。
/// 将每个报名项目的单价相加得到单人总费用,再乘以报名人数得出最终金额
/// </summary>
private static void CalculateUnitPriceProjectMode(PricingResult result, PricingInput input)
{
decimal totalProjectPrice = 0;
foreach (var project in input.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 * input.ParticipantCount;
result.TotalAmount = totalAmount;
// 添加汇总项
result.Details.Add(new PricingDetailItem
{
ItemName = input.ParticipantCount == 1 ? "项目总价" : "项目总价 × 人数",
UnitPrice = totalProjectPrice,
Quantity = input.ParticipantCount,
Subtotal = totalAmount,
Remark = input.ParticipantCount == 1
? $"个人参赛,项目总价 {totalProjectPrice:F2} 元"
: $"团队参赛,({totalProjectPrice:F2} 元) × {input.ParticipantCount} 人"
});
result.CalculationLogs.Add($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 单价(项目)模式: 项目总价 {totalProjectPrice:F2} 元 × {input.ParticipantCount} 人 = {totalAmount:F2} 元");
}
}