Архив OpenSpec intercompany-matrix-ui (PR #158) #169
184
openspec/specs/intercompany-matrix-ui/spec.md
Normal file
184
openspec/specs/intercompany-matrix-ui/spec.md
Normal file
@ -0,0 +1,184 @@
|
||||
# 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** выпадающее окно видно поверх полноэкранного блока
|
||||
Loading…
x
Reference in New Issue
Block a user