/
KDP
/
SuprTimeLogAutomation
Обзор
Документация
Войти
/
KDP
/
SuprTimeLogAutomation
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Services/TimeDistributionService.cs
82 строки
4 KB
Timshin Mikhail
first commit
24 июн 2026, 14:52
24 июн 2026, 14:52
61ceede
Код
Авторство
О чём код?
using SuprTimeLogAutomation.Helpers; using SuprTimeLogAutomation.Models; namespace SuprTimeLogAutomation.Services; public static class TimeDistributionService { public static List<TaskDistribution> PrepareDistributions(List<TimeLogEntry> entries) { var distributions = new List<TaskDistribution>(); decimal[] dayTotals = new decimal[5]; // Накопитель по дням: Пн-Пт const decimal maxPerDay = 8m; const int decimalPlaces = 1; // Точность 1С: 1 знак после запятой // Собираем все задачи в один плоский список с привязкой к группе var allTasks = entries .SelectMany(e => e.Details, (e, d) => new { e.Group, d.Id, d.Name, d.Hours }) .ToList(); foreach (var task in allTasks) { var dist = new TaskDistribution { ProjectCode = ProjectMapper.GetProjectValue(task.Group), TaskId = task.Id, TaskName = task.Name }; decimal remaining = (decimal)task.Hours; var rawHours = new decimal[5]; // Значения ДО округления // 1. Распределяем часы по дням (без округления) for (int day = 0; day < 5 && remaining > 0; day++) { decimal spaceLeft = maxPerDay - dayTotals[day]; if (spaceLeft <= 0) continue; decimal toAdd = Math.Min(remaining, spaceLeft); rawHours[day] = toAdd; dayTotals[day] += toAdd; remaining -= toAdd; } // 2. Округляем все значения до 1 знака var roundedHours = new decimal[5]; decimal roundedSum = 0; for (int day = 0; day < 5; day++) { roundedHours[day] = Math.Round(rawHours[day], decimalPlaces, MidpointRounding.AwayFromZero); roundedSum += roundedHours[day]; } // 3. 🔥 Компенсируем разницу округления (с точностью 0.1) decimal targetSum = Math.Round((decimal)task.Hours, decimalPlaces, MidpointRounding.AwayFromZero); decimal difference = targetSum - roundedSum; // Может быть -0.1, 0, +0.1 и т.д. if (Math.Abs(difference) >= 0.05m) // Если разница >= половины шага округления { // Находим день, где можно скорректировать (не 0 и не 8.0 после округления) for (int day = 4; day >= 0; day--) // Идем с конца { if (roundedHours[day] > 0 && roundedHours[day] < maxPerDay) { // Применяем коррекцию с округлением до 1 знака decimal newValue = Math.Round(roundedHours[day] + difference, decimalPlaces, MidpointRounding.AwayFromZero); // Clamp to [0, 8] с учётом точности newValue = Math.Max(0, Math.Min(maxPerDay, newValue)); roundedHours[day] = Math.Round(newValue, decimalPlaces, MidpointRounding.AwayFromZero); break; } } } // 4. Сохраняем итоговые значения dist.DayHours = roundedHours; distributions.Add(dist); } return distributions; } }