## MODIFIED Requirements ### Requirement: Таблица шахматки ЮЛ × ЮЛ Экран SHALL загружать матрицу при открытии вкладки (`POST /consolidations/versions/{id}/intercompany-matrix`, тело — по требованию «Фильтр счетов Дт и Кт и режимы расчёта») и показывать таблицу: первая колонка «ДБ / КТ» (закреплена слева) — компании периметра в порядке ответа (`companies[]`), остальные колонки — те же компании. В ячейке пары (строка A, колонка Б) SHALL быть три числа друг под другом: сумма `amount_a`, сумма `amount_b` и расхождение `variance_amount` в скобках; расхождение выделяется красным, если `exceeds_threshold = true` или `one_sided = true` (пара без встречной стороны; правило подсветки — как в API и xlsx, AURORA-1651). Если у пары есть строки ОСВ без сопоставленного счёта (`skipped_osv_entry_count > 0`), рядом с первым числом SHALL показываться значок предупреждения с подсказкой «Строк ОСВ без сопоставленного счёта: N; в суммы не вошли». Если ячейки пары в ответе нет (в том числе на диагонали), SHALL показываться прочерк «—» на приглушённом фоне. Справа закреплена колонка «Итого Дт» — `total_debit` ответа для компании строки; ниже таблицы закреплена строка «Итого Кт» — `total_credit` для компании колонки; ячейка на их пересечении пустая. Итоги считает сервер (DOC-221277 «Итоги шахматки», AURORA-1756), клиент их только форматирует («Единицы и знаки»); отсутствующий в ответе итог — прочерк «—». Пока идёт загрузка, таблица показывает индикатор загрузки; ошибка API показывается уведомлением с текстом сервера. Панель фильтров показывает год и квартал версии неактивными полями «Год» и «Период» (например, `2024` и `К1`): версия задаётся адресом. #### Scenario: Ячейка с расхождением выше порога - **WHEN** для пары `(A, Б)` сервер вернул `exceeds_threshold = true` - **THEN** третье число ячейки (расхождение) показано красным, первые два — обычным цветом #### Scenario: Пара без встречной стороны - **WHEN** для пары `(A, Б)` сервер вернул `amount_b = 0`, `one_sided = true`, `exceeds_threshold = false` - **THEN** третье число ячейки (расхождение) показано красным #### Scenario: Пары нет в ответе - **WHEN** в `cells[]` нет ячейки для пары компаний - **THEN** на их пересечении показан прочерк «—» #### Scenario: Пропущенные строки ОСВ - **WHEN** у ячейки `skipped_osv_entry_count = 2` - **THEN** у первого числа ячейки виден значок предупреждения, подсказка — «Строк ОСВ без сопоставленного счёта: 2; в суммы не вошли» #### Scenario: Итоги из ответа - **WHEN** сервер вернул `total_debit[A] = "120000.00"` и `total_credit[Б] = "75000.00"`, выбраны «тыс. руб.» и 2 знака - **THEN** в колонке «Итого Дт» строки A показано `120,00`, в строке «Итого Кт» под колонкой Б — `75,00`, пересечение итогов пустое ### Requirement: Результирующая таблица ВГО Под матрицей экран SHALL показывать результирующую таблицу ВГО, загруженную при открытии вкладки (`GET /consolidations/versions/{id}/intercompany-matrix/result-table`): первая колонка «Статья» — статьи ответа (`articles[]`, `name`) в порядке ответа, далее колонки компаний (`companies[]`) с суммой статьи по компании (`amounts[]` по `company_id`) и колонка «Итого по группе» со значением `group_total` из ответа; пустая сумма — прочерк «—». Строки итога по всем статьям под таблицей нет: суммы разных статей не складываются (аналитик, 03.11.2026). У таблицы свои выбор единиц и знаков (по правилам требования «Единицы и знаки», независимо от матрицы), кнопка «Экспорт» и кнопка «На весь экран». Пока идёт загрузка, таблица показывает индикатор; ошибка API (в том числе 422 `RESULT_ACCOUNTS_MISSING`) показывается уведомлением с текстом сервера. #### Scenario: Колонка «Итого» из ответа - **WHEN** сервер вернул статью «Дебиторская задолженность» с `group_total = "1296510.00"`, выбраны «тыс. руб.» и 2 знака - **THEN** в колонке «Итого по группе» этой статьи показано `1 296,51` #### Scenario: Нет обязательного счёта - **WHEN** сервер ответил 422 `RESULT_ACCOUNTS_MISSING` - **THEN** показано уведомление с текстом сервера, матрица шахматки при этом показывается как обычно ### Requirement: Фильтр компаний Выбор «Компании» (множественный, пустой выбор — «Все компании») SHALL передаваться в запрос матрицы `legal_entity_ids`: сервер возвращает только выбранные компании, ячейки между ними и итоги «Итого Дт» / «Итого Кт» по ним. Каждое изменение выбора перезапрашивает матрицу (в состоянии «выбрана одна сторона» — нет). Список вариантов — компании последнего ответа, полученного без выбора компаний (весь периметр версии); ответы с выбором его не меняют. Выпадающее окно выбора — дерево с поиском по названию, кнопками применения и сброса. #### Scenario: Две компании из периметра - **WHEN** выбраны две компании из пяти - **THEN** запрос содержит `legal_entity_ids` этих двух компаний, матрица содержит две строки и две колонки, итоги — из ответа, в списке вариантов по-прежнему пять компаний ### Requirement: Фильтр счетов Дт и Кт и режимы расчёта Экран SHALL загружать план счетов `GET /directories/accounts` один раз при открытии и строить из него два дерева по иерархии `parent_id`: дебетовые счета (`is_debit`) и кредитовые (`is_credit`); подпись узла — «код - название», в том числе у выбранных дочерних счетов в поле выбора. Выбор счетов Дт и Кт — множественный, пустой выбор — «Все счета». Отметки в дереве SHALL считаться по полному плану счетов: родительский счёт отмечен тогда и только тогда, когда отмечены все его потомки в полном дереве. Поиск по дереву скрывает не совпавшие узлы, но не меняет этого правила: отметка единственного видимого при поиске субсчёта не отмечает его родителя, а снятие отметки с субсчёта снимает её и с родителя. Скрытые поиском отметки при отметке видимых узлов сохраняются. Режим расчёта определяется выбором: - ничего не выбрано ни в Дт, ни в Кт — SHALL выполняться `POST …/intercompany-matrix` с пустыми `debit_account_ids` и `credit_account_ids` (режим `all`); - выбраны счета и в Дт, и в Кт — SHALL выполняться `POST …/intercompany-matrix` с выбранными `debit_account_ids` и `credit_account_ids` (режим `manual`); - выбрана только одна сторона — запрос SHALL NOT отправляться, таблица матрицы SHALL быть пустой и вместо данных показывать текст «Для расчёта по счетам выберите счета и в Дт, и в Кт»; тот же текст SHALL показываться у фильтров Дт/Кт (не всплывающим уведомлением) и только в этом состоянии; кнопка «Экспорт» матрицы SHALL быть недоступна. В тело всегда входит `legal_entity_ids` (требование «Фильтр компаний»). Каждое изменение выбора счетов, приводящее к режиму `all` или `manual`, перезапрашивает матрицу; на экране остаётся ответ на последний запрос, индикатор загрузки снимается и при переходе в состояние «выбрана одна сторона». Кнопка «Сбросить фильтры» появляется, когда выбрано что-либо в компаниях, Дт или Кт, и очищает все три выбора. Выбор единиц и знаков кнопкой не сбрасывается. Ошибка загрузки плана счетов показывается уведомлением. #### Scenario: Обе стороны выбраны - **WHEN** выбран счёт 60.01 в Дт и счёт 62.01 в Кт - **THEN** отправляется `POST …/intercompany-matrix` с идентификаторами этих счетов и таблица показывает ответ #### Scenario: Выбрана одна сторона - **WHEN** выбран счёт только в Дт - **THEN** запрос матрицы не отправляется, таблица пуста и показывает «Для расчёта по счетам выберите счета и в Дт, и в Кт», тот же текст виден у фильтров, «Экспорт» матрицы недоступен, выбор Дт остаётся в фильтре #### Scenario: Выбрана одна сторона во время загрузки - **WHEN** выбраны Дт и Кт, запрос `manual` ещё выполняется, и пользователь очищает Кт - **THEN** индикатор загрузки снят, ответ прежнего запроса на экран не выводится, таблица в состоянии «выбрана одна сторона» #### Scenario: Поиск и отметка субсчёта - **WHEN** в дереве Дт введён поиск, видна ветка 60 с единственным субсчётом 60.02, и отмечен 60.02 - **THEN** выбранным остаётся только 60.02; после сброса поиска счёт 60 и его прочие субсчета не отмечены #### Scenario: Снятие субсчёта отмеченного родителя - **WHEN** отмечен счёт 60 (отмечены 60, 60.01, 60.02) и снята отметка с 60.01 - **THEN** выбранным остаётся 60.02, счёт 60 не отмечен #### Scenario: Сброс - **WHEN** выбраны компании и счета, нажато «Сбросить фильтры» - **THEN** все три выбора пусты, матрица перезапрошена в режиме `all`, кнопка исчезла ### Requirement: Экспорт в XLSX Кнопка «Экспорт» матрицы SHALL скачивать XLSX в том же режиме, что и таблица: `POST …/intercompany-matrix/export` с тем же телом, что запрос таблицы (`debit_account_ids`, `credit_account_ids`, `legal_entity_ids`), — итоги в файле совпадают с экраном; при выбранной одной стороне кнопка недоступна. Кнопка «Экспорт» результирующей таблицы SHALL скачивать `GET …/intercompany-matrix/result-table/export`. Файл сохраняется под именем из `Content-Disposition`, при его отсутствии — `Шахматка_<ГК>_<год>_<квартал>.xlsx` и `Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx` соответственно. Пока идёт выгрузка, в состоянии загрузки только нажатая кнопка; ошибка API показывается уведомлением. Единицы и знаки в запрос экспорта не передаются. #### Scenario: Экспорт по всем счетам - **WHEN** счета не выбраны и нажато «Экспорт» матрицы - **THEN** отправлен `POST …/intercompany-matrix/export` с пустыми списками, браузер сохраняет файл `intercompany-matrix_….xlsx` #### Scenario: Экспорт результирующей таблицы - **WHEN** нажато «Экспорт» результирующей таблицы - **THEN** отправлен `GET …/intercompany-matrix/result-table/export`, кнопка «Экспорт» матрицы не переходит в состояние загрузки