feat(templateDistributor): логика распределения шаблонов по периоду
This commit is contained in:
@@ -1,16 +1,40 @@
|
||||
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(IApplicationsInWorkService applicationsInWorkService)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,27 +44,204 @@ namespace PARR.TemplateDistributor
|
||||
// группирует по РР
|
||||
// -> 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)
|
||||
public async Task<List<Template>> DistributeTemplateAsync(List<Template> templates, Guid applicationInWorkId, Guid workGroupid)
|
||||
//public async Task<List<Template>> DistributeTemplateAsync(List<Template> templates, Guid applicationInWorkId)
|
||||
{
|
||||
//TODO: ЗАГУЛШКА переделать!
|
||||
|
||||
// распределить?
|
||||
// не распределить, NextRun = appInWork.ReferenceDate
|
||||
|
||||
var appInWork = await applicationsInWorkService.Get().FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
|
||||
if (appInWork == null)
|
||||
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)
|
||||
{
|
||||
throw new Exception("ERROROORORO!!!");
|
||||
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;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
templates.ForEach(t => t.NextRun = appInWork.ReferenceDate);
|
||||
else
|
||||
templates.ForEach(t => t.NextRun = appInWork!.ReferenceDate);
|
||||
|
||||
return templates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user