< Summary

Information
Class: Services.StockSyncServices.WarehouseStockLookupMatcher
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/StockSyncServices/WarehouseStockLookupMatcher.cs
Line coverage
96%
Covered lines: 25
Uncovered lines: 1
Coverable lines: 26
Total lines: 59
Line coverage: 96.1%
Branch coverage
90%
Covered branches: 18
Total branches: 20
Branch coverage: 90%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Normalize(...)100%22100%
FindMatch(...)88.88%181895.83%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/StockSyncServices/WarehouseStockLookupMatcher.cs

#LineLine coverage
 1namespace Services.StockSyncServices;
 2
 3public sealed class MatchResult<T> where T : class
 4{
 5    public T Item { get; init; } = null!;
 6    public bool ManufacturerMatched { get; init; }
 7}
 8
 9/// <summary>
 10/// Сопоставление артикула заказа со строкой WarehouseStock (exact → prefix).
 11/// </summary>
 12public static class WarehouseStockLookupMatcher
 13{
 14    public static string Normalize(string? s) =>
 6215        string.IsNullOrEmpty(s) ? "" :
 6216        new string(s.Where(char.IsLetterOrDigit).ToArray()).ToUpperInvariant();
 17
 18    public static MatchResult<T>? FindMatch<T>(
 19        IEnumerable<T> candidates,
 20        string normalizedArticle,
 21        string normalizedManufacturer,
 22        Func<T, string?> getArticle,
 23        Func<T, string?> getManufacturer) where T : class
 24    {
 1625        var list = candidates.ToList();
 1626        if (list.Count == 0 || string.IsNullOrEmpty(normalizedArticle))
 227            return null;
 28
 29        bool ManufacturerMatches(T item) =>
 30            string.IsNullOrEmpty(normalizedManufacturer) ||
 31            Normalize(getManufacturer(item)) == normalizedManufacturer;
 32
 1433        var scoped = list.Where(ManufacturerMatches).ToList();
 1434        var manufacturerMatched = scoped.Count > 0;
 1435        if (scoped.Count == 0)
 236            scoped = list;
 1437        if (scoped.Count == 0)
 038            return null;
 39
 2940        var exact = scoped.FirstOrDefault(x => Normalize(getArticle(x)) == normalizedArticle);
 1441        if (exact != null)
 442            return new MatchResult<T> { Item = exact, ManufacturerMatched = manufacturerMatched };
 43
 1044        var prefixMatches = scoped
 1145            .Select(x => (Item: x, Norm: Normalize(getArticle(x))))
 1146            .Where(t => t.Norm.StartsWith(normalizedArticle, StringComparison.Ordinal) ||
 1147                        normalizedArticle.StartsWith(t.Norm, StringComparison.Ordinal))
 1148            .OrderBy(t => t.Norm.StartsWith(normalizedArticle, StringComparison.Ordinal) ? 0 : 1)
 1149            .ThenBy(t => Math.Abs(t.Norm.Length - normalizedArticle.Length))
 1150            .ThenBy(t => t.Norm.Length)
 1151            .Select(t => t.Item)
 1052            .ToList();
 53
 1054        if (prefixMatches.Count == 1)
 955            return new MatchResult<T> { Item = prefixMatches[0], ManufacturerMatched = manufacturerMatched };
 56
 157        return null;
 58    }
 59}