fix(templateMatcher): восстановлена фильтрация рабочей группы при группировке по ответственному исполнителю

This commit is contained in:
Mikhail Kuznetsov
2026-09-15 10:02:00 +10:00
parent 0629579cf0
commit 2befb6b0c3

View File

@@ -103,33 +103,29 @@ internal class GroupedTemplateBuilder : IGroupedTemplateBuilder
// 5. Определяем значения для внутренней группировки
Dictionary<Guid, string> unitIdToGroupingValueMap;
// Загружаем список разрешённых региональных ПТК (если не нужно пропускать фильтрацию)
bool skipRegionalFilter = maxJob.WorkGroupMask.Contains("_в_ЗО_РГ", StringComparison.OrdinalIgnoreCase);
HashSet<string>? allowedWorkGroupSet = null;
if (!skipRegionalFilter)
{
var allowedWorkGroupValues = await regionalEkPtkGroupRepository.Get()
.AsNoTracking()
.Include(g => g.FieldValue)
.Where(g => g.FieldValue != null && g.FieldValue.Value != null)
.Select(g => g.FieldValue!.Value!)
.ToListAsync(ct);
allowedWorkGroupSet = new HashSet<string>(allowedWorkGroupValues, StringComparer.OrdinalIgnoreCase);
logger.LogDebug("Загружено {Count} разрешённых значений рабочих групп из RegionalEkPtkGroup.", allowedWorkGroupSet.Count);
}
else
{
logger.LogDebug("Маска содержит тег с '_в_ЗО_РГ'. Фильтрация по списку рабочих групп ПТК пропущена.");
}
if (useWorkGroupMask)
{
// Определяем, нужно ли выполнять фильтрацию по списку рабочих групп ПТК.
// Если маска содержит тег с "_в_ЗО_РГ", фильтрация не выполняется.
var skipRegionalFilter = maxJob.WorkGroupMask.Contains("_в_ЗО_РГ", StringComparison.OrdinalIgnoreCase);
HashSet<string>? allowedWorkGroupSet = null;
if (!skipRegionalFilter)
{
// Загружаем разрешённые значения из regionalEkPtkGroupRepository
var allowedWorkGroupValues = await regionalEkPtkGroupRepository.Get()
.AsNoTracking()
.Include(g => g.FieldValue)
.Where(g => g.FieldValue != null && g.FieldValue.Value != null)
.Select(g => g.FieldValue!.Value!)
.ToListAsync(ct);
allowedWorkGroupSet = new HashSet<string>(allowedWorkGroupValues, StringComparer.OrdinalIgnoreCase);
logger.LogDebug("Загружено {Count} разрешённых значений рабочих групп из RegionalEkPtkGroup.", allowedWorkGroupSet.Count);
}
else
{
logger.LogDebug("Маска содержит тег с '_в_ЗО_РГ'. Фильтрация по списку рабочих групп ПТК пропущена.");
}
// Применяем WorkGroupMask для каждого юнита отдельно
unitIdToGroupingValueMap = new Dictionary<Guid, string>();
@@ -169,16 +165,16 @@ internal class GroupedTemplateBuilder : IGroupedTemplateBuilder
continue;
}
// Фильтрация по списку рабочих групп ПТК выполняется только если не используется тег с "_в_ЗО_РГ"
// Фильтрация по списку рабочих групп ПТК
if (!skipRegionalFilter && !allowedWorkGroupSet!.Contains(workGroupValue))
{
logger.LogDebug( // Изменено с LogDebug на LogInformation для тестирования
logger.LogDebug(
"[FILTER] Юнит {UnitId} ИСКЛЮЧЁН: рабочая группа '{WorkGroup}' не найдена в списке разрешённых ({AllowedCount} значений).",
relatedUnitId, workGroupValue, allowedWorkGroupSet!.Count);
continue;
}
logger.LogDebug( // Добавляем лог для успешного прохождения
logger.LogDebug(
"[FILTER] Юнит {UnitId} ПРОШЁЛ: рабочая группа '{WorkGroup}' для PotentialUnit {PotentialUnitId}.",
relatedUnitId, workGroupValue, potentialUnitId);
@@ -201,9 +197,79 @@ internal class GroupedTemplateBuilder : IGroupedTemplateBuilder
new HashSet<Guid> { innerGroupingFieldId },
ct);
unitIdToGroupingValueMap = innerGroupingValues
.Where(uv => uv.Value != null && uv.Value.Value != null && !string.IsNullOrEmpty(uv.Value.Value))
// Собираем значения поля "Ответственный" для группировки
var responsibleValueByUnit = innerGroupingValues
.Where(uv => uv.Value != null && !string.IsNullOrEmpty(uv.Value.Value))
.ToDictionary(uv => uv.UnitId, uv => uv.Value!.Value!);
unitIdToGroupingValueMap = new Dictionary<Guid, string>();
// Для каждого юнита дополнительно применяем WorkGroupMask и фильтруем по RegionalEkPtkGroup
foreach (var potentialUnitId in reverseMapping.Keys)
{
var relatedUnitIds = reverseMapping[potentialUnitId]
.Select(e => e.UnitId)
.Distinct()
.ToList();
foreach (var relatedUnitId in relatedUnitIds)
{
// Юнит исключается, если у него нет значения поля "Ответственный"
if (!responsibleValueByUnit.TryGetValue(relatedUnitId, out var responsibleValue))
{
logger.LogDebug(
"Юнит {UnitId} исключён: отсутствует значение поля 'Ответственный за ЭК'.",
relatedUnitId);
continue;
}
// Фильтрация по списку региональных ПТК выполняется только если не используется тег с "_в_ЗО_РГ"
if (!skipRegionalFilter)
{
// Формируем временный шаблон с одним связанным юнитом для применения WorkGroupMask
var tempTemplate = new Template
{
Id = Guid.NewGuid(),
Name = "temp",
JobId = maxJob.Id,
UnitId = potentialUnitId,
Job = maxJob,
UnitsInTemplate = new List<UnitsInTemplate>
{
new UnitsInTemplate { UnitId = relatedUnitId, UnitFieldValueId = Guid.Empty }
}
};
var workGroupValue = await shortcodesService.ApplyShortcodesAsync(
maxJob.WorkGroupMask,
tempTemplate,
nameof(GroupedTemplateBuilder));
if (string.IsNullOrEmpty(workGroupValue))
{
logger.LogDebug(
"Юнит {UnitId} исключён: WorkGroupMask вернула пустую строку.",
relatedUnitId);
continue;
}
if (!allowedWorkGroupSet!.Contains(workGroupValue))
{
logger.LogDebug(
"[FILTER] Юнит {UnitId} ИСКЛЮЧЁН: рабочая группа '{WorkGroup}' не найдена в списке разрешённых ({AllowedCount} значений).",
relatedUnitId, workGroupValue, allowedWorkGroupSet!.Count);
continue;
}
logger.LogDebug(
"[FILTER] Юнит {UnitId} ПРОШЁЛ: рабочая группа '{WorkGroup}' для PotentialUnit {PotentialUnitId}.",
relatedUnitId, workGroupValue, potentialUnitId);
}
// В маппинг группировки пишем значение поля "Ответственный" — по нему идёт группировка в этапе 6
unitIdToGroupingValueMap[relatedUnitId] = responsibleValue;
}
}
}
// 6. Формируем итоговую структуру