diff --git a/этрн.md b/этрн.md new file mode 100644 index 0000000..a9c4573 --- /dev/null +++ b/этрн.md @@ -0,0 +1,251 @@ +# ТЗ на доработку: оптимизация создания и обработки ЭТрН + +**Дата:** 07.10.2026 +**Конфигурация:** ВесоваяАК (`ves2020`) +**Версия конфигурации (на момент анализа):** 0.0.3.21 +**Область:** контур электронных транспортных накладных (ЭТрН / ЭПД, API Санадор) +**Тип работ:** оптимизация производительности без изменения бизнес-смысла процесса + +Документ сформирован по результатам анализа исходников. Правки в конфигурацию этим документом не вносятся. + +--- + +## 1. Цель и критерии успеха + +### 1.1. Цель + +Сократить время и нагрузку на СУБД/сеть при регламентной обработке очереди ЭТрН и при сборке payload титулов Т1/Т3, сохранив текущую модель: + +- проведение документов **не** обращается к внешнему API; +- создание/отправка ЭТрН выполняется роботом `ак_ЭТрНРобот` по очереди в регистре `ак_СтатусыДокументовЭПД`; +- опросы статусов остаются пакетными по организации. + +### 1.2. Критерии приёмки + +| № | Критерий | Как проверить | +|---|----------|---------------| +| К1 | Один проход РЗ с той же порцией новых документов укладывается в бюджет времени стабильнее (меньше срабатываний «Исчерпан бюджет времени») | Журнал регистрации события робота до/после на сопоставимой нагрузке | +| К2 | Запросы выборки очереди (`ДобавитьНовые` / `ДобавитьОпросы` / подсчёт неудач) не сканируют лишнюю историю без необходимости | План запроса / замер времени на тестовой ИБ с наполненным регистром | +| К3 | На одну отправку Т1 уменьшено число точечных запросов к ИБ (адреса, телефоны, КИ, ТС и т.п.) | Сравнение числа запросов на документ в отладке / технологическом журнале | +| К4 | Повторные чтения параметров авторизации ЭПД и создание нового HTTP-соединения на каждый вызов устранены или сведены к минимуму в рамках порции | Код-ревью + замер latency порции | +| К5 | Поиск перевозки для Т3 без uuid не выполняет отдельный HTTP-запрос на каждый документ при одинаковых ключах поиска | Код-ревью сценария «только Т3» | +| К6 | Поведение статусов, идемпотентность перепроведения и запрет повторной отправки Т1 при наличии uuid **не нарушены** | Регрессионные сценарии §6 | + +Нефункционально: изменения обратимы, без «тихих» смен контракта API Санадора. + +--- + +## 2. Текущая архитектура (as-is) + +### 2.1. Поток + +```text +Проведение (5 видов документов) + ↓ +ак_ЭТрНРобот.ЗарегистрироватьПриПроведении + ↓ +РС ак_СтатусыДокументовЭПД («К отправке» / «Не требуется») + ↓ +РЗ ак_ОбработкаОчередиЭТрН → ак_ЭТрНРобот.ОбработатьОчередь + ↓ +ак_ЭТрНОтправка (Т1 / Т3) ← ак_ЭТрНФормированиеТитулов ← ак_ЭТрНДанные + ↓ +ак_ПолучениеДанныхЭПД (синхронный HTTPS к Санадору) +``` + +### 2.2. Ключевые объекты + +| Объект | Назначение | +|--------|------------| +| `ОбщийМодуль.ак_ЭТрНРобот` | Регистрация при проведении, очередь, регламент | +| `ОбщийМодуль.ак_ЭТрНОтправка` | Сборка + отправка Т1/Т3, запись статусов | +| `ОбщийМодуль.ак_ЭТрНФормированиеТитулов` | Payload титулов для API | +| `ОбщийМодуль.ак_ЭТрНДанные` | Запросы к ИБ, `КешДанных` | +| `ОбщийМодуль.ак_ЭТрНКлиентСервер` / `ак_ЭТрНПовтИсп` | Контекст, статусы, константы | +| `ОбщийМодуль.ак_ПолучениеДанныхЭПД` | HTTP к API ЭПД | +| `РС.ак_СтатусыДокументовЭПД` | Очередь и история статусов (период — секунда) | +| `РС.ак_УчетныеЗаписиЭПД`, `ак_АбонентыЭПД` | Учётные записи / абоненты | +| `РЗ.ак_ОбработкаОчередиЭТрН` | Метод: `ак_ЭТрНРобот.ОбработатьОчередь` | +| `Обработка.ак_ВыбывшиеДокументыЭТрН` | РМ по застрявшим документам | + +Документы-основания: `РасходнаяНакладная`, `РасходПоСкладу`, `ПеремещениеСПоляНаЭлеватор`, `ПриходПоВесовой`, `ПриходПоСкладу`. + +Отдельного документа «Электронная транспортная накладная» в конфигурации нет: ЭТрН создаётся во внешнем сервисе. + +### 2.3. Что уже сделано удачно (не ломать) + +- Проведение не ходит в сеть. +- Разделение очередей «новые» / «опросы» по наличию `ИдентификаторСанадор` (защита от повторного Т1). +- Пакетный опрос статусов по организации (порции uuid). +- Раздельные лимиты порций новых и опросов, мягкий бюджет времени. +- `КешДанных` на порцию (часть идентификаторов / auth / организация по контрагенту). +- Ключ регламентного задания против параллельного запуска. + +--- + +## 3. Проблемы (на основании анализа кода) + +| ID | Проблема | Где | Влияние | +|----|----------|-----|---------| +| P1 | Синхронный HTTP в цикле по документам порции; каждое соединение создаётся заново | `ОбработатьОчередь` → отправка → `ак_ПолучениеДанныхЭПД.ОтправитьHTTPЗапрос` | Основной риск исчерпания бюджета 300 с | +| P2 | Auth (`ак_УчетныеЗаписиЭПД`) читается на каждый HTTP; кэш робота HTTP-слоем не используется | `ВызватьHTTPМетод` | Лишние обращения к РС на каждый вызов | +| P3 | `СрезПоследних` без отбора по измерениям; итоги среза последних выключены; `ВТ_Неудачи` сканирует историю по регистру | `ДобавитьНовые`, `ДобавитьОпросы`, `ТекстВременнойТаблицыНеудач` | Рост стоимости РЗ с объёмом истории | +| P4 | Фильтрация статусов по `.Наименование` (строка) | Запросы робота | Хуже для индексации/планов, хрупкость | +| P5 | Много точечных запросов на сборку одного Т1 | `ак_ЭТрНДанные` + `ак_ЭТрНФормированиеТитулов` | Нагрузка на СУБД пропорционально порции × полям | +| P6 | Поиск Т3 без uuid: HTTP-список АРМ на каждый документ | `ак_ЭТрНОтправка.ПеревозкаВСервисе` | Лишние сетевые вызовы при сценарии «только Т3» | +| P7 | Мелкие накладные: ИНН через точечные чтения; `Метаданные.НайтиПоТипу` в цикле РМ | `ПеревозкаСторонняя`, `ДокументыСОшибками` | Вторичный эффект | + +--- + +## 4. Объём доработки (to-be) + +Работы разбиты на этапы. Этапы можно сдавать отдельно при сохранении критериев §1.2 для затронутой части. + +### Этап A — очередь и регистр статусов (P3, P4) — приоритет 1 + +**Задачи** + +1. Оценить и при положительном результате **включить итоги среза последних** у `ак_СтатусыДокументовЭПД` (сейчас `EnableTotalsSliceLast = false`). Зафиксировать влияние на запись статусов и объём ИБ. +2. Переработать выборку кандидатов очереди: + - не строить полный срез «всего регистра», если достаточно отбора по активным статусам / отдельной структуре очереди; + - подсчёт неудач (`ВТ_Неудачи`) ограничить документами-кандидатами текущей выборки, а не всей историей ошибок. +3. По возможности заменить отбор по `Статус.Наименование` на отбор по ссылкам справочника `ак_СтатусыЭТРН` (предопределённые / кэшированные ссылки). +4. (Опционально, при росте объёма) ввести узкий регистр/механизм «активная очередь» (документ + вид очереди: новый/опрос), историю статусов оставить в текущем РС. + +**Ограничения** + +- Сохранить семантику: условие в параметрах `СрезПоследних` по статусу **нельзя** ставить так, чтобы возвращалась «последняя запись с таким статусом», а не последняя запись документа (это уже осознанно зафиксировано в комментариях модуля). +- Не менять смысл границы «новый / опрос» по `ИдентификаторСанадор`. + +**Результат этапа:** ускорение `ДобавитьНовые` / `ДобавитьОпросы` / протокола ошибок на наполненном регистре. + +### Этап B — HTTP и авторизация в рамках порции (P1, P2) — приоритет 1 + +**Задачи** + +1. Переиспользовать `HTTPСоединение` (и при возможности параметры авторизации) **в рамках одной порции / одной организации**. +2. Пробросить/использовать кэш параметров авторизации (`КешДанных.ПараметрыАвторизации` или аналог) в `ак_ПолучениеДанныхЭПД.ВызватьHTTPМетод`, чтобы не читать `ак_УчетныеЗаписиЭПД` на каждый вызов. +3. Настроить/зафиксировать рекомендуемые параметры РЗ: меньшая порция новых (ориентир 10–20) при отдельном/более частом запуске опросов — без изменения кода бизнес-логики титулов, если достаточно настроек расписания и параметров метода. + +**Ограничения** + +- Параллельный запуск нескольких экземпляров робота по-прежнему не допускается без отдельного архитектурного решения (ключ РЗ). +- Контракт API (URL, заголовки Bearer / `counterparty-uuid`, тела Т1/Т3) не менять. + +**Результат этапа:** снижение latency порции отправки при том же числе документов. + +### Этап C — пакетная подготовка данных титула Т1 (P5) — приоритет 2 + +**Задачи** + +1. Расширить prefetch на порцию: один или несколько пакетных запросов по массиву документов вместо серии точечных вызовов (`РабочийТелефонВодителя`, `АдресВесовой`, адреса/телефоны сторон, координаты, `ДокументЗакрепленияТС`, даты прибытия/убытия и т.п. — по фактическому использованию в `ПараметрыОтправкиТ1`). +2. Расширить `КешДанных` ключами по ссылкам (адреса КИ, телефоны, коды регионов, закрепления ТС), с заполнением из prefetch. +3. По возможности дополнить уже существующий `ДанныеПоДокументам` (UNION по видам документов) полями, которые сейчас читаются повторно при сборке payload. + +**Ограничения** + +- Состав и смысл полей JSON payload Т1/Т3 не менять (кроме явно согласованных дефектов данных). +- Ошибки заполнения полей по-прежнему фиксируются в результате формирования / статусах. + +**Результат этапа:** меньше запросов к ИБ на документ при отправке Т1. + +### Этап D — батч поиска перевозки для Т3 (P6) — приоритет 2 + +**Задачи** + +1. Группировать вызовы `ПолучитьСписокДокументовДляАРМ` по ключу (организация, водитель, номер ТС, окно дат) внутри порции. +2. Разбирать общую таблицу ответа локально для нескольких документов группы. +3. Где в данных есть uuid связанной перевозки / ранее сохранённый идентификатор — использовать его и не вызывать поиск АРМ. + +**Ограничения** + +- Правила различения нескольких перевозок «Груз в пути» (входящий номер / номер документа) сохранить. +- Состояния ожидания Т2 по-прежнему блокируют отправку Т3. + +**Результат этапа:** меньше HTTP при сценарии документов только с Т3 без uuid. + +### Этап E — мелкие оптимизации (P7) — приоритет 3 + +**Задачи** + +1. Пакетное/кэшируемое чтение ИНН сторон в `ПеревозкаСторонняя`. +2. В `ДокументыСОшибками` — соответствие тип → синоним вместо `Метаданные.НайтиПоТипу` на каждую строку. +3. Оценить необходимость двух записей статуса после успешного Т1 («Черновик…» + «Ожидается Т2…»); менять только при согласовании с пользователями РМ/отчётами по истории. + +--- + +## 5. Вне объёма + +- Изменение формата обмена с Санадором / новых титулов ЭПД. +- Перенос создания ЭТрН в интерактивный режим «по кнопке» вместо робота. +- Оптимизация бумажных макетов `ПФ_MXL_ТранспортнаяНакладная*`. +- Параллельная обработка очереди несколькими рабочими процессами (требует отдельного ТЗ по блокировкам и идемпотентности API). +- Рефакторинг модулей `сндОбменДаннымиСанадор*` вне контура ЭТрН. + +--- + +## 6. Регрессионные сценарии + +| № | Сценарий | Ожидание | +|---|----------|----------| +| R1 | Проведение документа со сторонней перевозкой и включённой настройкой Т1/Т3 | Статус «К отправке», сеть не вызывается | +| R2 | Проведение при внутренней перевозке / выключенных настройках | «Не требуется» или отсутствие постановки по текущим правилам | +| R3 | Повторное проведение документа уже в процессе | Статус/очередь не дублируют отправку | +| R4 | РЗ: новый документ → Т1 | Черновик в сервисе, заполнен `ИдентификаторСанадор`, статус ожидания Т2 | +| R5 | РЗ: опрос при готовности к Т3 | Отправка Т3, корректный статус | +| R6 | РЗ: документ с ошибкой первой отправки, неудач < максимума | Повторная попытка как «новый» | +| R7 | Документ с uuid и ошибкой Т3 | Не уходит в очередь «новых», не создаётся второй Т1 | +| R8 | РМ «Выбывшие документы ЭТрН» → вернуть в очередь | Счётчик неудач сбрасывается логикой `ВернутьВОчередь`, история сохраняется | +| R9 | Исчерпание бюджета времени | Текущий документ дорабатывается, остальные подхватываются следующим запуском | + +--- + +## 7. Порядок внедрения и оценка + +Рекомендуемый порядок: **A → B → C → D → E**. + +| Этап | Ориентир трудозатрат | Зависимости | +|------|----------------------|-------------| +| A | 2–5 чел·дн (без нового РС); +2–4 при введении узкой очереди | Решение по итогам среза / метаданным РС | +| B | 1–3 чел·дн | Согласование сигнатур HTTP-обёрток | +| C | 3–6 чел·дн | Этап B желателен, не обязателен | +| D | 1–3 чел·дн | — | +| E | 0,5–1,5 чел·дн | — | + +Оценки ориентировочные; уточняются после замера текущего времени `ДобавитьНовые`/`ДобавитьОпросы` и средней длительности HTTP на тестовой/боевой статистике. + +--- + +## 8. Риски + +| Риск | Митигация | +|------|-----------| +| Включение итогов среза увеличит стоимость каждой записи статуса | Замер записи до/после; при неприемлемости — узкая очередь без итогов | +| Кэш auth устареет при смене токена в середине порции | Инвалидация кэша по организации при 401/ошибке авторизации и один повтор | +| Prefetch полей титула разъедется с ветвлениями по видам документов | Покрыть R4–R5 на всех 5 видах документов | +| Батч поиска Т3 склеит чужие перевозки | Сохранить текущие правила уточнения по номерам; не укрупнять ключ сверх (орг+водитель+ТС+даты) | + +--- + +## 9. Поставка + +1. Описание изменений по модулям/метаданным. +2. Результаты замеров до/после (хотя бы время порции РЗ и число запросов/HTTP на документ). +3. Протокол прохождения сценариев §6. +4. При изменении метаданных РС — инструкция обновления ИБ и оценка времени пересчёта итогов (если применимо). + +--- + +## 10. Источники анализа + +- `ves2020/CommonModules/ак_ЭТрНРобот/Ext/Module.bsl` +- `ves2020/CommonModules/ак_ЭТрНОтправка/Ext/Module.bsl` +- `ves2020/CommonModules/ак_ЭТрНФормированиеТитулов/Ext/Module.bsl` +- `ves2020/CommonModules/ак_ЭТрНДанные/Ext/Module.bsl` +- `ves2020/CommonModules/ак_ПолучениеДанныхЭПД/Ext/Module.bsl` +- `ves2020/InformationRegisters/ак_СтатусыДокументовЭПД.xml` +- `ves2020/ScheduledJobs/ак_ОбработкаОчередиЭТрН.xml` + +**Memory:** локальный `memory.md` (постоянных записей по ЭТрН нет). +**Template:** проверка шаблонов MCP в сессии недоступна — «no fitting template». +**Docs / Metadata tooling:** разбор по исходникам выгрузки; live MCP user-1c при анализе был частично недоступен.