< Summary

Information
Class: OzonOrdersWeb.WebServices.BitrixStock.BitrixSyncGridRequest
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/BitrixStock/BitrixSyncGridRequest.cs
Line coverage
88%
Covered lines: 8
Uncovered lines: 1
Coverable lines: 9
Total lines: 134
Line coverage: 88.8%
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_StartRow()100%11100%
get_EndRow()100%11100%
get_SortModel()100%11100%
get_FilterModel()100%11100%
get_Search()100%11100%
get_ShowZero()100%11100%
get_OnlyPriceChanged()100%11100%
get_ExcludedMappings()100%11100%
get_ColId()100%210%

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{
 1311    public int StartRow { get; set; }
 12
 1413    public int EndRow { get; set; } = 100;
 14
 815    public List<AgGridSortModelItem> SortModel { get; set; } = [];
 16
 1017    public Dictionary<string, AgGridFilterModelItem> FilterModel { get; set; } = new(StringComparer.Ordinal);
 18
 319    public string? Search { get; set; }
 20
 221    public bool ShowZero { get; set; }
 22
 123    public bool OnlyPriceChanged { get; set; }
 24
 25    /// <summary>Отключённые связи складов «clientId|склад 1С|склад Ozon» (галки в «Управление связями»).</summary>
 226    public List<string>? ExcludedMappings { get; set; }
 27
 28    /// <summary>Для счётчиков значений: колонка, по которой считать.</summary>
 029    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    {
 40        if (request is null) return "Пустой запрос.";
 41        if (request.StartRow < 0 || request.EndRow <= request.StartRow) return "Некорректный диапазон строк.";
 42        if (request.EndRow - request.StartRow > BitrixStockSyncReportGridSql.MaxBlockSize)
 43            return $"Слишком большой блок (максимум {BitrixStockSyncReportGridSql.MaxBlockSize} строк).";
 44        if (request.ExcludedMappings is { Count: > BitrixStockSyncReportGridSql.MaxExcludedMappings })
 45            return "Слишком много отключённых связей складов.";
 46        if (request.Search is { Length: > BitrixStockSyncReportGridSql.MaxTextLength }) return "Слишком длинная строка п
 47        if (request.FilterModel is { Count: > BitrixStockSyncReportGridSql.MaxConditions }) return "Слишком много фильтр
 48        if (request.SortModel is { Count: > BitrixStockSyncReportGridSql.MaxSorts }) return "Слишком много столбцов сорт
 49        foreach (var (colId, item) in request.FilterModel ?? new Dictionary<string, AgGridFilterModelItem>())
 50        {
 51            if (colId.Length > 64) return "Некорректный идентификатор колонки фильтра.";
 52            if (item?.Values is { Count: > BitrixStockSyncReportGridSql.MaxSetValues }) return $"Слишком много значений 
 53            if (item?.Filter is { ValueKind: JsonValueKind.String } f && f.GetString()!.Length > BitrixStockSyncReportGr
 54                return $"Слишком длинное значение фильтра «{colId}».";
 55        }
 56
 57        return null;
 58    }
 59
 60    public static BitrixSyncGridLinesQuery Map(BitrixSyncGridRequest request)
 61    {
 62        var query = new BitrixSyncGridLinesQuery
 63        {
 64            StartRow = request.StartRow,
 65            EndRow = request.EndRow,
 66            Search = request.Search,
 67            ShowZero = request.ShowZero,
 68            OnlyPriceChanged = request.OnlyPriceChanged,
 69            ExcludedMappings = request.ExcludedMappings ?? new List<string>()
 70        };
 71
 72        foreach (var sort in request.SortModel ?? new List<AgGridSortModelItem>())
 73        {
 74            if (!BitrixStockSyncReportGridSql.IsSortable(sort.ColId)) continue;
 75            query.Sorts.Add(new BitrixSyncGridSort
 76            {
 77                ColId = sort.ColId,
 78                Descending = string.Equals(sort.Sort, "desc", StringComparison.OrdinalIgnoreCase)
 79            });
 80        }
 81
 82        foreach (var (colId, item) in request.FilterModel ?? new Dictionary<string, AgGridFilterModelItem>())
 83        {
 84            var condition = MapCondition(colId, item);
 85            if (condition != null) query.Conditions.Add(condition);
 86        }
 87
 88        return query;
 89    }
 90
 91    private static BitrixSyncGridCondition? MapCondition(string colId, AgGridFilterModelItem? item)
 92    {
 93        if (item is null) return null;
 94        var kind = item.FilterType switch
 95        {
 96            "number" => BitrixSyncGridConditionKind.Number,
 97            "set" => BitrixSyncGridConditionKind.Set,
 98            _ => BitrixSyncGridConditionKind.Text
 99        };
 100        if (!BitrixStockSyncReportGridSql.IsFilterable(colId, kind)) return null;
 101
 102        return new BitrixSyncGridCondition
 103        {
 104            ColId = colId,
 105            Kind = kind,
 106            Operator = string.IsNullOrWhiteSpace(item.Type) ? (kind == BitrixSyncGridConditionKind.Number ? "equals" : "
 107            Text = ReadString(item.Filter),
 108            Number = ReadDecimal(item.Filter),
 109            NumberTo = ReadDecimal(item.FilterTo),
 110            Values = item.Values ?? new List<string>()
 111        };
 112    }
 113
 114    private static string? ReadString(JsonElement? element)
 115    {
 116        if (element is not { } e) return null;
 117        return e.ValueKind switch
 118        {
 119            JsonValueKind.String => e.GetString(),
 120            JsonValueKind.Number => e.GetRawText(),
 121            _ => null
 122        };
 123    }
 124
 125    private static decimal? ReadDecimal(JsonElement? element)
 126    {
 127        if (element is not { } e) return null;
 128        if (e.ValueKind == JsonValueKind.Number && e.TryGetDecimal(out var number)) return number;
 129        if (e.ValueKind == JsonValueKind.String
 130            && decimal.TryParse(e.GetString()?.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out
 131            return parsed;
 132        return null;
 133    }
 134}