diff --git a/PARR.DAL/NextRunServices/INextRunServiceV2.cs b/PARR.DAL/NextRunServices/INextRunServiceV2.cs
index f59081b9..c24af80f 100644
--- a/PARR.DAL/NextRunServices/INextRunServiceV2.cs
+++ b/PARR.DAL/NextRunServices/INextRunServiceV2.cs
@@ -20,8 +20,8 @@ namespace PARR.DAL.NextRunServices
/// ИД группы работ
/// Рабочая группа, не маска
/// Зона ответственности, не маска
- ///
- Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string workGroupName, string responseAreaName);
+ /// NextRun или null, если null - то ошибка
+ Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string workGroupName, string responseAreaName);
///
@@ -29,8 +29,8 @@ namespace PARR.DAL.NextRunServices
///
/// ИД шаблона
/// При перемещении шаблона в новую для него работу, ставить isNew=true
- ///
- Task GetNextRunForTemplateAsync(Guid templateId, bool isNew);
+ /// NextRun или null, если null - то ошибка
+ Task GetNextRunForTemplateAsync(Guid templateId, bool isNew);
diff --git a/PARR.DAL/NextRunServices/NextRunServiceV2.cs b/PARR.DAL/NextRunServices/NextRunServiceV2.cs
index 9c74bfce..655c2ab3 100644
--- a/PARR.DAL/NextRunServices/NextRunServiceV2.cs
+++ b/PARR.DAL/NextRunServices/NextRunServiceV2.cs
@@ -260,7 +260,7 @@ namespace PARR.DAL.NextRunServices
}
- public async Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string workGroupName, string responseAreaName)
+ public async Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string workGroupName, string responseAreaName)
{
logger.LogDebug("Получить nextRun для вновь создаваемого шаблона. jobGroupId: {jobGroupId}, workGroupName: {workGroupName}, responseAreaName: {responseAreaName}",
jobGroupId, workGroupName, responseAreaName);
@@ -274,7 +274,8 @@ namespace PARR.DAL.NextRunServices
if (jobGroup == null)
{
logger.LogError("Не найдена группа работ с Id: {jobGroupId}.", jobGroupId);
- throw new ArgumentNullException(nameof(jobGroupId), $"Не найдена группа работ с Id: {jobGroupId}");
+ //throw new ArgumentNullException(nameof(jobGroupId), $"Не найдена группа работ с Id: {jobGroupId}");
+ return null;
}
if (jobGroup.IsAutoDistributionEnabled)
@@ -285,7 +286,8 @@ namespace PARR.DAL.NextRunServices
if (jobGroup.DistributionConfig == null)
{
logger.LogError("Для группы работ {jobGroupId}, указано автораспределение, но отсутствует конфиг в таблице {GroupDistributionConfigs}", jobGroupId, nameof(JobGroupDistributionConfig));
- throw new ArgumentNullException(nameof(JobGroupDistributionConfig), $"Для jobGroupId: {jobGroupId} отсутствует конфигурация автораспределения в таблице {nameof(JobGroupDistributionConfig)}");
+ //throw new ArgumentNullException(nameof(JobGroupDistributionConfig), $"Для jobGroupId: {jobGroupId} отсутствует конфигурация автораспределения в таблице {nameof(JobGroupDistributionConfig)}");
+ return null;
}
var startDate = GetDateStart();
@@ -430,7 +432,7 @@ namespace PARR.DAL.NextRunServices
if (jobGroup.IsResponseAreaTimezone)
{
- // использовать часовой пояс РГ
+ // использовать часовой пояс ЗО
var referenceDate = GetReferenceDate(jobGroup, responseAreaName);
var offset = GetOffsetForDistributionByResponseArea(responseAreaName);
@@ -443,7 +445,7 @@ namespace PARR.DAL.NextRunServices
}
else
{
- // не использовать часовой пояс РГ
+ // не использовать часовой пояс ЗО
// так как это классическое расписание еспп, и не используется часовой пояс РГ, то нам нужно считать в часовом поясе УЗ ЕСПП, т.е. МСК
var referenceDate = GetReferenceDate(jobGroup, null);
@@ -459,12 +461,217 @@ namespace PARR.DAL.NextRunServices
}
- public async Task GetNextRunForTemplateAsync(Guid templateId, bool isNew)
+ public async Task GetNextRunForTemplateAsync(Guid templateId, bool isNew)
{
logger.LogDebug("Получить nextRun для существующего шаблона, templateId: {templateId}, isNew: {isNew}", templateId, isNew);
+ var template = await templateService.Get()
+ .AsNoTracking()
+ .Include(t => t.Job)
+ .ThenInclude(t => t.Group).ThenInclude(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod)
+ .FirstOrDefaultAsync(t => t.Id == templateId);
- throw new NotImplementedException();
+ if (template == null)
+ {
+ logger.LogError("Не найден шаблон с Id: {templateId}.", templateId);
+ //throw new ArgumentNullException(nameof(templateId), $"Не найден шаблон с Id: {templateId}");
+ return null;
+ }
+
+ if (template.Job!.Group!.IsAutoDistributionEnabled == true)
+ {
+ // включено автораспределение
+ logger.LogDebug("Включено автораспределение");
+
+ if (template.Job!.Group.DistributionConfig == null)
+ {
+ logger.LogError("Для шаблона {templateId}, jobGroupId {jobGroupId}, указано автораспределение, но отсутствует конфиг в таблице {GroupDistributionConfigs}", template.Id, template.Job.GroupId, nameof(JobGroupDistributionConfig));
+ // throw new ArgumentNullException(nameof(JobGroupDistributionConfig), $"Для jobGroupId: {template.Job.GroupId} отсутствует конфигурация автораспределения в таблице {nameof(JobGroupDistributionConfig)}");
+ return null;
+ }
+
+ var startDate = GetDateStart();
+ var duration = GetDurationDays(template.Job.Group.DistributionConfig);
+ var excludeWeekends = template.Job.Group.DistributionConfig.IsExcludeWeekends;
+ var targetTemplate = new TemplateNextRunDto(template.Id, template.NextRun);
+ var templateStatusType = TemplateStatusTypeEnum.Used;
+
+ var jobGroup = template.Job.Group;
+
+ // получаем все шаблоны из этой же группы что и template
+ var allTemplatesQuery = templateService.Get()
+ .AsNoTracking()
+ .Include(t => t.Job)
+ .Where(t => t.StatusTypeId == templateStatusType && t.Job!.GroupId == jobGroup.Id);
+
+ // группировать по РГ
+ var isGroupingByWorkGroup = jobGroup.DistributionConfig.IsGroupingByWorkGroup;
+
+ // использовать часовой пояс РГ
+ var isResponseAreaTimeZone = jobGroup.IsResponseAreaTimezone;
+
+ if (isGroupingByWorkGroup)
+ {
+ var targetTemplateWorkGroup = await shortcodesService.ApplyShortcodesAsync(template.Job.WorkGroupMask, template);
+
+ // группировать по РГ
+ logger.LogDebug("Нужно группировать по РГ");
+
+ // получаем для всех шаблонов РГ и группируем их по РГ
+ var templatesByWorkGroup = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ var allTemplates = await allTemplatesQuery.ToListAsync();
+ foreach (var templateItem in allTemplates)
+ {
+ var templateWorkGroupName = await shortcodesService.ApplyShortcodesAsync(templateItem.Job!.WorkGroupMask, templateItem);
+
+ // Если даже workGroupName == null, ну и ладно, сгруппируем по null
+ if (templateWorkGroupName == null)
+ logger.LogWarning("Для шаблона {id}, с маской РГ '{workGroupMask}', не смог с помощью шорткода определить рабочую группу, шорткод сервис вернул РГ: '{workGroupName}'",
+ templateItem.Id, templateItem.Job!.WorkGroupMask, templateWorkGroupName);
+
+ // Добавляем шаблон в группу
+ if (!templatesByWorkGroup.TryGetValue(templateWorkGroupName, out var templatesList))
+ {
+ templatesList = new List();
+ templatesByWorkGroup[templateWorkGroupName] = templatesList;
+ }
+ templatesList.Add(templateItem);
+ }
+
+ //Берем шаблоны только нашей РГ workGroupName
+ templatesByWorkGroup.TryGetValue(targetTemplateWorkGroup, out var templatesWithWorkGroup);
+
+ var templatesByWorkGroupDto = (templatesWithWorkGroup ?? new List()).Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList();
+
+ logger.LogDebug("Шаблонов в РГ {targetTemplateWorkGroup} - {count} шт.", targetTemplateWorkGroup, templatesByWorkGroupDto.Count);
+
+ if (isResponseAreaTimeZone)
+ {
+ // использовать часовой пояс РГ
+
+ var targetTemplateResponseArea = await shortcodesService.ApplyShortcodesAsync(template.Job.ResponseAreaMask, template);
+
+ logger.LogDebug("Использовать часовой пояс РГ '{responseAreaName}'", targetTemplateResponseArea);
+
+ var offset = GetOffsetForDistributionByResponseArea(targetTemplateResponseArea);
+ var referenceDate = GetReferenceDate(jobGroup, targetTemplateResponseArea);
+
+ var nextRun = await templateDistributor.GetNextRunForTemplateAsync(startDate, duration, referenceDate, offset, targetTemplate, templatesByWorkGroupDto, excludeWeekends, isNew);
+
+ return nextRun.NextRun;
+ }
+ else
+ {
+ // не нужно использовать часовой пояс РГ (используем часовой пояс УЗ ЕСПП)
+ logger.LogDebug("Не нужно использовать часовой пояс РГ (используем часовой пояс УЗ ЕСПП)");
+
+ var offset = GetOffsetForDistributionByResponseArea();
+ var referenceDate = GetReferenceDate(jobGroup, null);
+
+ var nextRun = await templateDistributor.GetNextRunForTemplateAsync(startDate, duration, referenceDate, offset, targetTemplate, templatesByWorkGroupDto, excludeWeekends, isNew);
+
+ return nextRun.NextRun;
+ }
+ }
+ else
+ {
+ // не нужно группировать по РГ
+ logger.LogDebug("Не нужно группировать по РГ");
+
+ if (isResponseAreaTimeZone)
+ {
+ // использовать ЧАСОВОЙ ПОЯС ЗО
+
+ var responseAreaName = await shortcodesService.ApplyShortcodesAsync(template.Job.ResponseAreaMask, template);
+
+ logger.LogDebug("Нужно использовать часовой пояс ЗО '{responseAreaName}'", responseAreaName);
+
+ // получить все шаблоны, сгруппировать их по ЗО, получить nextRun в рамках переданной ЗО
+ var referenceDate = GetReferenceDate(jobGroup, responseAreaName);
+ var offset = GetOffsetForDistributionByResponseArea(responseAreaName);
+ var allTemplates = await allTemplatesQuery.ToListAsync();
+
+ // получаем для каждого шаблона ЗО и сразу группируем по ЗО
+ var templatesByResponseArea = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ foreach (var templateItem in allTemplates)
+ {
+ var responseArea = await shortcodesService.ApplyShortcodesAsync(templateItem.Job!.ResponseAreaMask, templateItem);
+ if (responseArea == null)
+ logger.LogWarning("Для шаблона {id}, с маской ЗО '{responseAreaMask}', не смог с помощью шорткода определить ЗО, шорткод сервис вернул ЗО: '{responseArea}'",
+ templateItem.Id, templateItem.Job!.ResponseAreaMask, responseArea);
+
+ // Добавляем шаблон в группу
+ if (!templatesByResponseArea.TryGetValue(responseArea, out var templateList))
+ {
+ templateList = new List();
+ templatesByResponseArea[responseArea] = templateList;
+ }
+ templateList.Add(templateItem);
+ }
+
+ // из сгруппированных шаблонов, получаем существующие с ЗО нашего шаблона responseAreaName
+ templatesByResponseArea.TryGetValue(responseAreaName, out var templatesWithResponseArea);
+ var templatesWithResponseAreaDto = (templatesWithResponseArea ?? new List()).Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList();
+
+ logger.LogDebug("Существующих шаблонов в БД с responseAreaName: {responseAreaName} - {count} шт.", responseAreaName, templatesWithResponseAreaDto.Count);
+
+ var nextRun = await templateDistributor.GetNextRunForTemplateAsync(startDate, duration, referenceDate, offset, targetTemplate, templatesWithResponseAreaDto, excludeWeekends, isNew);
+
+ return nextRun.NextRun;
+ }
+ else
+ {
+ // не нужно использовать часовой пояс ЗО
+ logger.LogDebug("Не нужно использовать часовой пояс ЗО.");
+
+ var referenceDate = GetReferenceDate(jobGroup, null);
+ var offset = GetOffsetForDistributionByResponseArea();
+ var allTemplates = await allTemplatesQuery
+ .Select(t => new TemplateNextRunDto(t.Id, t.NextRun))
+ .ToListAsync();
+
+ var nextRun = await templateDistributor.GetNextRunForTemplateAsync(startDate, duration, referenceDate, offset, targetTemplate, allTemplates, excludeWeekends, isNew);
+
+ return nextRun.NextRun;
+ }
+ }
+ }
+ else
+ {
+ // метод расчета ЕСПП
+ logger.LogDebug("Метод расчета ЕСПП");
+
+ if (template.Job.Group.IsResponseAreaTimezone)
+ {
+ // использовать часовой пояс ЗО
+ var responseAreaName = await shortcodesService.ApplyShortcodesAsync(template.Job.ResponseAreaMask, template);
+ var jobGroup = template.Job.Group;
+
+ var referenceDate = GetReferenceDate(jobGroup, responseAreaName);
+ var offset = GetOffsetForDistributionByResponseArea(responseAreaName);
+
+ logger.LogDebug("Расчет nextRun используя метод ЕСПП, использую часовой пояс ЗО '{responseAreaName}, referenceDate: {referenceDate}, offset: {offset}'", responseAreaName, referenceDate, offset);
+
+ var nextRun = await esppScheduleTransformService.GetNextDateAsync(jobGroup.Id, referenceDate, offset);
+
+ return nextRun;
+ }
+ else
+ {
+ // не использовать часовой пояс ЗО
+ // так как это классическое расписание еспп, и не используется часовой пояс РГ, то нам нужно считать в часовом поясе УЗ ЕСПП, т.е. МСК
+
+ var referenceDate = GetReferenceDate(template.Job.Group, null);
+ var offset = GetOffsetForDistributionByResponseArea();
+
+ logger.LogDebug("Расчет nextRun используя метод ЕСПП, не использую часовой пояс ЗО, использую часовой пояс УЗ ЕСПП, referenceDate: {referenceDate}, offset: {offset}", referenceDate, offset);
+
+ var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job.GroupId, referenceDate, offset);
+
+ return nextRun;
+ }
+
+ }
}
diff --git a/PARR.Test/NextRun/NextRunTest.cs b/PARR.Test/NextRun/NextRunTest.cs
index 484715d8..be779bea 100644
--- a/PARR.Test/NextRun/NextRunTest.cs
+++ b/PARR.Test/NextRun/NextRunTest.cs
@@ -48,6 +48,12 @@ namespace PARR.Test.NextRun
// новый шаблон - еспп
//var nextRunForNewTemplateEspp = await nextRunServiceV2.GetNextRunForNewTemplateAsync(Guid.Parse("692531d6-4ef4-4a6d-99be-d2ef375d520f"), workGroupName: "ЦКИТ-ЗСИБ", responseAreaName: "83-ЗСИБ");
+ // существующий шаблон - автодистриб
+ //var nextRunForExistTemplateDistib = await nextRunServiceV2.GetNextRunForTemplateAsync(Guid.Parse("05769f8d-9630-4683-b07a-070d69e1dc12"), false);
+
+ // существующий шаблон - еспп
+ var nextRunForExistTemplateEspp = await nextRunServiceV2.GetNextRunForTemplateAsync(Guid.Parse("1329dfca-5e09-4b19-a2e6-560a4896080c"), false);
+
#endregion