- унификация деактивации шаблонов между разными синхронизаторами - поиск ЭК выделен в отдельную сущность
209 lines
7.6 KiB
C#
209 lines
7.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
using PARR.Core.Repositories.Interfaces.Unit;
|
||
using PARR.Domain.Entities;
|
||
using PARR.Domain.Entities.Unit;
|
||
using PARR.TemplateMatcher.Constants;
|
||
using PARR.TemplateMatcher.Services.Interfaces;
|
||
|
||
namespace PARR.TemplateMatcher.Services.Implementations;
|
||
|
||
internal class UnusedTemplateTargetUnitResolver : IUnusedTemplateTargetUnitResolver
|
||
{
|
||
private readonly IUnitFieldRepository _unitFieldRepository;
|
||
private readonly IUnitInValueRepository _unitInValueRepository;
|
||
private readonly IUnitRepository _unitRepository;
|
||
private readonly ILogger<UnusedTemplateTargetUnitResolver> _logger;
|
||
|
||
public UnusedTemplateTargetUnitResolver(
|
||
IUnitFieldRepository unitFieldRepository,
|
||
IUnitInValueRepository unitInValueRepository,
|
||
IUnitRepository unitRepository,
|
||
ILogger<UnusedTemplateTargetUnitResolver> logger)
|
||
{
|
||
_unitFieldRepository = unitFieldRepository;
|
||
_unitInValueRepository = unitInValueRepository;
|
||
_unitRepository = unitRepository;
|
||
_logger = logger;
|
||
}
|
||
|
||
public async Task<IReadOnlyDictionary<Guid, Unit>> ResolveAsync(
|
||
IReadOnlyCollection<Template> templates,
|
||
CancellationToken ct = default)
|
||
{
|
||
var result = new Dictionary<Guid, Unit>();
|
||
|
||
foreach (var template in templates.Where(t => t.Unit != null))
|
||
{
|
||
result[template.Id] = template.Unit!;
|
||
}
|
||
|
||
if (templates.Count == 0)
|
||
return result;
|
||
|
||
var responsableAreaField = await _unitFieldRepository.GetByAihitNameAsync(
|
||
UnusedTemplateConstants.ResponsibilityAreaFieldName,
|
||
ct);
|
||
|
||
var tagField = await _unitFieldRepository.GetByAihitNameAsync(
|
||
UnusedTemplateConstants.ParrTagFieldName,
|
||
ct);
|
||
|
||
if (responsableAreaField == null || tagField == null)
|
||
{
|
||
_logger.LogWarning(
|
||
"Не найдены поля '{ResponsibilityAreaField}' или '{TagField}'. Целевой Unit для неиспользуемых шаблонов будет выбран как текущий.",
|
||
UnusedTemplateConstants.ResponsibilityAreaFieldName,
|
||
UnusedTemplateConstants.ParrTagFieldName);
|
||
|
||
await AddFallbackUnitsAsync(templates, result, ct);
|
||
|
||
return result;
|
||
}
|
||
|
||
var targetTagValueId = await _unitInValueRepository.Get()
|
||
.AsNoTracking()
|
||
.Where(uiv => uiv.FieldId == tagField.Id
|
||
&& uiv.Value != null
|
||
&& uiv.Value.Value == UnusedTemplateConstants.NotUsedTagValue)
|
||
.Select(uiv => uiv.ValueId)
|
||
.FirstOrDefaultAsync(ct);
|
||
|
||
if (targetTagValueId == Guid.Empty)
|
||
{
|
||
_logger.LogWarning(
|
||
"Значение '{TagValue}' для поля '{FieldName}' не найдено. Целевой Unit для неиспользуемых шаблонов будет выбран как текущий.",
|
||
UnusedTemplateConstants.NotUsedTagValue,
|
||
UnusedTemplateConstants.ParrTagFieldName);
|
||
|
||
await AddFallbackUnitsAsync(templates, result, ct);
|
||
|
||
return result;
|
||
}
|
||
|
||
var unitIds = templates
|
||
.Select(t => t.UnitId)
|
||
.Distinct()
|
||
.ToList();
|
||
|
||
var unitResponsableAreaValues = await _unitInValueRepository.GetByUnitIdsAndFieldIdsAsync(
|
||
unitIds,
|
||
new List<Guid> { responsableAreaField.Id },
|
||
ct);
|
||
|
||
var unitToResponsableAreaValueMap = unitResponsableAreaValues
|
||
.Where(uiv => uiv.ValueId != Guid.Empty)
|
||
.ToDictionary(uiv => uiv.UnitId, uiv => uiv.ValueId);
|
||
|
||
if (unitToResponsableAreaValueMap.Count == 0)
|
||
{
|
||
_logger.LogDebug(
|
||
"Для юнитов не найдены значения поля '{FieldName}'. Целевой Unit для неиспользуемых шаблонов будет выбран как текущий.",
|
||
UnusedTemplateConstants.ResponsibilityAreaFieldName);
|
||
|
||
await AddFallbackUnitsAsync(templates, result, ct);
|
||
|
||
return result;
|
||
}
|
||
|
||
var distinctResponsableAreaValues = unitToResponsableAreaValueMap.Values
|
||
.Distinct()
|
||
.ToList();
|
||
|
||
var matches = await _unitInValueRepository.Get()
|
||
.AsNoTracking()
|
||
.Where(uiv => uiv.FieldId == responsableAreaField.Id
|
||
&& distinctResponsableAreaValues.Contains(uiv.ValueId))
|
||
.Join(
|
||
_unitInValueRepository.Get()
|
||
.AsNoTracking()
|
||
.Where(t => t.FieldId == tagField.Id && t.ValueId == targetTagValueId),
|
||
responsableArea => responsableArea.UnitId,
|
||
tag => tag.UnitId,
|
||
(responsableArea, tag) => new
|
||
{
|
||
responsableArea.ValueId,
|
||
responsableArea.UnitId
|
||
})
|
||
.ToListAsync(ct);
|
||
|
||
var responsableAreaToTargetUnitMap = matches
|
||
.GroupBy(x => x.ValueId)
|
||
.ToDictionary(g => g.Key, g => g.First().UnitId);
|
||
|
||
var templatesToReload = new Dictionary<Guid, Guid>();
|
||
|
||
foreach (var template in templates)
|
||
{
|
||
if (!unitToResponsableAreaValueMap.TryGetValue(template.UnitId, out var responsableAreaValueId))
|
||
continue;
|
||
|
||
if (!responsableAreaToTargetUnitMap.TryGetValue(responsableAreaValueId, out var targetUnitId))
|
||
continue;
|
||
|
||
if (targetUnitId == Guid.Empty || targetUnitId == template.UnitId)
|
||
continue;
|
||
|
||
templatesToReload[template.Id] = targetUnitId;
|
||
}
|
||
|
||
if (templatesToReload.Count > 0)
|
||
{
|
||
var targetUnitIds = templatesToReload.Values
|
||
.Distinct()
|
||
.ToList();
|
||
|
||
var targetUnits = await _unitRepository.Get()
|
||
.AsNoTracking()
|
||
.Where(u => targetUnitIds.Contains(u.Id))
|
||
.ToDictionaryAsync(u => u.Id, ct);
|
||
|
||
foreach (var kvp in templatesToReload)
|
||
{
|
||
if (targetUnits.TryGetValue(kvp.Value, out var targetUnit))
|
||
{
|
||
result[kvp.Key] = targetUnit;
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning(
|
||
"Не удалось загрузить целевой Unit {TargetUnitId} для шаблона {TemplateId}.",
|
||
kvp.Value,
|
||
kvp.Key);
|
||
}
|
||
}
|
||
}
|
||
|
||
await AddFallbackUnitsAsync(templates, result, ct);
|
||
|
||
return result;
|
||
}
|
||
|
||
private async Task AddFallbackUnitsAsync(
|
||
IReadOnlyCollection<Template> templates,
|
||
Dictionary<Guid, Unit> result,
|
||
CancellationToken ct)
|
||
{
|
||
var missingUnitIds = templates
|
||
.Where(t => !result.ContainsKey(t.Id) && t.UnitId != Guid.Empty)
|
||
.Select(t => t.UnitId)
|
||
.Distinct()
|
||
.ToList();
|
||
|
||
if (missingUnitIds.Count == 0)
|
||
return;
|
||
|
||
var fallbackUnits = await _unitRepository.Get()
|
||
.AsNoTracking()
|
||
.Where(u => missingUnitIds.Contains(u.Id))
|
||
.ToDictionaryAsync(u => u.Id, ct);
|
||
|
||
foreach (var template in templates.Where(t => !result.ContainsKey(t.Id) && t.UnitId != Guid.Empty))
|
||
{
|
||
if (fallbackUnits.TryGetValue(template.UnitId, out var fallbackUnit))
|
||
{
|
||
result[template.Id] = fallbackUnit;
|
||
}
|
||
}
|
||
}
|
||
} |