Files
parr_api/PARR.TemplateDistributor/TemplateDistributor.cs
Mikhail Kuznetsov a489ad4990 Merge branch 'dev' of http://gitlab.dvgd.oao.rzd/devptk/parr/parr_api into dev
# Conflicts:
#	PARR.TemplateDistributor/TemplateDistributor.cs
2024-07-05 15:21:06 +10:00

246 lines
13 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 Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.BLL.Services.Interfaces;
using PARR.Constants;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.TransformServices;
namespace PARR.TemplateDistributor
{
internal class TemplateDistributor : ITemplateDistributor
{
private readonly ILogger<TemplateDistributor> logger;
private readonly ITemplateService templateService;
private readonly IApplicationsInWorkService applicationsInWorkService;
private readonly IEsppSchTypeScheduleService esppSchTypeScheduleService;
private readonly ICalendarService calendarService;
private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly IWeekendDayService weekendDayService;
public TemplateDistributor(
ILogger<TemplateDistributor> logger,
ITemplateService templateService,
IApplicationsInWorkService applicationsInWorkService,
IEsppSchTypeScheduleService esppSchTypeScheduleService,
ICalendarService calendarService,
IEsppScheduleTransformService esppScheduleTransformService,
IWeekendDayService weekendDayService
)
{
this.logger = logger;
this.templateService = templateService;
this.applicationsInWorkService = applicationsInWorkService;
this.esppSchTypeScheduleService = esppSchTypeScheduleService;
this.calendarService = calendarService;
this.esppScheduleTransformService = esppScheduleTransformService;
this.weekendDayService = weekendDayService;
}
public async Task UpdateScheduleAsync(Guid applicationInWorkId)
{
// все шаблоны по applicationInWorkId
// группирует по РР
// -> DistributeTemplateForPeriodAsync
// сохранить в БД
//applicationInWorkId = Guid.Parse("bdfefd77-bce3-4f62-a484-5042c06f4467");
var appInWork = await applicationsInWorkService.Get()
.Include(aiw => aiw.EsppSchValues)
.ThenInclude(esv => esv.EsppSchTypeValue)
.ThenInclude(etv => etv!.DistributionPeriod)
.FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
var templates = await templateService.Get()
.Include(t => t.Host)
.ThenInclude(h => h.WorkGroup)
.Where(t => t.ApplicationInWorkId == applicationInWorkId)
.ToListAsync();
//var refDate = appInWork!.ReferenceDate;
//var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
//DistributionPeriodTypeEnum periodType = (DistributionPeriodTypeEnum)Enum.Parse(typeof(DistributionPeriodTypeEnum), period!.Type);
//var workGroupsWithTemplates = templates.GroupBy(t => new { t.Host!.WorkGroupId, t.NextRun});
var workGroupsWithTemplates = templates.GroupBy(t => t.Host!.WorkGroupId);
//var startPeriod = await esppScheduleTransformService.GetStartPeriodForDateAsync(applicationInWorkId, DateTimeOffset.UtcNow/*.AddDays(45)*/, refDate, periodType, period.Duration);
//var workdays = calendarService.GetWorkDatesForPeriod(startPeriod, periodType, period.Duration, weekendDayService.GetWeekends);
//var templatePerWorkDay = (int)Math.Ceiling((double)templates.Count() / workdays.Count());//
foreach (var item in workGroupsWithTemplates)
{
var wgId = item.Key ?? Guid.NewGuid();//TODO сделать правильно
var values = item.ToList();
var distrTemplates = await DistributeTemplateAsync(values, applicationInWorkId, wgId);
}
// saveChanges
if (!await applicationsInWorkService.CommitAsync())
logger.LogError($"Ошибка записи изменений в БД при перераспределении NextRun шаблонов");
}
public async Task<List<Template>> DistributeTemplateAsync(List<Template> templates, Guid applicationInWorkId, Guid workGroupid)
{
//TODO: ЗАГУЛШКА переделать!
// распределить?
// не распределить, NextRun = appInWork.ReferenceDate
var appInWork = await applicationsInWorkService.Get()
.Include(aiw => aiw.EsppSchValues)
.ThenInclude(esv => esv.EsppSchTypeValue)
.ThenInclude(etv => etv!.DistributionPeriod)
.FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
//appInWork!.IsAutoDistributionEnabled = true;//!!!!!!!!!!!!!!!!!!!КОСТЫЛЬ пока нет связки с фронтом
//Проверяем наличие распределения РР на период
if (appInWork!.IsAutoDistributionEnabled)
{
var existingTemplates = new List<Template>();
//Если распределенная РР получаем начало
//DateOnly startPeriod = await esppScheduleTransformService.GetStartPeriodForDateAsync(applicationInWorkId,DateTimeOffset.UtcNow);
var refDate = appInWork.ReferenceDate;
var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
//if(period != null) {
DistributionPeriodTypeEnum periodType = (DistributionPeriodTypeEnum)Enum.Parse(typeof(DistributionPeriodTypeEnum), period!.Type);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//periodType = DistributionPeriodTypeEnum.Day;
//period.Duration = "90";
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var startPeriod = await esppScheduleTransformService.GetStartPeriodForDateAsync(applicationInWorkId, DateTimeOffset.UtcNow/*.AddDays(45)*/, appInWork.ReferenceDate, periodType, period.Duration);
var workdays = calendarService.GetWorkDatesForPeriod(startPeriod, periodType, period.Duration, weekendDayService.GetWeekends);
var d = new Dictionary<DateOnly, int>();
foreach (var wd in workdays)
{
var wrokDateTimeOffset = new DateTimeOffset(
wd.Year, wd.Month, wd.Day,
refDate.Hour, refDate.Minute, refDate.Second,
new TimeSpan(0, 0, 0)); ;
var assignedTemplateCount = existingTemplates.Where(t => t.NextRun == wrokDateTimeOffset).Count();
d.Add(wd, assignedTemplateCount);
}
//templates = templates.Take(5).ToList();
//var templatesPerStep = (int)Math.Ceiling((double)templates.Count() / workdays.Count());//
var templatesPerStep = (double)templates.Count() / workdays.Count();//
//templatesPerStep = (templatesPerStep < 1) ? 1 : templatesPerStep;
var currentDay = new DateTimeOffset(
startPeriod.Year, startPeriod.Month, startPeriod.Day,
refDate.Hour, refDate.Minute, refDate.Second,
new TimeSpan(0, 0, 0)); ;
var balance = templates.Count();
var step = 0;
var stepDays = (int)Math.Floor((double)workdays.Count() / templates.Count());
stepDays = (stepDays < 1) ? 1 : stepDays;
var currentTemplateStep = (int)Math.Ceiling(templatesPerStep);
var delta = templatesPerStep - currentTemplateStep;
templates.First().NextRun = currentDay;
var templateDistributed = 0;
//Отталкиваясь от количества
while (templateDistributed < templates.Count())
{
var wdCounts = d.Select(wd => wd.Value).OrderBy(count => count).ToArray();
// = existingTemplates.Select(t => t.NextRun).OrderBy(nextRun => nextRun).Distinct().ToArray();//managers.Select(m => m.Orders.Count).OrderBy(count => count).Distinct().ToArray();
var templateCountDelta = d.Max(t => t.Value) - d.Max(t => t.Value);
var addingTemplatesCount = wdCounts.Length > 1 ?
(templateCountDelta == 0) ? (int)Math.Ceiling(templatesPerStep) : templateCountDelta :
(int)Math.Ceiling(templatesPerStep);
var workDaysWithMinTemplates = d.Where(wd => wd.Value == wdCounts[0]).ToArray();
if (workDaysWithMinTemplates.Length * addingTemplatesCount < templates.Count())
{
foreach (var wd in workDaysWithMinTemplates)
{
//Считаем DateTimeOffset, потому что у нас только дата пока
currentDay = new DateTimeOffset(
wd.Key.Year, wd.Key.Month, wd.Key.Day,
refDate.Hour, refDate.Minute, refDate.Second,
new TimeSpan(0, 0, 0));
if (currentDay < DateTimeOffset.UtcNow)
currentDay = esppScheduleTransformService.GetNextDateForDistributionRun(currentDay, periodType, period.Duration);
templates.Skip(templateDistributed).Take(addingTemplatesCount).ToList().ForEach(t => t.NextRun = currentDay);
templateDistributed += addingTemplatesCount;
d[wd.Key] = wd.Value + addingTemplatesCount;
}
}
else
{
while (templateDistributed < templates.Count())
{
//var wdIndex = templateDistributed % workDaysWithMinTemplates.Length;
//var wd = workDaysWithMinTemplates[wdIndex];
var wd = d.Where(wd => wd.Value == d.Min(t => t.Value)).First();
//Считаем DateTimeOffset, потому что у нас только дата пока
currentDay = new DateTimeOffset(
wd.Key.Year, wd.Key.Month, wd.Key.Day,
refDate.Hour, refDate.Minute, refDate.Second,
new TimeSpan(0, 0, 0));
if (currentDay < DateTimeOffset.UtcNow)
currentDay = esppScheduleTransformService.GetNextDateForDistributionRun(currentDay, periodType, period.Duration);
templates.Skip(templateDistributed).Take(addingTemplatesCount).ToList().ForEach(t => t.NextRun = currentDay);
d[wd.Key] = wd.Value + addingTemplatesCount;
templateDistributed += addingTemplatesCount;
}
}
}
////Отталкиваясь от количества рабочих дней
//foreach (var wd in workdays)
//{
// if (currentTemplateStep > 1 && currentTemplateStep >= templatesPerStep)
// {
// var roundedCurTemplStep = (int)Math.Round(currentTemplateStep);
// //Считаем DateTimeOffset, потому что у нас только дата пока
// currentDay = new DateTimeOffset(
// wd.Year, wd.Month, wd.Day,
// refDate.Hour, refDate.Minute, refDate.Second,
// new TimeSpan(0, 0, 0));
// if (currentDay < DateTimeOffset.UtcNow)
// currentDay = esppScheduleTransformService.GetNextDateForDistributionRun(currentDay, periodType, period.Duration);
// templates.Skip(templates.Count - balance).Take(roundedCurTemplStep).ToList().ForEach(t =>
// {
// t.NextRun = currentDay;
// });
// balance -= roundedCurTemplStep;
// delta = currentTemplateStep - roundedCurTemplStep;
// }
// else
// delta = currentTemplateStep;
// currentTemplateStep = delta + templatesPerStep;
//}
}
else
templates.ForEach(t => t.NextRun = appInWork!.ReferenceDate);
return templates;
}
}
}