diff --git a/PARR.DAL/NextRunServices/INextRunServiceV2.cs b/PARR.DAL/NextRunServices/INextRunServiceV2.cs
index f101651e..f59081b9 100644
--- a/PARR.DAL/NextRunServices/INextRunServiceV2.cs
+++ b/PARR.DAL/NextRunServices/INextRunServiceV2.cs
@@ -12,5 +12,27 @@ namespace PARR.DAL.NextRunServices
/// Статус шаблона, если не передать, берутся все шаблоны группы
/// Список TemplateId с NextRun и NextRunOld
Task?> GetNextRunForJobGroupWithAutoDistributionAsync(Guid jobGroupId, TemplateStatusTypeEnum? templateStatusType);
+
+
+ ///
+ /// Получить nextRun для вновь создаваемого шаблона, которого еще нет в БД
+ ///
+ /// ИД группы работ
+ /// Рабочая группа, не маска
+ /// Зона ответственности, не маска
+ ///
+ Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string workGroupName, string responseAreaName);
+
+
+ ///
+ /// Получить nextRun по id существующего в БД шаблона
+ ///
+ /// ИД шаблона
+ /// При перемещении шаблона в новую для него работу, ставить isNew=true
+ ///
+ Task GetNextRunForTemplateAsync(Guid templateId, bool isNew);
+
+
+
}
}
diff --git a/PARR.DAL/NextRunServices/NextRunService.cs b/PARR.DAL/NextRunServices/NextRunService.cs
index eb7f0ee5..b6751d2f 100644
--- a/PARR.DAL/NextRunServices/NextRunService.cs
+++ b/PARR.DAL/NextRunServices/NextRunService.cs
@@ -153,7 +153,7 @@ namespace PARR.DAL.NextRunServices
public async Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string responseArea)
{
- // определяю это автораспределение или нет, вызываю соответствующий рассчет
+ // определяю это автораспределение или нет, вызываю соответствующий расчет
var jobGroup = await jobGroupService.Get()
.Include(t => t.DistributionConfig)
diff --git a/PARR.DAL/NextRunServices/NextRunServiceV2.cs b/PARR.DAL/NextRunServices/NextRunServiceV2.cs
index 97d0638c..9c74bfce 100644
--- a/PARR.DAL/NextRunServices/NextRunServiceV2.cs
+++ b/PARR.DAL/NextRunServices/NextRunServiceV2.cs
@@ -115,7 +115,7 @@ namespace PARR.DAL.NextRunServices
logger.LogDebug("Нужно группировать по РГ");
// получаем для каждого шаблона РГ и сразу группируем по РГ
- var templatesByWorkGroup = new Dictionary>();
+ var templatesByWorkGroup = new Dictionary>(StringComparer.OrdinalIgnoreCase);
foreach (var template in allTemplates)
{
var workGroupName = await shortcodesService.ApplyShortcodesAsync(template.Job!.WorkGroupMask, template);
@@ -199,7 +199,7 @@ namespace PARR.DAL.NextRunServices
logger.LogDebug("Использовать ЧАСОВОЙ ПОЯС ЗО (нужно сгруппировать шаблоны по часовым поясам, затем отдельно распределить каждую группу)");
// получаем для каждого шаблона ЗО и сразу группируем по ЗО
- var templatesByResponseArea = new Dictionary>();
+ var templatesByResponseArea = new Dictionary>(StringComparer.OrdinalIgnoreCase);
foreach (var template in allTemplates)
{
var responseArea = await shortcodesService.ApplyShortcodesAsync(template.Job!.ResponseAreaMask, template);
@@ -260,6 +260,214 @@ namespace PARR.DAL.NextRunServices
}
+ public async Task GetNextRunForNewTemplateAsync(Guid jobGroupId, string workGroupName, string responseAreaName)
+ {
+ logger.LogDebug("Получить nextRun для вновь создаваемого шаблона. jobGroupId: {jobGroupId}, workGroupName: {workGroupName}, responseAreaName: {responseAreaName}",
+ jobGroupId, workGroupName, responseAreaName);
+
+ var jobGroup = await jobGroupService.Get()
+ .AsNoTracking()
+ .Include(t => t.DistributionConfig)
+ .ThenInclude(t => t.DistributionPeriod)
+ .FirstOrDefaultAsync(t => t.Id == jobGroupId);
+
+ if (jobGroup == null)
+ {
+ logger.LogError("Не найдена группа работ с Id: {jobGroupId}.", jobGroupId);
+ throw new ArgumentNullException(nameof(jobGroupId), $"Не найдена группа работ с Id: {jobGroupId}");
+ }
+
+ if (jobGroup.IsAutoDistributionEnabled)
+ {
+ // автораспределение
+ logger.LogDebug("Расчет используя метод распределения работ");
+
+ if (jobGroup.DistributionConfig == null)
+ {
+ logger.LogError("Для группы работ {jobGroupId}, указано автораспределение, но отсутствует конфиг в таблице {GroupDistributionConfigs}", jobGroupId, nameof(JobGroupDistributionConfig));
+ throw new ArgumentNullException(nameof(JobGroupDistributionConfig), $"Для jobGroupId: {jobGroupId} отсутствует конфигурация автораспределения в таблице {nameof(JobGroupDistributionConfig)}");
+ }
+
+ var startDate = GetDateStart();
+ var duration = GetDurationDays(jobGroup.DistributionConfig);
+ var excludeWeekends = jobGroup.DistributionConfig.IsExcludeWeekends;
+ var targetTemplate = new TemplateNextRunDto(Guid.Empty, null);
+ var templateStatusType = TemplateStatusTypeEnum.Used;
+ var allTemplatesQuery = templateService.Get()
+ .AsNoTracking()
+ .Include(t => t.Job)
+ .Where(t => t.StatusTypeId == templateStatusType && t.Job!.GroupId == jobGroupId);
+
+ // группировать по РГ
+ var isGroupingByWorkGroup = jobGroup.DistributionConfig.IsGroupingByWorkGroup;
+
+ // использовать часовой пояс РГ
+ var isResponseAreaTimeZone = jobGroup.IsResponseAreaTimezone;
+
+ if (isGroupingByWorkGroup)
+ {
+ // группировать по РГ
+ logger.LogDebug("Нужно группировать по РГ");
+
+ // получаем для всех шаблонов РГ и группируем их по РГ
+ var templatesByWorkGroup = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ var allTemplates = await allTemplatesQuery.ToListAsync();
+ foreach (var template in allTemplates)
+ {
+ var templateWorkGroupName = await shortcodesService.ApplyShortcodesAsync(template.Job!.WorkGroupMask, template);
+
+ // Если даже workGroupName == null, ну и ладно, сгруппируем по null
+ if (templateWorkGroupName == null)
+ logger.LogWarning("Для шаблона {id}, с маской РГ '{workGroupMask}', не смог с помощью шорткода определить рабочую группу, шорткод сервис вернул РГ: '{workGroupName}'",
+ template.Id, template.Job!.WorkGroupMask, templateWorkGroupName);
+
+ // Добавляем шаблон в группу
+ if (!templatesByWorkGroup.TryGetValue(templateWorkGroupName, out var templatesList))
+ {
+ templatesList = new List();
+ templatesByWorkGroup[templateWorkGroupName] = templatesList;
+ }
+ templatesList.Add(template);
+ }
+
+ //Берем шаблоны только нашей РГ workGroupName
+ templatesByWorkGroup.TryGetValue(workGroupName, out var templatesWithWorkGroup);
+
+ var templatesByWorkGroupDto = (templatesWithWorkGroup ?? new List()).Select(t => new TemplateNextRunDto(t.Id, t.NextRun)).ToList();
+
+ logger.LogDebug("Шаблонов в РГ {workGroupName} - {count} шт.", workGroupName, templatesByWorkGroupDto.Count);
+
+ if (isResponseAreaTimeZone)
+ {
+ // использовать часовой пояс РГ
+ logger.LogDebug("Использовать часовой пояс РГ '{responseAreaName}'", responseAreaName);
+
+ var offset = GetOffsetForDistributionByResponseArea(responseAreaName);
+ var referenceDate = GetReferenceDate(jobGroup, responseAreaName);
+
+ var nextRun = await templateDistributor.GetNextRunForTemplateAsync(startDate, duration, referenceDate, offset, targetTemplate, templatesByWorkGroupDto, excludeWeekends, isNew: true);
+
+ 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: true);
+
+ return nextRun.NextRun;
+ }
+ }
+ else
+ {
+ // не нужно группировать по РГ
+ logger.LogDebug("Не нужно группировать по РГ");
+
+ if (isResponseAreaTimeZone)
+ {
+ // использовать ЧАСОВОЙ ПОЯС ЗО
+
+ 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 template in allTemplates)
+ {
+ var responseArea = await shortcodesService.ApplyShortcodesAsync(template.Job!.ResponseAreaMask, template);
+ if (responseArea == null)
+ logger.LogWarning("Для шаблона {id}, с маской ЗО '{responseAreaMask}', не смог с помощью шорткода определить ЗО, шорткод сервис вернул ЗО: '{responseArea}'",
+ template.Id, template.Job!.ResponseAreaMask, responseArea);
+
+ // Добавляем шаблон в группу
+ if (!templatesByResponseArea.TryGetValue(responseArea, out var templateList))
+ {
+ templateList = new List();
+ templatesByResponseArea[responseArea] = templateList;
+ }
+ templateList.Add(template);
+ }
+
+ // из сгруппированных шаблонов, получаем существующие с нашей переданной 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: true);
+
+ 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: true);
+
+ return nextRun.NextRun;
+ }
+ }
+ }
+ else
+ {
+ // расписание ЕСПП
+ logger.LogDebug("Расчет используя метод ЕСПП");
+
+ if (jobGroup.IsResponseAreaTimezone)
+ {
+ // использовать часовой пояс РГ
+
+ 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(jobGroupId, referenceDate, offset);
+
+ return nextRun;
+ }
+ else
+ {
+ // не использовать часовой пояс РГ
+ // так как это классическое расписание еспп, и не используется часовой пояс РГ, то нам нужно считать в часовом поясе УЗ ЕСПП, т.е. МСК
+
+ var referenceDate = GetReferenceDate(jobGroup, null);
+ var offset = GetOffsetForDistributionByResponseArea();
+
+ logger.LogDebug("Расчет nextRun используя метод ЕСПП, не использую часовой пояс ЗО, использую часовой пояс УЗ ЕСПП, referenceDate: {referenceDate}, offset: {offset}", referenceDate, offset);
+
+ var nextRun = await esppScheduleTransformService.GetNextDateAsync(jobGroupId, referenceDate, offset);
+
+ return nextRun;
+ }
+ }
+ }
+
+
+ public async Task GetNextRunForTemplateAsync(Guid templateId, bool isNew)
+ {
+ logger.LogDebug("Получить nextRun для существующего шаблона, templateId: {templateId}, isNew: {isNew}", templateId, isNew);
+
+
+ throw new NotImplementedException();
+ }
+
+
///
/// Получить продолжительность в днях
///
@@ -354,7 +562,6 @@ namespace PARR.DAL.NextRunServices
}
-
///
/// Получить referenceDate для расчета с учетом часового пояса ЗО или без учета
///
@@ -413,7 +620,5 @@ namespace PARR.DAL.NextRunServices
}
}
-
-
}
}
diff --git a/PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs b/PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs
index f94f9291..c78caabf 100644
--- a/PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs
+++ b/PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs
@@ -68,7 +68,7 @@ namespace PARR.DAL.NextRunServices.Subservices
{
//offset - желательно передавать всегда, хотябы МСК, чтобы рассчитывались правильно даты, так как в ЕСПП все в МСК
- logger.LogDebug("Начинаю рассчет nextRun по расписанию ЕСПП. Входные данные: date: {referenceDate}, offset: {offset}, esppSchedule: {esppSchedule}", referenceDate, offset, JsonSerializer.Serialize(esppSchedule));
+ logger.LogDebug("Начинаю рассчет nextRun по расписанию ЕСПП. Входные данные: date: {referenceDate}, offset: {offset}", referenceDate, offset);
var nextRun = referenceDate;
diff --git a/PARR.Test/NextRun/NextRunTest.cs b/PARR.Test/NextRun/NextRunTest.cs
index 4f96b434..484715d8 100644
--- a/PARR.Test/NextRun/NextRunTest.cs
+++ b/PARR.Test/NextRun/NextRunTest.cs
@@ -39,7 +39,14 @@ namespace PARR.Test.NextRun
{
#region тестирование INextRunServiceV2
- var distributeResult = await nextRunServiceV2.GetNextRunForJobGroupWithAutoDistributionAsync(Guid.Parse("d25d8a9e-898f-417a-9bec-ef3a356e7c94"), TemplateStatusTypeEnum.Used);
+ //рапсределить
+ //var distributeResult = await nextRunServiceV2.GetNextRunForJobGroupWithAutoDistributionAsync(Guid.Parse("d25d8a9e-898f-417a-9bec-ef3a356e7c94"), TemplateStatusTypeEnum.Used);
+
+ // новый шаблон - автодистриб
+ //var nextRunForNewTemplateDistrib = await nextRunServiceV2.GetNextRunForNewTemplateAsync(Guid.Parse("d25d8a9e-898f-417a-9bec-ef3a356e7c94"), workGroupName: "ЦКИТ-ВСИБ", responseAreaName: "92-ВСИБ");
+
+ // новый шаблон - еспп
+ //var nextRunForNewTemplateEspp = await nextRunServiceV2.GetNextRunForNewTemplateAsync(Guid.Parse("692531d6-4ef4-4a6d-99be-d2ef375d520f"), workGroupName: "ЦКИТ-ЗСИБ", responseAreaName: "83-ЗСИБ");
#endregion