< Summary

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

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Kind()100%11100%

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
 4319public 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{
 28    private static readonly Dictionary<char, char> Lookalikes = new()
 29    {
 30        ['А'] = 'A', ['В'] = 'B', ['Е'] = 'E', ['К'] = 'K', ['М'] = 'M', ['Н'] = 'H',
 31        ['О'] = 'O', ['Р'] = 'P', ['С'] = 'C', ['Т'] = 'T', ['Х'] = 'X', ['У'] = 'Y'
 32    };
 33
 34    public static string Key(string? value)
 35    {
 36        if (string.IsNullOrEmpty(value))
 37            return string.Empty;
 38
 39        var decomposed = value.Normalize(NormalizationForm.FormKD);
 40        var sb = new StringBuilder(decomposed.Length);
 41        foreach (var ch in decomposed)
 42        {
 43            if (CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.NonSpacingMark)
 44                continue;
 45
 46            if (!char.IsLetterOrDigit(ch))
 47                continue;
 48
 49            var upper = char.ToUpperInvariant(ch);
 50            sb.Append(Lookalikes.TryGetValue(upper, out var latin) ? latin : upper);
 51        }
 52
 53        return sb.ToString();
 54    }
 55
 56    /// <summary>
 57    /// Запасные ключи для поиска «похожего» артикула. Применять только вместе с совпавшим брендом:
 58    /// без него один номер без нуля или буквы принадлежит другому товару.
 59    /// </summary>
 60    public static IReadOnlyList<ArticleVariant> Variants(string key)
 61    {
 62        var result = new List<ArticleVariant>(4);
 63        if (string.IsNullOrEmpty(key))
 64            return result;
 65
 66        var stripped = key.TrimStart('0');
 67        if (stripped.Length >= 3 && stripped.Length != key.Length)
 68            result.Add(new ArticleVariant(ArticleVariantKind.StripLeadingZeros, stripped));
 69
 70        if (key.Length >= 3 && key[0] != '0')
 71        {
 72            result.Add(new ArticleVariant(ArticleVariantKind.PadLeadingZero, "0" + key));
 73            result.Add(new ArticleVariant(ArticleVariantKind.PadLeadingZero, "00" + key));
 74        }
 75
 76        if (key.Length >= 6 && char.IsLetter(key[^1]) && char.IsDigit(key[^2]))
 77            result.Add(new ArticleVariant(ArticleVariantKind.DropTrailingLetter, key[..^1]));
 78
 79        return result;
 80    }
 81}

Methods/Properties

get_Kind()