< Summary

Information
Class: OzonOrdersWeb.WebServices.BitrixStock.BitrixSyncGridRequestMapper
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/BitrixStock/BitrixSyncGridRequest.cs
Line coverage
89%
Covered lines: 60
Uncovered lines: 7
Coverable lines: 67
Total lines: 134
Line coverage: 89.5%
Branch coverage
68%
Covered branches: 62
Total branches: 90
Branch coverage: 68.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Validate(...)52.27%1464462.5%
Map(...)85.71%1414100%
MapCondition(...)78.57%1414100%
ReadString(...)83.33%6685.71%
ReadDecimal(...)91.66%1212100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/BitrixStock/BitrixSyncGridRequest.cs

#LineLine coverage
 1using System.Globalization;
 2using System.Text.Json;
 3using OzonOrdersWeb.WebServices.Orders.Grid;
 4using Services.BitrixStockServices;
 5
 6namespace OzonOrdersWeb.WebServices.BitrixStock;
 7
 8/// <summary>Запрос блока строк отчёта синхронизации от AG Grid (Infinite Row Model).</summary>
 9public sealed class BitrixSyncGridRequest
 10{
 11    public int StartRow { get; set; }
 12
 13    public int EndRow { get; set; } = 100;
 14
 15    public List<AgGridSortModelItem> SortModel { get; set; } = [];
 16
 17    public Dictionary<string, AgGridFilterModelItem> FilterModel { get; set; } = new(StringComparer.Ordinal);
 18
 19    public string? Search { get; set; }
 20
 21    public bool ShowZero { get; set; }
 22
 23    public bool OnlyPriceChanged { get; set; }
 24
 25    /// <summary>Отключённые связи складов «clientId|склад 1С|склад Ozon» (галки в «Управление связями»).</summary>
 26    public List<string>? ExcludedMappings { get; set; }
 27
 28    /// <summary>Для счётчиков значений: колонка, по которой считать.</summary>
 29    public string? ColId { get; set; }
 30}
 31
 32/// <summary>
 33/// AG Grid → <see cref="BitrixSyncGridLinesQuery"/>: колонки/операторы вне whitelist
 34/// <see cref="BitrixStockSyncReportGridSql"/> отбрасываются, лимиты проверяются до обращения к БД.
 35/// </summary>
 36public static class BitrixSyncGridRequestMapper
 37{
 38    public static string? Validate(BitrixSyncGridRequest? request)
 39    {
 540        if (request is null) return "Пустой запрос.";
 441        if (request.StartRow < 0 || request.EndRow <= request.StartRow) return "Некорректный диапазон строк.";
 242        if (request.EndRow - request.StartRow > BitrixStockSyncReportGridSql.MaxBlockSize)
 143            return $"Слишком большой блок (максимум {BitrixStockSyncReportGridSql.MaxBlockSize} строк).";
 144        if (request.ExcludedMappings is { Count: > BitrixStockSyncReportGridSql.MaxExcludedMappings })
 045            return "Слишком много отключённых связей складов.";
 146        if (request.Search is { Length: > BitrixStockSyncReportGridSql.MaxTextLength }) return "Слишком длинная строка п
 147        if (request.FilterModel is { Count: > BitrixStockSyncReportGridSql.MaxConditions }) return "Слишком много фильтр
 148        if (request.SortModel is { Count: > BitrixStockSyncReportGridSql.MaxSorts }) return "Слишком много столбцов сорт
 249        foreach (var (colId, item) in request.FilterModel ?? new Dictionary<string, AgGridFilterModelItem>())
 50        {
 051            if (colId.Length > 64) return "Некорректный идентификатор колонки фильтра.";
 052            if (item?.Values is { Count: > BitrixStockSyncReportGridSql.MaxSetValues }) return $"Слишком много значений 
 053            if (item?.Filter is { ValueKind: JsonValueKind.String } f && f.GetString()!.Length > BitrixStockSyncReportGr
 054                return $"Слишком длинное значение фильтра «{colId}».";
 55        }
 56
 157        return null;
 058    }
 59
 60    public static BitrixSyncGridLinesQuery Map(BitrixSyncGridRequest request)
 61    {
 162        var query = new BitrixSyncGridLinesQuery
 163        {
 164            StartRow = request.StartRow,
 165            EndRow = request.EndRow,
 166            Search = request.Search,
 167            ShowZero = request.ShowZero,
 168            OnlyPriceChanged = request.OnlyPriceChanged,
 169            ExcludedMappings = request.ExcludedMappings ?? new List<string>()
 170        };
 71
 672        foreach (var sort in request.SortModel ?? new List<AgGridSortModelItem>())
 73        {
 274            if (!BitrixStockSyncReportGridSql.IsSortable(sort.ColId)) continue;
 175            query.Sorts.Add(new BitrixSyncGridSort
 176            {
 177                ColId = sort.ColId,
 178                Descending = string.Equals(sort.Sort, "desc", StringComparison.OrdinalIgnoreCase)
 179            });
 80        }
 81
 882        foreach (var (colId, item) in request.FilterModel ?? new Dictionary<string, AgGridFilterModelItem>())
 83        {
 384            var condition = MapCondition(colId, item);
 685            if (condition != null) query.Conditions.Add(condition);
 86        }
 87
 188        return query;
 89    }
 90
 91    private static BitrixSyncGridCondition? MapCondition(string colId, AgGridFilterModelItem? item)
 92    {
 393        if (item is null) return null;
 394        var kind = item.FilterType switch
 395        {
 196            "number" => BitrixSyncGridConditionKind.Number,
 197            "set" => BitrixSyncGridConditionKind.Set,
 198            _ => BitrixSyncGridConditionKind.Text
 399        };
 3100        if (!BitrixStockSyncReportGridSql.IsFilterable(colId, kind)) return null;
 101
 3102        return new BitrixSyncGridCondition
 3103        {
 3104            ColId = colId,
 3105            Kind = kind,
 3106            Operator = string.IsNullOrWhiteSpace(item.Type) ? (kind == BitrixSyncGridConditionKind.Number ? "equals" : "
 3107            Text = ReadString(item.Filter),
 3108            Number = ReadDecimal(item.Filter),
 3109            NumberTo = ReadDecimal(item.FilterTo),
 3110            Values = item.Values ?? new List<string>()
 3111        };
 112    }
 113
 114    private static string? ReadString(JsonElement? element)
 115    {
 4116        if (element is not { } e) return null;
 2117        return e.ValueKind switch
 2118        {
 1119            JsonValueKind.String => e.GetString(),
 1120            JsonValueKind.Number => e.GetRawText(),
 0121            _ => null
 2122        };
 123    }
 124
 125    private static decimal? ReadDecimal(JsonElement? element)
 126    {
 9127        if (element is not { } e) return null;
 4128        if (e.ValueKind == JsonValueKind.Number && e.TryGetDecimal(out var number)) return number;
 2129        if (e.ValueKind == JsonValueKind.String
 2130            && decimal.TryParse(e.GetString()?.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out
 1131            return parsed;
 1132        return null;
 133    }
 134}