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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|