Andrey Epifancev 8b888fdef8 Архив OpenSpec intercompany-matrix-ui (PR #158)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:42:15 +04:00

20 KiB
Raw Blame History

intercompany-matrix-ui Specification

Purpose

Аналитик видит шахматку ВГО версии [31-01] (матрица Дт/Кт по компаниям с фильтрами компаний и счетов, единицами и полноэкранным режимом) и результирующую таблицу ВГО [31-01-01], выгружает обе в xlsx; суммы и итоги приходят с бэка, фронт их только форматирует.

Requirements

Requirement: Вкладки страницы отчёта по версии

Страница /groups/:group_id/versions/:version_id/:tab SHALL показывать шапку версии (ГК, период, статус отчёта) один раз и под ней ряд вкладок шагов консолидации и содержимое активной вкладки. Активная вкладка определяется сегментом :tab: osv — «ОСВ» (сводная ОСВ), chess — «Шахматка». Выбор вкладки SHALL менять последний сегмент адреса на ключ вкладки (навигация, не локальное состояние), активная вкладка подсвечена зелёным и выделена жирным. Неизвестный ключ вкладки SHALL заменяться на osv без новой записи в истории браузера. Вкладки «Таблица корректировки», «Гудвилл», «КФО», «КФО Общий», «Подтверждение КФО клиента» SHALL быть недоступны с подсказкой «Будет в следующих срезах». При смене version_id всё состояние страницы (карточка версии, данные, фильтры) SHALL создаваться заново.

Scenario: Переход на шахматку

  • WHEN открыта сводная ОСВ версии по адресу …/versions/{id}/osv и нажата вкладка «Шахматка»
  • THEN адрес становится …/versions/{id}/chess, шапка версии остаётся, под вкладками показана шахматка

Scenario: Прежний адрес сводной ОСВ

  • WHEN открыт адрес …/versions/{id}/osv
  • THEN показана сводная ОСВ, вкладка «ОСВ» активна

Scenario: Неизвестная вкладка

  • WHEN открыт адрес …/versions/{id}/abc
  • THEN адрес заменяется на …/versions/{id}/osv, показана сводная ОСВ; кнопка «Назад» браузера не возвращает на …/abc

Requirement: Таблица шахматки ЮЛ × ЮЛ

Экран SHALL загружать матрицу при открытии вкладки (GET /consolidations/versions/{id}/intercompany-matrix/all) и показывать таблицу: первая колонка «ДБ / КТ» (закреплена слева) — компании периметра в порядке ответа (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 показываться прочерк «—» на приглушённом фоне. Ниже таблицы закреплена строка «Итого»: до появления итогов в API (AURORA-1756, AURORA-1757) она временно считается на клиенте точным сложением десятичных строк — сумма amount_a по колонке видимых ячеек; итог, который не удалось сложить, показывается прочерком «—», а не нулём. Пока идёт загрузка, таблица показывает индикатор загрузки; ошибка 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; в суммы не вошли»

Requirement: Результирующая таблица ВГО

Под матрицей экран SHALL показывать результирующую таблицу ВГО, загруженную при открытии вкладки (GET /consolidations/versions/{id}/intercompany-matrix/result-table): первая колонка «Статья» — статьи ответа (articles[], name) в порядке ответа, далее колонки компаний (companies[]) с суммой статьи по компании (amounts[] по company_id) и колонка «Итого» со значением group_total из ответа; пустая сумма — прочерк «—». Ниже таблицы закреплена строка «Итого»: до появления итогов в API (AURORA-1756, AURORA-1757) она временно считается на клиенте точным сложением сумм всех статей по колонке (итог, который не удалось сложить, — «—»). У таблицы свои выбор единиц и знаков (по правилам требования «Единицы и знаки», независимо от матрицы), кнопка «Экспорт» и кнопка «На весь экран». Пока идёт загрузка, таблица показывает индикатор; ошибка 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 позволять выбрать единицы суммы — «руб.», «тыс. руб.» (по умолчанию), «млн. руб.», «млрд руб.» — и число знаков после запятой 0–3 (по умолчанию 2). Выбор применяется на клиенте к уже загруженным значениям (повторного запроса не делает): запятая сдвигается в десятичной строке на 3 / 6 / 9 разрядов, значение округляется до выбранного числа знаков (половина — от нуля) без перевода в число с плавающей точкой и показывается с разделителем разрядов и десятичной запятой. Значение, округлённое до нуля, показывается без минуса. Пустое значение — пустая ячейка. Значение, которое не удаётся прочитать как число, SHALL показываться как пришло — при любых единицах.

Scenario: Смена единиц

  • WHEN выбраны «млн. руб.» и 1 знак, а сервер вернул amount_a = "2346459.05"
  • THEN в ячейке показано 2,3

Scenario: Точное округление

  • WHEN выбраны «тыс. руб.» и 2 знака, а сервер вернул "1005"
  • THEN показано 1,01 (не 1,00, как дало бы округление числа с плавающей точкой)

Scenario: Маленькая отрицательная сумма

  • WHEN выбраны «тыс. руб.» и 2 знака, а сервер вернул "-4.00"
  • THEN показано 0,00, а не -0,00

Requirement: Фильтр компаний

Выбор «Компании» (множественный, пустой выбор — «Все компании») SHALL ограничивать матрицу на клиенте: остаются строки и колонки выбранных компаний и ячейки, у которых обе компании выбраны. Запрос на сервер при этом не отправляется. Список вариантов — компании последнего загруженного ответа. Выпадающее окно выбора — дерево с поиском по названию, кнопками применения и сброса.

Scenario: Две компании из периметра

  • WHEN выбраны две компании из пяти
  • THEN матрица содержит две строки и две колонки, «Итого» считается по оставшимся ячейкам

Requirement: Фильтр счетов Дт и Кт и режимы расчёта

Экран SHALL загружать план счетов GET /directories/accounts один раз при открытии и строить из него два дерева по иерархии parent_id: дебетовые счета (is_debit) и кредитовые (is_credit); подпись узла — «код - название», в том числе у выбранных дочерних счетов в поле выбора. Выбор счетов Дт и Кт — множественный, пустой выбор — «Все счета».

Отметки в дереве SHALL считаться по полному плану счетов: родительский счёт отмечен тогда и только тогда, когда отмечены все его потомки в полном дереве. Поиск по дереву скрывает не совпавшие узлы, но не меняет этого правила: отметка единственного видимого при поиске субсчёта не отмечает его родителя, а снятие отметки с субсчёта снимает её и с родителя. Скрытые поиском отметки при отметке видимых узлов сохраняются.

Режим расчёта определяется выбором:

  • ничего не выбрано ни в Дт, ни в Кт — SHALL выполняться GET …/intercompany-matrix/all (режим all);
  • выбраны счета и в Дт, и в Кт — SHALL выполняться POST …/intercompany-matrix/manual с {debit_account_ids, credit_account_ids} (режим manual);
  • выбрана только одна сторона — запрос SHALL NOT отправляться, таблица матрицы SHALL быть пустой и вместо данных показывать текст «Для расчёта по счетам выберите счета и в Дт, и в Кт»; тот же текст SHALL показываться у фильтров Дт/Кт (не всплывающим уведомлением) и только в этом состоянии; кнопка «Экспорт» матрицы SHALL быть недоступна.

Каждое изменение выбора счетов, приводящее к режиму all или manual, перезапрашивает матрицу; на экране остаётся ответ на последний запрос, индикатор загрузки снимается и при переходе в состояние «выбрана одна сторона». Кнопка «Сбросить фильтры» появляется, когда выбрано что-либо в компаниях, Дт или Кт, и очищает все три выбора. Выбор единиц и знаков кнопкой не сбрасывается. Ошибка загрузки плана счетов показывается уведомлением.

Scenario: Обе стороны выбраны

  • WHEN выбран счёт 60.01 в Дт и счёт 62.01 в Кт
  • THEN отправляется POST …/intercompany-matrix/manual с идентификаторами этих счетов и таблица показывает ответ

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 в том же режиме, что и таблица: в режиме manual — POST …/intercompany-matrix/manual/export с телом {debit_account_ids, credit_account_ids}, в режиме all — GET …/intercompany-matrix/all/export; при выбранной одной стороне кнопка недоступна. Кнопка «Экспорт» результирующей таблицы SHALL скачивать GET …/intercompany-matrix/result-table/export. Файл сохраняется под именем из Content-Disposition, при его отсутствии — Шахматка_<ГК>_<год>_<квартал>.xlsx и Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx соответственно. Пока идёт выгрузка, в состоянии загрузки только нажатая кнопка; ошибка API показывается уведомлением. Фильтр компаний, единицы и знаки в запрос экспорта не передаются.

Scenario: Экспорт по всем счетам

  • WHEN счета не выбраны и нажато «Экспорт» матрицы
  • THEN отправлен GET …/intercompany-matrix/all/export, браузер сохраняет файл intercompany-matrix_….xlsx

Scenario: Экспорт результирующей таблицы

  • WHEN нажато «Экспорт» результирующей таблицы
  • THEN отправлен GET …/intercompany-matrix/result-table/export, кнопка «Экспорт» матрицы не переходит в состояние загрузки

Requirement: Полноэкранный режим

Кнопка «На весь экран» матрицы и результирующей таблицы SHALL переводить свой блок (панель фильтров и таблицу) в полноэкранный режим средствами Fullscreen API с белым фоном и таблицей на высоту окна; в нём кнопка меняется на «Свернуть». Выпадающие списки фильтров и подсказки SHALL оставаться видимыми в полноэкранном режиме. Выход клавишей Esc SHALL возвращать обычный вид и подпись кнопки. Отказ браузера войти в полноэкранный режим показывается уведомлением.

Scenario: Вход и выход

  • WHEN нажато «На весь экран», затем Esc
  • THEN блок разворачивается на весь экран, затем возвращается в страницу, кнопка снова «На весь экран»

Scenario: Фильтр в полноэкранном режиме

  • WHEN матрица в полноэкранном режиме и открыт выбор «Компании»
  • THEN выпадающее окно видно поверх полноэкранного блока