< Summary

Information
Class: OzonOrdersWeb.WebServices.ApiSettingsGrid.ApiSupplierSettingsGridRows
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/ApiSettingsGrid/ApiSupplierSettingsGridRows.cs
Line coverage
100%
Covered lines: 40
Uncovered lines: 0
Coverable lines: 40
Total lines: 94
Line coverage: 100%
Branch coverage
72%
Covered branches: 16
Total branches: 22
Branch coverage: 72.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Error()100%44100%
Build(...)68.75%1616100%
BuildWarehouses(...)50%22100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/ApiSettingsGrid/ApiSupplierSettingsGridRows.cs

#LineLine coverage
 1using System.Globalization;
 2using OzonOrdersWeb.Areas.Studio2.ViewModels.ApiSupplierSettings;
 3
 4namespace OzonOrdersWeb.WebServices.ApiSettingsGrid;
 5
 6/// <summary>Вариант выпадающего списка в ячейке значения.</summary>
 7public sealed record ApiSettingOption(string Value, string Label);
 8
 9/// <summary>
 10/// Строка грида «параметр — значение» страницы настроек API-поставщика. <c>Field</c> — имя поля формы
 11/// (то, что раньше давал <c>asp-for</c>), <c>Kind</c> — редактор: text | number | decimal | bool | select | readonly.
 12/// </summary>
 13public sealed record ApiSettingRow(
 14    string Field,
 15    string Label,
 16    string Kind,
 17    string Value,
 18    string Hint,
 19    IReadOnlyList<ApiSettingOption>? Options = null,
 20    string? Display = null,
 21    string? Placeholder = null,
 22    string? Unit = null,
 23    decimal? Min = null,
 24    decimal? Max = null,
 25    string? Note = null,
 26    string? Error = null);
 27
 28/// <summary>Строка грида складов поставщика: чекбокс «доступен» вместо списка меток.</summary>
 29public sealed record ApiWarehouseRow(int Id, string Name, bool Selected);
 30
 31/// <summary>
 32/// Строки грида настроек API-поставщика. Подсказки, курс ЦБ, варианты выбора и типы редакторов считаются здесь,
 33/// а не во вьюхе, чтобы грид мог сортировать/искать по ним, а разметка не содержала логики.
 34/// </summary>
 35public static class ApiSupplierSettingsGridRows
 36{
 37    private const string DefaultCurrencyHint = "Валюта берётся из выбранного системного поставщика.";
 38    private const string DefaultQuotationHint = "Отключение исключит поставщика из новых запросов проценки.";
 39
 40    public static IReadOnlyList<ApiSettingRow> Build(
 41        ApiSupplierSettingsViewModelBase model,
 42        string? currencyHint = null,
 43        string? quotationHint = null,
 44        IReadOnlyDictionary<string, string>? errors = null)
 45    {
 2046        string? Error(string field) => errors is not null && errors.TryGetValue(field, out var e) ? e : null;
 47
 448        var suppliers = new List<ApiSettingOption> { new("", "Не связывать с системным поставщиком") };
 849        suppliers.AddRange(model.Suppliers.Select(s => new ApiSettingOption(
 850            s.Id.ToString(CultureInfo.InvariantCulture), $"{s.Name} ({s.CurrencyCode})")));
 51
 452        var currency = model.CurrencyCode.ToString();
 453        var rate = model.CurrentRateToRub?.ToString("0.####", CultureInfo.CurrentCulture) ?? "недоступен";
 54
 455        return new[]
 456        {
 457            new ApiSettingRow(nameof(model.DisplayName), "Название в интерфейсе", "text", model.DisplayName,
 458                "Используется в карточках поставщика, корзине и проценке.",
 459                Error: Error(nameof(model.DisplayName))),
 460            new ApiSettingRow(nameof(model.SupplierId), "Системный поставщик", "select",
 461                model.SupplierId?.ToString(CultureInfo.InvariantCulture) ?? "",
 462                "При клике цены в проценке будет выбран именно этот Supplier.",
 463                Options: suppliers, Error: Error(nameof(model.SupplierId))),
 464            new ApiSettingRow(nameof(model.CurrencyCode), "Валюта цен", "readonly", currency,
 465                currencyHint ?? DefaultCurrencyHint,
 466                Display: currency, Note: $"Курс ЦБ РФ: {rate} RUB за 1 {currency}"),
 467            new ApiSettingRow(nameof(model.IsQuotationEnabled), "Загружать предложения в проценке", "bool",
 468                model.IsQuotationEnabled ? "true" : "false", quotationHint ?? DefaultQuotationHint),
 469            new ApiSettingRow(nameof(model.ExtraDeliveryHours), "Доп. срок поставки", "number",
 470                model.ExtraDeliveryHours.ToString(CultureInfo.InvariantCulture),
 471                "Прибавляется к сроку каждого предложения этого поставщика в проценке. 0 — срок отдаётся как есть. " +
 472                "В таблице предложений срок показывается в днях, округлённых вверх, со значком надбавки.",
 473                Unit: "ч", Min: 0, Max: 720, Error: Error(nameof(model.ExtraDeliveryHours))),
 474            new ApiSettingRow(nameof(model.PriceMultiplier), "Коэффициент цены", "decimal",
 475                model.PriceMultiplier.ToString(CultureInfo.InvariantCulture),
 476                "Умножает себестоимость каждого предложения этого поставщика. Значение 1 сохраняет себестоимость равной 
 477                "цена закупки в таблице остаётся исходной в рублях, а себестоимость пересчитывается на коэффициент.",
 478                Unit: "×", Min: 0.0001m, Max: 100, Error: Error(nameof(model.PriceMultiplier))),
 479            new ApiSettingRow(nameof(model.DeliveryAddress), "Адрес доставки", "text", model.DeliveryAddress ?? "",
 480                "Ручное значение имеет приоритет в колонке «Направление» и заменяет адрес, полученный из API. " +
 481                "Изменяется только отображение в Studio2: точка доставки, выбранная у поставщика через API, остаётся пре
 482                Placeholder: "Например: Москва, Ходынский бульвар, 20А", Error: Error(nameof(model.DeliveryAddress)))
 483        };
 84    }
 85
 86    public static IReadOnlyList<ApiWarehouseRow> BuildWarehouses(ApiSupplierSettingsViewModelBase model)
 87    {
 188        var selected = model.WarehouseIds.ToHashSet();
 189        return model.Warehouses
 290            .OrderBy(w => w.Name, StringComparer.CurrentCultureIgnoreCase)
 291            .Select(w => new ApiWarehouseRow(w.Id, w.Name ?? $"ID {w.Id}", selected.Contains(w.Id)))
 192            .ToList();
 93    }
 94}