< Summary

Information
Class: OzonDomains.Nomenclature.ArticleKey
Assembly: OzonDomains
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonDomains/Nomenclature/ArticleKey.cs
Line coverage
100%
Covered lines: 27
Uncovered lines: 0
Coverable lines: 27
Total lines: 81
Line coverage: 100%
Branch coverage
100%
Covered branches: 26
Total branches: 26
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
Key(...)100%1010100%
Variants(...)100%1616100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonDomains/Nomenclature/ArticleKey.cs

#LineLine coverage
 1using System.Globalization;
 2using System.Text;
 3
 4namespace OzonDomains.Nomenclature;
 5
 6/// <summary>Чем получен вариант ключа артикула — от него зависит уверенность совпадения.</summary>
 7public enum ArticleVariantKind
 8{
 9    /// <summary>Убраны ведущие нули: <c>0250603006</c> → <c>250603006</c>.</summary>
 10    StripLeadingZeros,
 11
 12    /// <summary>Добавлен ведущий ноль: <c>31129</c> → <c>031129</c>.</summary>
 13    PadLeadingZero,
 14
 15    /// <summary>Убрана замыкающая буква после цифры: <c>059198405B</c> → <c>059198405</c>.</summary>
 16    DropTrailingLetter
 17}
 18
 19public readonly record struct ArticleVariant(ArticleVariantKind Kind, string Key);
 20
 21/// <summary>
 22/// Ключ поиска артикула: одинаковый для заказа, карты соответствий и запроса к 1С.
 23/// NFKC, снятие диакритики, верхний регистр, только буквы и цифры, свёртка кириллических двойников латиницы
 24/// (в 1С бывают карточки вроде <c>1284971С03</c> с кириллической «С», в заказе та же позиция приходит латиницей).
 25/// </summary>
 26public static class ArticleKey
 27{
 128    private static readonly Dictionary<char, char> Lookalikes = new()
 129    {
 130        ['А'] = 'A', ['В'] = 'B', ['Е'] = 'E', ['К'] = 'K', ['М'] = 'M', ['Н'] = 'H',
 131        ['О'] = 'O', ['Р'] = 'P', ['С'] = 'C', ['Т'] = 'T', ['Х'] = 'X', ['У'] = 'Y'
 132    };
 33
 34    public static string Key(string? value)
 35    {
 160536        if (string.IsNullOrEmpty(value))
 32737            return string.Empty;
 38
 127839        var decomposed = value.Normalize(NormalizationForm.FormKD);
 127840        var sb = new StringBuilder(decomposed.Length);
 1844641        foreach (var ch in decomposed)
 42        {
 794543            if (CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.NonSpacingMark)
 44                continue;
 45
 791046            if (!char.IsLetterOrDigit(ch))
 47                continue;
 48
 770049            var upper = char.ToUpperInvariant(ch);
 770050            sb.Append(Lookalikes.TryGetValue(upper, out var latin) ? latin : upper);
 51        }
 52
 127853        return sb.ToString();
 54    }
 55
 56    /// <summary>
 57    /// Запасные ключи для поиска «похожего» артикула. Применять только вместе с совпавшим брендом:
 58    /// без него один номер без нуля или буквы принадлежит другому товару.
 59    /// </summary>
 60    public static IReadOnlyList<ArticleVariant> Variants(string key)
 61    {
 2162        var result = new List<ArticleVariant>(4);
 2163        if (string.IsNullOrEmpty(key))
 164            return result;
 65
 2066        var stripped = key.TrimStart('0');
 2067        if (stripped.Length >= 3 && stripped.Length != key.Length)
 568            result.Add(new ArticleVariant(ArticleVariantKind.StripLeadingZeros, stripped));
 69
 2070        if (key.Length >= 3 && key[0] != '0')
 71        {
 1572            result.Add(new ArticleVariant(ArticleVariantKind.PadLeadingZero, "0" + key));
 1573            result.Add(new ArticleVariant(ArticleVariantKind.PadLeadingZero, "00" + key));
 74        }
 75
 2076        if (key.Length >= 6 && char.IsLetter(key[^1]) && char.IsDigit(key[^2]))
 277            result.Add(new ArticleVariant(ArticleVariantKind.DropTrailingLetter, key[..^1]));
 78
 2079        return result;
 80    }
 81}