using Jiaowu.Api.Domain.Academic; namespace Jiaowu.Api.Infrastructure.Grades; public static class GradeCalculator { public static bool AreWeightsValid( decimal regularWeight, decimal finalWeight, IEnumerable items) => regularWeight is >= 0 and <= 100 && finalWeight is >= 0 and <= 100 && items.All(item => item.Weight is >= 0 and <= 100) && regularWeight + finalWeight + items.Sum(item => item.Weight) == 100; public static decimal? CalculateTotal( decimal? regularScore, decimal? finalScore, IReadOnlyCollection itemScores, decimal regularWeight, decimal finalWeight, IReadOnlyCollection items, GradeExamStatus examStatus) { if (examStatus != GradeExamStatus.Normal && examStatus != GradeExamStatus.Makeup) return null; if (regularWeight > 0 && !regularScore.HasValue) return null; if (finalWeight > 0 && !finalScore.HasValue) return null; var itemWeightById = items.ToDictionary(item => item.Id, item => item.Weight); foreach (var itemScore in itemScores) { if (itemWeightById.TryGetValue(itemScore.GradeItemId, out var weight) && weight > 0 && !itemScore.Score.HasValue) return null; } var total = (regularScore ?? 0) * regularWeight / 100; foreach (var itemScore in itemScores) { if (itemWeightById.TryGetValue(itemScore.GradeItemId, out var weight)) total += (itemScore.Score ?? 0) * weight / 100; } total += (finalScore ?? 0) * finalWeight / 100; return Math.Round(total, 1, MidpointRounding.AwayFromZero); } public static decimal? CalculateGradePoint(decimal? totalScore) { if (!totalScore.HasValue) return null; return totalScore.Value switch { >= 90 => 4.0m, >= 85 => 3.7m, >= 82 => 3.3m, >= 78 => 3.0m, >= 75 => 2.7m, >= 72 => 2.3m, >= 68 => 2.0m, >= 64 => 1.5m, >= 60 => 1.0m, _ => 0m }; } }