feat(dal,templateMatcher): добавлена сортировка связанных юнитов группированного типа групп работ
This commit is contained in:
@@ -15,7 +15,6 @@ using PARR.DAL.Services.Interfaces.Unit;
|
||||
using PARR.DAL.TransformServices;
|
||||
using PARR.TemplateMatcher.Services.Interfaces;
|
||||
using PARR.TemplateMatcher.Settings;
|
||||
using System.Configuration;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace PARR.TemplateMatcher.Services.Implementations;
|
||||
@@ -502,20 +501,31 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
foreach (var kvp in groupedRelationships)
|
||||
{
|
||||
var relationshipUnitId = kvp.Key; // Связанный юнит (не из unitIdsWithValidGroupingFieldSet)
|
||||
var childUnitIds = kvp.Value; // Юниты из unitIdsWithValidGroupingFieldSet, связанные с regionalUnitId
|
||||
var childUnitIds = kvp.Value; // Юниты из unitIdsWithValidGroupingFieldSet, связанные с relationshipUnitId
|
||||
if (childUnitIds.Count == 0)
|
||||
continue;
|
||||
|
||||
#if DEBUG
|
||||
// Отладка: проверить, есть ли ВРТ-AOS-05-ДВС в childUnitIds
|
||||
var childUnitNames = childUnitIds.Select(id => unitService.Get().AsNoTracking().Where(u => u.Id == id).Select(u => u.Name).FirstOrDefaultAsync().GetAwaiter().GetResult() ?? id.ToString()).ToList();
|
||||
if (childUnitNames.Contains("ВРТ-AOS-05-ДВС"))
|
||||
var childUnitNamesForDebug = childUnitIds.Select(id => unitService.Get().AsNoTracking().Where(u => u.Id == id).Select(u => u.Name).FirstOrDefaultAsync().GetAwaiter().GetResult() ?? id.ToString()).ToList();
|
||||
if (childUnitNamesForDebug.Contains("ВРТ-AOS-05-ДВС"))
|
||||
{
|
||||
var relationshipUnitName = await unitService.Get().AsNoTracking().Where(u => u.Id == relationshipUnitId).Select(u => u.Name).FirstOrDefaultAsync();
|
||||
logger.LogDebug("Группа с ключом {Key} (название: {Name}) содержит юнит 'ВРТ-AOS-05-ДВС' в childUnitIds: [{ChildUnitNames}]", relationshipUnitId, relationshipUnitName, string.Join(", ", childUnitNames));
|
||||
logger.LogDebug("Группа с ключом {Key} (название: {Name}) содержит юнит 'ВРТ-AOS-05-ДВС' в childUnitIds: [{ChildUnitNames}]", relationshipUnitId, relationshipUnitName, string.Join(", ", childUnitNamesForDebug));
|
||||
}
|
||||
#endif
|
||||
|
||||
logger.LogDebug("Обработка связанного юнита {RegionalUnitId} с {Count} юнитами из списка.", relationshipUnitId, childUnitIds.Count);
|
||||
logger.LogDebug("Обработка связанного юнита {RelationshipUnitId} с {Count} юнитами из списка.", relationshipUnitId, childUnitIds.Count);
|
||||
|
||||
// --- СОРТИРОВКА childUnitIds ПО ИМЕНИ ---
|
||||
var childUnitNameMap = await unitService.Get()
|
||||
.AsNoTracking()
|
||||
.Where(u => childUnitIds.Contains(u.Id))
|
||||
.ToDictionaryAsync(u => u.Id, u => u.Name);
|
||||
|
||||
var sortedChildUnitIds = childUnitIds
|
||||
.OrderBy(id => childUnitNameMap.GetValueOrDefault(id, id.ToString()))
|
||||
.ToList();
|
||||
|
||||
// Применяем ограничение MaxValueRelationships maxJob
|
||||
if (!maxJob.MaxValueRelationships.HasValue)
|
||||
@@ -524,13 +534,13 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
return;
|
||||
}
|
||||
int maxValueForSplitting = maxJob.MaxValueRelationships.Value;
|
||||
var childUnitGroups = childUnitIds
|
||||
var childUnitGroups = sortedChildUnitIds
|
||||
.Select((id, index) => new { id, groupIndex = index / maxValueForSplitting })
|
||||
.GroupBy(x => x.groupIndex)
|
||||
.Select(g => g.Select(x => x.id).ToList())
|
||||
.ToList();
|
||||
|
||||
logger.LogDebug("Связанный юнит {RegionalUnitId}: разбит на {GroupCount} подгрупп.", relationshipUnitId, childUnitGroups.Count);
|
||||
logger.LogDebug("Связанный юнит {RelationshipUnitId}: разбит на {GroupCount} подгрупп (после сортировки по имени).", relationshipUnitId, childUnitGroups.Count);
|
||||
|
||||
// Для каждой подгруппы:
|
||||
for (int i = 0; i < childUnitGroups.Count; i++)
|
||||
@@ -538,7 +548,7 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
var subGroup = childUnitGroups[i];
|
||||
var subGroupSize = subGroup.Count;
|
||||
|
||||
logger.LogDebug("Обработка подгруппы {Index} связанного юнита {RegionalUnitId}, размер {Size}.", i, relationshipUnitId, subGroupSize);
|
||||
logger.LogDebug("Обработка подгруппы {Index} связанного юнита {RelationshipUnitId}, размер {Size}.", i, relationshipUnitId, subGroupSize);
|
||||
|
||||
// Выбираем targetJob для подгруппы
|
||||
Job? targetJob = SelectTargetJob(jobsInGroup, subGroupSize, maxJob);
|
||||
@@ -560,7 +570,7 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
|
||||
if (existingUnitIds.SetEquals(newUnitIds))
|
||||
{
|
||||
logger.LogDebug("Шаблон {TemplateId} (Job {JobId}, Regional {RegionalId}, Index {Index}) актуален по юнитам.", existingTemplateForSubGroup.Id, targetJob.Id, relationshipUnitId, i);
|
||||
logger.LogDebug("Шаблон {TemplateId} (Job {JobId}, Relationship {RelationshipId}, Index {Index}) актуален по юнитам.", existingTemplateForSubGroup.Id, targetJob.Id, relationshipUnitId, i);
|
||||
|
||||
// Проверить, изменилось ли имя шаблона (например, из-за %МАКС:...% или %ТНК-КРАТКО%)
|
||||
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(targetJob, relationshipUnitId, i, subGroup);
|
||||
@@ -595,7 +605,7 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("Шаблон {TemplateId} (Job {JobId}, Regional {RegionalId}, Index {Index}) требует обновления юнитов.", existingTemplateForSubGroup.Id, targetJob.Id, relationshipUnitId, i);
|
||||
logger.LogDebug("Шаблон {TemplateId} (Job {JobId}, Relationship {RelationshipId}, Index {Index}) требует обновления юнитов.", existingTemplateForSubGroup.Id, targetJob.Id, relationshipUnitId, i);
|
||||
|
||||
// Пересчитать targetJob для нового размера subGroup
|
||||
var newTargetJob = SelectTargetJob(jobsInGroup, subGroupSize, maxJob);
|
||||
@@ -615,7 +625,7 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
|
||||
if (reusableTemplate != null)
|
||||
{
|
||||
logger.LogInformation("Переиспользован шаблон {TemplateId} для Job {JobId}, связанного юнита {RegionalId}, Index {Index}.", reusableTemplate.Id, targetJob.Id, relationshipUnitId, i);
|
||||
logger.LogInformation("Переиспользован шаблон {TemplateId} для Job {JobId}, связанного юнита {RelationshipId}, Index {Index}.", reusableTemplate.Id, targetJob.Id, relationshipUnitId, i);
|
||||
|
||||
var expectedName = await templateNameNormalizer.GetNormalizedTemplateNameAsync(targetJob, relationshipUnitId, i, subGroup);
|
||||
var nextRun = await GetNextRunAsync(targetJob);
|
||||
@@ -639,21 +649,32 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogDebug("Создание нового шаблона для Job {JobId}, связанного юнита {RegionalId}, Index {Index}, с {Count} юнитами.", targetJob.Id, relationshipUnitId, i, subGroup.Count);
|
||||
logger.LogDebug("Создание нового шаблона для Job {JobId}, связанного юнита {RelationshipUnitId}, Index {Index}, с {Count} юнитами.", targetJob.Id, relationshipUnitId, i, subGroup.Count);
|
||||
await CreateGroupedTemplateAsync(targetJob.Id, relationshipUnitId, subGroup, i, initiator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Деактивировать шаблоны, которые больше не соответствуют ни одной подгруппе (логика без изменений)
|
||||
// 10. Деактивировать шаблоны, которые больше не соответствуют ни одной подгруппе
|
||||
var expectedTemplateKeys = new HashSet<(Guid JobId, Guid UnitId, int Index)>();
|
||||
foreach (var kvp in groupedRelationships)
|
||||
{
|
||||
var regionalUnitId = kvp.Key;
|
||||
var relationshipUnitId = kvp.Key;
|
||||
var childUnitIds = kvp.Value;
|
||||
|
||||
// --- СОРТИРОВКА ПЕРЕД ФОРМИРОВАНИЕМ expectedTemplateKeys ---
|
||||
var childUnitNameMapForDeactivate = await unitService.Get()
|
||||
.AsNoTracking()
|
||||
.Where(u => childUnitIds.Contains(u.Id))
|
||||
.ToDictionaryAsync(u => u.Id, u => u.Name);
|
||||
|
||||
var sortedChildUnitIdsForDeactivate = childUnitIds
|
||||
.OrderBy(id => childUnitNameMapForDeactivate.GetValueOrDefault(id, id.ToString()))
|
||||
.ToList();
|
||||
|
||||
int maxValueForSplitting = maxJob.MaxValueRelationships!.Value;
|
||||
var childUnitGroups = childUnitIds
|
||||
var childUnitGroups = sortedChildUnitIdsForDeactivate
|
||||
.Select((id, index) => new { id, groupIndex = index / maxValueForSplitting })
|
||||
.GroupBy(x => x.groupIndex)
|
||||
.Select(g => g.Select(x => x.id).ToList())
|
||||
@@ -666,17 +687,17 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
|
||||
Job? targetJobForExpectedKey = SelectTargetJob(jobsInGroup, subGroupSize, maxJob);
|
||||
|
||||
expectedTemplateKeys.Add((targetJobForExpectedKey.Id, regionalUnitId, i));
|
||||
expectedTemplateKeys.Add((targetJobForExpectedKey.Id, relationshipUnitId, i));
|
||||
}
|
||||
}
|
||||
|
||||
var allRegionalUnitIds = groupedRelationships.Keys.ToHashSet();
|
||||
var allRelationshipUnitIds = groupedRelationships.Keys.ToHashSet();
|
||||
var allJobIdsInGroup = jobsInGroup.Select(j => j.Id).ToHashSet();
|
||||
|
||||
var allExistingTemplatesInGroup = await templateService.Get()
|
||||
.AsNoTracking()
|
||||
.Include(t => t.UnitsInTemplate)
|
||||
.Where(t => allJobIdsInGroup.Contains(t.JobId) && allRegionalUnitIds.Contains(t.UnitId))
|
||||
.Where(t => allJobIdsInGroup.Contains(t.JobId) && allRelationshipUnitIds.Contains(t.UnitId))
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var existingTemplate in allExistingTemplatesInGroup)
|
||||
@@ -767,14 +788,14 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
await templateUpdaterMqSender.SendTemplateUpdateMessageAsync(updateRequest);
|
||||
}
|
||||
|
||||
private async Task CreateGroupedTemplateAsync(Guid jobId, Guid regionalUnitId, List<Guid> unitIds, int index, HistoryInitiator initiator)
|
||||
private async Task CreateGroupedTemplateAsync(Guid jobId, Guid relationshipUnitId, List<Guid> unitIds, int index, HistoryInitiator initiator)
|
||||
{
|
||||
logger.LogInformation("Создание нового группового шаблона для Job {JobId}, связанного юнита {RegionalUnitId}, Index {Index}, с {Count} юнитами.", jobId, regionalUnitId, index, unitIds.Count);
|
||||
logger.LogInformation("Создание нового группового шаблона для Job {JobId}, связанного юнита {RelationshipUnitId}, Index {Index}, с {Count} юнитами.", jobId, relationshipUnitId, index, unitIds.Count);
|
||||
|
||||
var mqRequest = new TemplateGeneratorMq
|
||||
{
|
||||
JobId = jobId,
|
||||
UnitId = regionalUnitId, // UnitId шаблона
|
||||
UnitId = relationshipUnitId, // UnitId шаблона
|
||||
UnitsInTemplate = unitIds, // Юниты для UnitsInTemplate
|
||||
Index = index, // Индекс шаблона
|
||||
HistoryInitiator = initiator
|
||||
@@ -784,7 +805,7 @@ internal class GroupedTemplateSynchronizer : ITemplateSynchronizer
|
||||
var result = await mqService.SendAsync(mqSettings.TemplateGenerator, new[] { msg });
|
||||
|
||||
if (!result.IsSuccess)
|
||||
logger.LogError("Ошибка отправки команды создания группового шаблона для Job {JobId}, связанного юнита {RegionalUnitId}, Index {Index}.", jobId, regionalUnitId, index);
|
||||
logger.LogError("Ошибка отправки команды создания группового шаблона для Job {JobId}, связанного юнита {RelationshipUnitId}, Index {Index}.", jobId, relationshipUnitId, index);
|
||||
}
|
||||
|
||||
private async Task<DateTimeOffset> GetNextRunAsync(Job targetJob, DateTimeOffset? currentNextRun = null)
|
||||
|
||||
Reference in New Issue
Block a user