| | | 1 | | using System.Globalization; |
| | | 2 | | using OzonOrdersWeb.Areas.Studio2.ViewModels.ApiSupplierSettings; |
| | | 3 | | |
| | | 4 | | namespace OzonOrdersWeb.WebServices.ApiSettingsGrid; |
| | | 5 | | |
| | | 6 | | /// <summary>Вариант выпадающего списка в ячейке значения.</summary> |
| | | 7 | | public 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> |
| | | 13 | | public 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> |
| | | 29 | | public sealed record ApiWarehouseRow(int Id, string Name, bool Selected); |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// Строки грида настроек API-поставщика. Подсказки, курс ЦБ, варианты выбора и типы редакторов считаются здесь, |
| | | 33 | | /// а не во вьюхе, чтобы грид мог сортировать/искать по ним, а разметка не содержала логики. |
| | | 34 | | /// </summary> |
| | | 35 | | public 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 | | { |
| | 20 | 46 | | string? Error(string field) => errors is not null && errors.TryGetValue(field, out var e) ? e : null; |
| | | 47 | | |
| | 4 | 48 | | var suppliers = new List<ApiSettingOption> { new("", "Не связывать с системным поставщиком") }; |
| | 8 | 49 | | suppliers.AddRange(model.Suppliers.Select(s => new ApiSettingOption( |
| | 8 | 50 | | s.Id.ToString(CultureInfo.InvariantCulture), $"{s.Name} ({s.CurrencyCode})"))); |
| | | 51 | | |
| | 4 | 52 | | var currency = model.CurrencyCode.ToString(); |
| | 4 | 53 | | var rate = model.CurrentRateToRub?.ToString("0.####", CultureInfo.CurrentCulture) ?? "недоступен"; |
| | | 54 | | |
| | 4 | 55 | | return new[] |
| | 4 | 56 | | { |
| | 4 | 57 | | new ApiSettingRow(nameof(model.DisplayName), "Название в интерфейсе", "text", model.DisplayName, |
| | 4 | 58 | | "Используется в карточках поставщика, корзине и проценке.", |
| | 4 | 59 | | Error: Error(nameof(model.DisplayName))), |
| | 4 | 60 | | new ApiSettingRow(nameof(model.SupplierId), "Системный поставщик", "select", |
| | 4 | 61 | | model.SupplierId?.ToString(CultureInfo.InvariantCulture) ?? "", |
| | 4 | 62 | | "При клике цены в проценке будет выбран именно этот Supplier.", |
| | 4 | 63 | | Options: suppliers, Error: Error(nameof(model.SupplierId))), |
| | 4 | 64 | | new ApiSettingRow(nameof(model.CurrencyCode), "Валюта цен", "readonly", currency, |
| | 4 | 65 | | currencyHint ?? DefaultCurrencyHint, |
| | 4 | 66 | | Display: currency, Note: $"Курс ЦБ РФ: {rate} RUB за 1 {currency}"), |
| | 4 | 67 | | new ApiSettingRow(nameof(model.IsQuotationEnabled), "Загружать предложения в проценке", "bool", |
| | 4 | 68 | | model.IsQuotationEnabled ? "true" : "false", quotationHint ?? DefaultQuotationHint), |
| | 4 | 69 | | new ApiSettingRow(nameof(model.ExtraDeliveryHours), "Доп. срок поставки", "number", |
| | 4 | 70 | | model.ExtraDeliveryHours.ToString(CultureInfo.InvariantCulture), |
| | 4 | 71 | | "Прибавляется к сроку каждого предложения этого поставщика в проценке. 0 — срок отдаётся как есть. " + |
| | 4 | 72 | | "В таблице предложений срок показывается в днях, округлённых вверх, со значком надбавки.", |
| | 4 | 73 | | Unit: "ч", Min: 0, Max: 720, Error: Error(nameof(model.ExtraDeliveryHours))), |
| | 4 | 74 | | new ApiSettingRow(nameof(model.PriceMultiplier), "Коэффициент цены", "decimal", |
| | 4 | 75 | | model.PriceMultiplier.ToString(CultureInfo.InvariantCulture), |
| | 4 | 76 | | "Умножает себестоимость каждого предложения этого поставщика. Значение 1 сохраняет себестоимость равной |
| | 4 | 77 | | "цена закупки в таблице остаётся исходной в рублях, а себестоимость пересчитывается на коэффициент.", |
| | 4 | 78 | | Unit: "×", Min: 0.0001m, Max: 100, Error: Error(nameof(model.PriceMultiplier))), |
| | 4 | 79 | | new ApiSettingRow(nameof(model.DeliveryAddress), "Адрес доставки", "text", model.DeliveryAddress ?? "", |
| | 4 | 80 | | "Ручное значение имеет приоритет в колонке «Направление» и заменяет адрес, полученный из API. " + |
| | 4 | 81 | | "Изменяется только отображение в Studio2: точка доставки, выбранная у поставщика через API, остаётся пре |
| | 4 | 82 | | Placeholder: "Например: Москва, Ходынский бульвар, 20А", Error: Error(nameof(model.DeliveryAddress))) |
| | 4 | 83 | | }; |
| | | 84 | | } |
| | | 85 | | |
| | | 86 | | public static IReadOnlyList<ApiWarehouseRow> BuildWarehouses(ApiSupplierSettingsViewModelBase model) |
| | | 87 | | { |
| | 1 | 88 | | var selected = model.WarehouseIds.ToHashSet(); |
| | 1 | 89 | | return model.Warehouses |
| | 2 | 90 | | .OrderBy(w => w.Name, StringComparer.CurrentCultureIgnoreCase) |
| | 2 | 91 | | .Select(w => new ApiWarehouseRow(w.Id, w.Name ?? $"ID {w.Id}", selected.Contains(w.Id))) |
| | 1 | 92 | | .ToList(); |
| | | 93 | | } |
| | | 94 | | } |