Files
parr_api/PARR.DAL/NextRunServices/NextRunService.cs

225 lines
11 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.Constants;
using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models;
using PARR.DAL.Models.Job;
using PARR.DAL.NextRunServices.Models;
using PARR.DAL.NextRunServices.Subservices;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.TransformServices;
namespace PARR.DAL.NextRunServices
{
internal class NextRunService : INextRunService
{
private readonly ILogger<NextRunService> logger;
private readonly ITemplateService templateService;
private readonly IJobGroupService jobGroupService;
private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly ITemplateDistributor templateDistributor;
private readonly IShortcodesService shortcodesService;
public NextRunService(
ILogger<NextRunService> logger,
ITemplateService templateService,
IJobGroupService jobGroupService,
IEsppScheduleTransformService esppScheduleTransformService,
ITemplateDistributor templateDistributor,
IShortcodesService shortcodesService
)
{
this.logger = logger;
this.templateService = templateService;
this.jobGroupService = jobGroupService;
this.esppScheduleTransformService = esppScheduleTransformService;
this.templateDistributor = templateDistributor;
this.shortcodesService = shortcodesService;
}
public async Task<List<TemplateNextRunResultDto>?> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId)
{
logger.LogInformation("Начинаю распределять шаблоны для группы работ {gobGroupId}", jobGroupId);
var jobGroup = await jobGroupService.Get()
.Include(t => t.DistributionConfig)
.ThenInclude(t => t.DistributionPeriod)
.AsNoTracking()
.FirstOrDefaultAsync(t => t.Id == jobGroupId);
if (jobGroup == null)
{
logger.LogError("Не найдена группа работа с id: {id}", jobGroupId);
return null;
}
if (!jobGroup.IsAutoDistributionEnabled || jobGroup.DistributionConfig == null)
{
logger.LogError("Группа работ id: {id} не подходит для автораспределения, у нее или отсутствуют настройки или не включено автораспределение. IsAutoDistributionEnabled: {IsAutoDistributionEnabled}. Есть конфиг: {DistributionConfig}", jobGroupId, jobGroup.IsAutoDistributionEnabled, jobGroup.DistributionConfig != null);
return null;
}
logger.LogInformation("Параметры распределения. groupId: {groupId}, name: {groupName}, referenceDate: {referenceDate}, " +
"distributionPeriodName: {distributionPeriodName}, distributionPeriodDuration: {distributionPeriodDuration}, " +
"distributionPeriodType: {distributionPeriodType}, IsExcludeWeekends: {IsExcludeWeekends}, IsGroupingByWorkGroup: {IsGroupingByWorkGroup}",
jobGroupId, jobGroup.GroupName, jobGroup.ReferenceDate, jobGroup.DistributionConfig.DistributionPeriod.Name, jobGroup.DistributionConfig.DistributionPeriod.Duration, jobGroup.DistributionConfig.DistributionPeriod.Type,
jobGroup.DistributionConfig.IsExcludeWeekends, jobGroup.DistributionConfig.IsGroupingByWorkGroup
);
var duration = GetDurationDays(jobGroup.DistributionConfig);
var dateStart = GetDateStart(jobGroup.ReferenceDate);
var allTemplates = await templateService.Get()
.Include(t => t.Job)
.Where(t => t.Job!.GroupId == jobGroupId)
.AsNoTracking()
.ToListAsync();
if (!allTemplates.Any())
{
logger.LogInformation("В группе c ИД {jobGroupId} отсутствуют шаблоны", jobGroupId);
return null;
}
logger.LogDebug("Всего шаблонов для распределения: {count} шт.", allTemplates.Count);
var result = new List<TemplateNextRunResultDto>();
if (jobGroup.DistributionConfig.IsGroupingByWorkGroup)
{
// Нужно группировать по РГ
// список шаблонов с полученной из шорткода РГ
var templatesWithWorkGroup = new List<TemplateWithWorkGroupDto>();
foreach (var template in allTemplates)
{
var workGroupName = await shortcodesService.ApplyShortcodesAsync(template.Job!.WorkGroupMask, template);
templatesWithWorkGroup.Add(new TemplateWithWorkGroupDto(template.Id, template.NextRun, workGroupName));
}
var grouping = templatesWithWorkGroup.GroupBy(t => t.WorkGroup);
//распределяем
foreach (var workGroupTemplates in grouping)
{
logger.LogInformation("Начинаю распределять шаблоны для рабочей группы: {workGroup}. Всего шаблонов: {countTemplates} шт.", workGroupTemplates.Key, workGroupTemplates.Count());
var templatesForDistribute = workGroupTemplates.Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList();
var distributedResult = await templateDistributor.DistributeTemplatesAsync(dateStart, duration, jobGroup.ReferenceDate, templatesForDistribute, jobGroup.DistributionConfig.IsExcludeWeekends);
result.AddRange(distributedResult);
}
}
else
{
// Не нужна группировка по РГ
// сразу распределяем все шаблоны
var templatesForDistribute = allTemplates.Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList();
result = await templateDistributor.DistributeTemplatesAsync(dateStart, duration, jobGroup.ReferenceDate, templatesForDistribute, jobGroup.DistributionConfig.IsExcludeWeekends);
}
logger.LogInformation("Завершено распределение шаблонов для группы {jobGroupId}. Всего распределено шаблонов: {count} шт.", jobGroupId, result.Count);
return result;
}
public async Task<DateTimeOffset> GetNextRunForJobGroupWithEsppSchedulleAsync(Guid jobGroupId)
{
var jobGroup = await jobGroupService.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Id == jobGroupId);
if (jobGroup == null)
{
logger.LogError("Не найдена группа работ с Id: {jobGroupId}.", jobGroupId);
throw new ArgumentNullException(nameof(jobGroupId), $"Не найдена группа работ с Id: {jobGroupId}");
}
// Берем из обычного расписания ЕСПП
return await esppScheduleTransformService.GetNextDateAsync(jobGroupId, jobGroup.ReferenceDate);
}
public async Task<DateTimeOffset> GetNextRunForTemplate(Guid templateId, bool isNew)
{
var template = await templateService.Get()
.Include(t => t.Job).ThenInclude(t => t.Group)
.AsNoTracking()
.FirstOrDefaultAsync(t => t.Id == templateId);
if (template == null)
{
logger.LogError("Не найдена шаблон с Id: {templateId}.", templateId);
throw new ArgumentNullException(nameof(templateId), $"Не найдена шаблон с Id: {templateId}");
}
if (template.Job!.Group!.IsAutoDistributionEnabled == true)
{
// включено автораспределение
//TODO: !!!!!!!!!!!!!!!! добавить метод рассчета с учетом распределения
throw new NotImplementedException();
//return await templateDistributor.GetValidNextRunForTemplateAsync();
}
else
{
// считаем как ЕСПП
return await esppScheduleTransformService.GetNextDateAsync(template.Job.Group.Id, template.Job.Group.ReferenceDate);
}
}
/// <summary>
/// Получить продолжительность в днях
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
private int GetDurationDays(JobGroupDistributionConfig config)
{
var period = config.DistributionPeriod;
var periodType = period!.Type;
int.TryParse(period.Duration, out var duration);
var periodDays = duration;
if (periodType == DistributionPeriodTypeEnum.Day.ToString())
periodDays = duration;
if (periodType == DistributionPeriodTypeEnum.Month.ToString())
// в месяце 30 дней, duration*30
periodDays = duration * 30;
if (periodType == DistributionPeriodTypeEnum.Year.ToString())
// в году 365 дней, duration*365
periodDays = duration * 365;
logger.LogDebug("Период распределения: {name}, duration: {duration}, type: {type}. Итого в днях: {days}", period.Name, period.Duration, period.Type, periodDays);
if (periodDays == 0)
logger.LogWarning("Период распределения 0 дней. Неверный конфиг распределения в таблице {table}. {name}, duration: {duration}, type: {type}", nameof(DistributionPeriod), period.Name, period.Duration, period.Type);
return periodDays;
}
/// <summary>
/// Получить дату начала распределения
/// </summary>
/// <param name="referenceDate"></param>
/// <returns></returns>
private DateOnly GetDateStart(DateTimeOffset referenceDate)
{
var today = DateTime.UtcNow;
if (today < referenceDate)
return DateOnly.FromDateTime(referenceDate.Date);
else
return DateOnly.FromDateTime(today.Date);
}
}
}