Files
Ai/TrafagSalesExporter/Services/StandorteSapEditorService.cs
2026-04-17 13:56:41 +02:00

241 lines
10 KiB
C#

using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IStandorteSapEditorService
{
void AddSapSource(List<SapSourceDefinition> sapSources, List<string> sapEntitySetsCache);
void RemoveSapSource(List<SapSourceDefinition> sapSources, SapSourceDefinition source);
void AddSapJoin(List<SapJoinDefinition> sapJoins);
SapAutoMatchResult AutoMatchSapJoins(List<SapSourceDefinition> sapSources, List<SapJoinDefinition> sapJoins, Dictionary<string, List<string>> sapSourceFieldMap);
void RemoveSapJoin(List<SapJoinDefinition> sapJoins, SapJoinDefinition join);
void AddSapMapping(List<SapFieldMapping> sapMappings, IReadOnlyList<string> salesRecordFields, List<string> sapAvailableSourceExpressions);
void RemoveSapMapping(List<SapFieldMapping> sapMappings, SapFieldMapping mapping);
List<string> BuildSourceExpressionsFromMappings(List<SapFieldMapping> sapMappings);
Dictionary<string, List<string>> BuildSourceFieldMapFromJoins(List<SapJoinDefinition> sapJoins);
IEnumerable<string> GetSapAliases(List<SapSourceDefinition> sapSources);
IEnumerable<string> GetAvailableSourceExpressions(List<string> sapAvailableSourceExpressions, string? currentValue);
IEnumerable<string> GetAvailableJoinFields(Dictionary<string, List<string>> sapSourceFieldMap, string? alias, string? currentKeys);
void NormalizeSapConfigCollections(List<SapSourceDefinition> sapSources, List<SapJoinDefinition> sapJoins, List<SapFieldMapping> sapMappings);
}
public sealed class StandorteSapEditorService : IStandorteSapEditorService
{
public void AddSapSource(List<SapSourceDefinition> sapSources, List<string> sapEntitySetsCache)
{
sapSources.Add(new SapSourceDefinition
{
Alias = $"SRC{sapSources.Count + 1}",
EntitySet = sapEntitySetsCache.FirstOrDefault() ?? string.Empty,
IsActive = true,
IsPrimary = sapSources.Count == 0,
SortOrder = sapSources.Count
});
}
public void RemoveSapSource(List<SapSourceDefinition> sapSources, SapSourceDefinition source)
=> sapSources.Remove(source);
public void AddSapJoin(List<SapJoinDefinition> sapJoins)
{
sapJoins.Add(new SapJoinDefinition
{
JoinType = "Left",
IsActive = true,
SortOrder = sapJoins.Count
});
}
public SapAutoMatchResult AutoMatchSapJoins(List<SapSourceDefinition> sapSources, List<SapJoinDefinition> sapJoins, Dictionary<string, List<string>> sapSourceFieldMap)
{
var activeSources = sapSources
.Where(s => s.IsActive && !string.IsNullOrWhiteSpace(s.Alias))
.OrderBy(s => s.SortOrder)
.ThenBy(s => s.Id)
.ToList();
if (activeSources.Count < 2)
return SapAutoMatchResult.WarningResult("Fuer Auto-Match werden mindestens zwei aktive SAP-Quellen benoetigt.");
if (sapSourceFieldMap.Count == 0)
return SapAutoMatchResult.WarningResult("Bitte zuerst 'Felder aus Quellen laden' ausfuehren.");
var primary = activeSources.FirstOrDefault(s => s.IsPrimary) ?? activeSources.First();
var createdOrUpdated = 0;
foreach (var source in activeSources.Where(s => !string.Equals(s.Alias, primary.Alias, StringComparison.OrdinalIgnoreCase)))
{
if (!sapSourceFieldMap.TryGetValue(primary.Alias, out var leftFields) || leftFields.Count == 0)
continue;
if (!sapSourceFieldMap.TryGetValue(source.Alias, out var rightFields) || rightFields.Count == 0)
continue;
var matchingFields = leftFields
.Intersect(rightFields, StringComparer.OrdinalIgnoreCase)
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.ToList();
if (matchingFields.Count == 0)
continue;
var existingJoin = sapJoins.FirstOrDefault(j =>
string.Equals(j.LeftAlias, primary.Alias, StringComparison.OrdinalIgnoreCase) &&
string.Equals(j.RightAlias, source.Alias, StringComparison.OrdinalIgnoreCase));
var keyList = string.Join(',', matchingFields);
if (existingJoin is null)
{
sapJoins.Add(new SapJoinDefinition
{
LeftAlias = primary.Alias,
RightAlias = source.Alias,
LeftKeys = keyList,
RightKeys = keyList,
JoinType = "Left",
IsActive = true,
SortOrder = sapJoins.Count
});
}
else
{
existingJoin.LeftKeys = keyList;
existingJoin.RightKeys = keyList;
existingJoin.JoinType = "Left";
existingJoin.IsActive = true;
}
createdOrUpdated++;
}
if (createdOrUpdated == 0)
return SapAutoMatchResult.InfoResult("Kein passender Join-Vorschlag gefunden.");
NormalizeSapConfigCollections(sapSources, sapJoins, []);
return SapAutoMatchResult.SuccessResult($"{createdOrUpdated} Join-Vorschlaege gesetzt.");
}
public void RemoveSapJoin(List<SapJoinDefinition> sapJoins, SapJoinDefinition join)
=> sapJoins.Remove(join);
public void AddSapMapping(List<SapFieldMapping> sapMappings, IReadOnlyList<string> salesRecordFields, List<string> sapAvailableSourceExpressions)
{
sapMappings.Add(new SapFieldMapping
{
TargetField = salesRecordFields.First(),
SourceExpression = sapAvailableSourceExpressions.FirstOrDefault() ?? "=SAP",
IsActive = true,
SortOrder = sapMappings.Count
});
}
public void RemoveSapMapping(List<SapFieldMapping> sapMappings, SapFieldMapping mapping)
=> sapMappings.Remove(mapping);
public List<string> BuildSourceExpressionsFromMappings(List<SapFieldMapping> sapMappings)
=> sapMappings
.Select(m => m.SourceExpression)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.ToList();
public Dictionary<string, List<string>> BuildSourceFieldMapFromJoins(List<SapJoinDefinition> sapJoins)
{
var result = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
foreach (var join in sapJoins)
{
AddJoinKeysToFieldMap(result, join.LeftAlias, join.LeftKeys);
AddJoinKeysToFieldMap(result, join.RightAlias, join.RightKeys);
}
return result;
}
public IEnumerable<string> GetSapAliases(List<SapSourceDefinition> sapSources)
=> sapSources.Where(s => !string.IsNullOrWhiteSpace(s.Alias)).Select(s => s.Alias).Distinct(StringComparer.OrdinalIgnoreCase);
public IEnumerable<string> GetAvailableSourceExpressions(List<string> sapAvailableSourceExpressions, string? currentValue)
{
var expressions = new List<string>(sapAvailableSourceExpressions);
if (!string.IsNullOrWhiteSpace(currentValue) && !expressions.Contains(currentValue, StringComparer.OrdinalIgnoreCase))
expressions.Insert(0, currentValue);
return expressions;
}
public IEnumerable<string> GetAvailableJoinFields(Dictionary<string, List<string>> sapSourceFieldMap, string? alias, string? currentKeys)
{
var values = new List<string>();
if (!string.IsNullOrWhiteSpace(alias) && sapSourceFieldMap.TryGetValue(alias, out var fields))
values.AddRange(fields);
foreach (var key in GetSelectedJoinKeys(currentKeys))
{
if (!values.Contains(key, StringComparer.OrdinalIgnoreCase))
values.Add(key);
}
return values
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.ToList();
}
public void NormalizeSapConfigCollections(List<SapSourceDefinition> sapSources, List<SapJoinDefinition> sapJoins, List<SapFieldMapping> sapMappings)
{
for (var i = 0; i < sapSources.Count; i++)
sapSources[i].SortOrder = i;
for (var i = 0; i < sapJoins.Count; i++)
sapJoins[i].SortOrder = i;
for (var i = 0; i < sapMappings.Count; i++)
sapMappings[i].SortOrder = i;
var selectedPrimaryIndex = sapSources.FindIndex(s => s.IsPrimary);
var primarySource = selectedPrimaryIndex >= 0 ? sapSources[selectedPrimaryIndex] : sapSources.FirstOrDefault();
foreach (var source in sapSources)
source.IsPrimary = primarySource is not null && ReferenceEquals(source, primarySource);
if (sapSources.Count > 0 && sapSources.All(s => !s.IsPrimary))
sapSources[0].IsPrimary = true;
}
private static void AddJoinKeysToFieldMap(Dictionary<string, List<string>> target, string alias, string keys)
{
if (string.IsNullOrWhiteSpace(alias))
return;
if (!target.TryGetValue(alias, out var fields))
{
fields = [];
target[alias] = fields;
}
foreach (var key in GetSelectedJoinKeys(keys))
{
if (!fields.Contains(key, StringComparer.OrdinalIgnoreCase))
fields.Add(key);
}
fields.Sort(StringComparer.OrdinalIgnoreCase);
}
private static HashSet<string> GetSelectedJoinKeys(string? keys)
=> keys?
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToHashSet(StringComparer.OrdinalIgnoreCase)
?? [];
}
public sealed class SapAutoMatchResult
{
public bool Success { get; init; }
public bool Warning { get; init; }
public bool Info { get; init; }
public string Message { get; init; } = string.Empty;
public static SapAutoMatchResult WarningResult(string message) => new() { Warning = true, Message = message };
public static SapAutoMatchResult InfoResult(string message) => new() { Info = true, Message = message };
public static SapAutoMatchResult SuccessResult(string message) => new() { Success = true, Message = message };
}