| | | 1 | | namespace OzonOrdersWeb.WebServices.Sidebar; |
| | | 2 | | |
| | | 3 | | /// <summary>Строка грида навигации /Studio2/Home: пункт меню с группой, подгруппой и назначением.</summary> |
| | | 4 | | public sealed record NavigationPageRow( |
| | | 5 | | string Id, |
| | | 6 | | int Order, |
| | | 7 | | string Title, |
| | | 8 | | string Icon, |
| | | 9 | | string Href, |
| | | 10 | | bool External, |
| | | 11 | | string Group, |
| | | 12 | | string GroupIcon, |
| | | 13 | | string? Subgroup, |
| | | 14 | | string Description, |
| | | 15 | | string? Keywords); |
| | | 16 | | |
| | | 17 | | /// <summary> |
| | | 18 | | /// Грид навигации Studio2 (/Studio2/Home) из того же дерева, что боковое меню (<see cref="SidebarNavigationCatalog"/>): |
| | | 19 | | /// один пункт — одна строка с назначением раздела. Пункт с адресом, который уже встречался выше, не повторяется. |
| | | 20 | | /// </summary> |
| | | 21 | | public static class NavigationPageRows |
| | | 22 | | { |
| | | 23 | | /// <summary>Назначение разделов: что делают на странице. Ключ — id пункта меню (тест проверяет полноту).</summary> |
| | 1 | 24 | | public static readonly IReadOnlyDictionary<string, string> Descriptions = new Dictionary<string, string>(StringCompa |
| | 1 | 25 | | { |
| | 1 | 26 | | ["orders.grid"] = "Все заказы в одной бесконечной таблице: фильтры и сортировка по всему набору, групповые дейст |
| | 1 | 27 | | ["orders.list"] = "Классический список заказов с карточкой заказа, фильтрами и задачами контроля.", |
| | 1 | 28 | | ["orders.upload.api"] = "Загрузка новых заказов из API маркетплейсов или из файла выгрузки.", |
| | 1 | 29 | | ["orders.upload.file"] = "Импорт заказов только из файла (Excel/CSV) по сохранённому сопоставлению колонок.", |
| | 1 | 30 | | ["orders.upload.percentage"] = "Загрузка отчёта Ozon для проценки: расчёт цен и наценки по позициям.", |
| | 1 | 31 | | ["orders.history"] = "История изменений заказа: поля, транзакции, расчёты, проценки, движения 1С.", |
| | 1 | 32 | | ["orders.control"] = "Заказы, требующие действий по правилам SLA: просрочки и зависшие статусы.", |
| | 1 | 33 | | ["orders.labels"] = "Печать этикеток Ozon для отправлений.", |
| | 1 | 34 | | ["orders.assembly"] = "Лист подбора для склада: что собрать и откуда.", |
| | 1 | 35 | | ["orders.assembly.keys"] = "Ключи внешнего доступа к листам подбора без входа в Studio2.", |
| | 1 | 36 | | ["orders.transactions"] = "Журнал проведённых документов по заказам (транзакции) с фильтрами и печатью.", |
| | 1 | 37 | | ["orders.transaction.jobs"] = "Фоновые задания проведения транзакций: очередь, статус и ошибки.", |
| | 1 | 38 | | ["orders.time.tracking"] = "Отчёт о времени между этапами обработки заказов.", |
| | 1 | 39 | | ["orders.archive"] = "Архивные заказы: поиск и возврат из архива.", |
| | 1 | 40 | | ["orders.returns.ozon"] = "Возвраты Ozon: акты, статусы и связь с заказами.", |
| | 1 | 41 | | ["orders.returns.journal"] = "Журнал оформленных возвратов по заказам.", |
| | 1 | 42 | | ["orders.returns.ozon.external"] = "Внешний сервис обработки возвратов Ozon (открывается в новой вкладке).", |
| | 1 | 43 | | ["purchases.cart"] = "Корзины и заказы API-поставщиков: проверка, оформление и статусы.", |
| | 1 | 44 | | ["purchases.bitrix.stock"] = "Синхронизация остатков 1С → Bitrix → Ozon: запуски, отчёты, исключения.", |
| | 1 | 45 | | ["settlements"] = "Взаиморасчёты с поставщиками: сальдо, документы, фактуры и их позиции по каждому поставщику." |
| | 1 | 46 | | ["purchases.warehouse.stock"] = "Остатки собственного склада и движение товара.", |
| | 1 | 47 | | ["purchases.onec.stock"] = "Остатки номенклатуры по складам 1С, давность поступления и залежавшийся товар.", |
| | 1 | 48 | | ["purchases.match.files"] = "Сравнение двух файлов прайсов или выгрузок по артикулам.", |
| | 1 | 49 | | ["purchases.interparts.currency"] = "Курсы валют Interparts для пересчёта закупочных цен.", |
| | 1 | 50 | | ["purchases.interparts.access"] = "Какие склады Interparts доступны для заказа и проценки.", |
| | 1 | 51 | | ["analytics.products"] = "Аналитика продаж и оборачиваемости товаров.", |
| | 1 | 52 | | ["analytics.prices"] = "История изменения цен товаров во времени.", |
| | 1 | 53 | | ["analytics.ozon.chat"] = "Переписка с покупателями Ozon: чаты и непрочитанные сообщения.", |
| | 1 | 54 | | ["analytics.ai"] = "AI-ассистент: вопросы по заказам и данным Studio2 на естественном языке.", |
| | 1 | 55 | | ["integrations.onec.fresh"] = "Работа с 1С Fresh: документы, номенклатура и проведение.", |
| | 1 | 56 | | ["integrations.onec.m2"] = "Внешний проект М2 в 1С (открывается в новой вкладке).", |
| | 1 | 57 | | ["integrations.mail.results"] = "Результаты импорта заказов из почтовых вложений.", |
| | 1 | 58 | | ["integrations.mail.rules"] = "Правила разбора писем: отправители, файлы и сопоставления для импорта.", |
| | 1 | 59 | | ["integrations.mail.scheduler"] = "Расписание проверки почты и автоматического импорта.", |
| | 1 | 60 | | ["integrations.files.records"] = "Журнал загруженных файлов и результат их обработки.", |
| | 1 | 61 | | ["integrations.files.mappings"] = "Сопоставления колонок Excel/CSV с полями заказа для импорта.", |
| | 1 | 62 | | ["integrations.feeds.stat"] = "Статистика товарных фидов: выгрузки, ошибки и аномалии.", |
| | 1 | 63 | | ["integrations.feeds.links"] = "Связи поставщиков с фидом: чей товар попадает в выгрузку.", |
| | 1 | 64 | | ["integrations.ozon.webhooks"] = "Входящие push-уведомления Ozon и результат их обработки.", |
| | 1 | 65 | | ["integrations.ozon.clients"] = "Кабинеты Ozon: ключи API, настройки и статусы клиентов.", |
| | 1 | 66 | | ["integrations.suppliers.settings"] = "Ключи и параметры API-поставщиков: склады, адреса доставки, наценки.", |
| | 1 | 67 | | ["integrations.suppliers.audit"] = "Журнал запросов к API поставщиков: ответы, ошибки, время.", |
| | 1 | 68 | | ["integrations.suppliers.consoles"] = "Ручные запросы к API поставщиков: поиск, корзина, заказы.", |
| | 1 | 69 | | ["catalogs.products"] = "Справочник товаров: артикулы, производители, карточки.", |
| | 1 | 70 | | ["catalogs.suppliers"] = "Поставщики: коэффициенты цен, валюта, сроки и связь с контрагентом 1С.", |
| | 1 | 71 | | ["catalogs.manufacturers"] = "Производители Ozon и их сопоставление с брендами.", |
| | 1 | 72 | | ["catalogs.producers"] = "Производители ET и их синонимы.", |
| | 1 | 73 | | ["catalogs.excluded.articles"] = "Артикулы, исключённые из проценки и выгрузок.", |
| | 1 | 74 | | ["catalogs.warehouse"] = "Склады отгрузки Studio2 и их параметры.", |
| | 1 | 75 | | ["catalogs.warehouse.mapping"] = "Связи складов Studio2 с поставщиками, 1С и маркетплейсами.", |
| | 1 | 76 | | ["catalogs.warehouse.excluded"] = "Склады Bitrix, не участвующие в синхронизации остатков.", |
| | 1 | 77 | | ["catalogs.status.app"] = "Статусы заказов Studio2: названия, цвета и порядок.", |
| | 1 | 78 | | ["catalogs.status.transitions"] = "Разрешённые переходы между статусами и их условия.", |
| | 1 | 79 | | ["catalogs.status.supplier"] = "Статусы заказов у поставщиков и их соответствие статусам Studio2.", |
| | 1 | 80 | | ["catalogs.status.client"] = "Статусы клиентов Ozon для отчётов и фильтров.", |
| | 1 | 81 | | ["catalogs.expense.types"] = "Типы расходов для учёта затрат по заказам.", |
| | 1 | 82 | | ["admin.center"] = "Раздел администрирования: роли, пользователи, права и журнал изменений.", |
| | 1 | 83 | | ["admin.access.profiles"] = "Профили доступа пользователей Studio2.", |
| | 1 | 84 | | ["admin.data.scopes"] = "Наборы данных: ограничение видимых записей для ролей и пользователей.", |
| | 1 | 85 | | ["admin.partners"] = "Партнёры: учётные записи, правила видимости заказов, возможности, уведомления и журнал дей |
| | 1 | 86 | | ["admin.job.logs"] = "Журнал фоновых задач: запуски, проведения 1С, вебхуки, импорт.", |
| | 1 | 87 | | ["admin.config"] = "Конфигурация приложения и подключения к базе данных.", |
| | 1 | 88 | | ["system.hangfire.stats"] = "Статистика очередей Hangfire: нагрузка и ошибки фоновых задач.", |
| | 1 | 89 | | ["system.hangfire"] = "Панель Hangfire: задачи, повторы и расписания (открывается в новой вкладке).", |
| | 1 | 90 | | ["system.autoload"] = "Расписания автозагрузки заказов и остатков." |
| | 1 | 91 | | }; |
| | | 92 | | |
| | | 93 | | public static IReadOnlyList<NavigationPageRow> Build(IReadOnlyList<SidebarNode> tree) |
| | | 94 | | { |
| | 2 | 95 | | var rows = new List<NavigationPageRow>(); |
| | 2 | 96 | | var seenHrefs = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
| | 16 | 97 | | foreach (var group in tree) |
| | | 98 | | { |
| | 60 | 99 | | foreach (var node in group.Children ?? []) |
| | | 100 | | { |
| | 24 | 101 | | if (node.IsLeaf) |
| | | 102 | | { |
| | 14 | 103 | | Add(node, group, null); |
| | 14 | 104 | | continue; |
| | | 105 | | } |
| | 82 | 106 | | foreach (var leaf in node.Children ?? []) |
| | 62 | 107 | | if (leaf.IsLeaf) Add(leaf, group, node.Title); |
| | | 108 | | } |
| | | 109 | | } |
| | 2 | 110 | | return rows; |
| | | 111 | | |
| | | 112 | | void Add(SidebarNode leaf, SidebarNode group, string? subgroup) |
| | | 113 | | { |
| | 46 | 114 | | if (!seenHrefs.Add(leaf.Href!)) return; |
| | 44 | 115 | | rows.Add(new NavigationPageRow( |
| | 44 | 116 | | leaf.Id, rows.Count, leaf.Title, leaf.Icon, leaf.Href!, leaf.External, |
| | 44 | 117 | | group.Title, group.Icon, subgroup, |
| | 44 | 118 | | Descriptions.TryGetValue(leaf.Id, out var description) ? description : string.Empty, |
| | 44 | 119 | | leaf.Keywords)); |
| | 44 | 120 | | } |
| | | 121 | | } |
| | | 122 | | } |