docs(openspec): intercompany-matrix-ui — временные клиентские «Итого», вид ячеек, решения раунда 3 (ревью #158)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-22 16:42:00 +04:00
parent c3d82bd293
commit 22d5733d16
3 changed files with 48 additions and 31 deletions

View File

@ -24,26 +24,25 @@
- **D-6. `apiFetchBlob(path, init)`** принимает `RequestInit`, чтобы выгружать POST-ом с телом; без `init` поведение прежнее.
- **D-7. Полноэкранный режим** — Fullscreen API на контейнере блока, состояние следует за `fullscreenchange`; выпадающие окна
antd рендерятся в `document.fullscreenElement` (`ConfigProvider getPopupContainer`).
- **D-8. Итоги отдаёт бэкенд.** Решение владельца 22.10.2026: все агрегаты (строки «Итого») считает API, фронт сумм не
складывает. Пока API их не отдаёт, строк «Итого» под матрицей и под результирующей таблицей нет; колонка «Итого» результирующей
таблицы — `group_total` из ответа. Итоги в API и правило суммирования — AURORA-1756 (бэк, ждёт аналитику AURORA-1373), вывод на
экран — AURORA-1757.
- **D-8. Итоги — задача бэкенда.** Решение владельца 22.10.2026: агрегаты (строки «Итого») должен отдавать API. Перенос —
технический долг: AURORA-1756 (итоги и правило суммирования в API, ждёт аналитику AURORA-1373) и AURORA-1757 (вывод итогов из
API). До этого строки «Итого» остаются клиентскими (решение владельца: «особо не мешает»): точное сложение строк через
`sumAmounts`, под матрицей — `amount_a` по колонке, под результирующей таблицей — все статьи по колонке; колонка «Итого»
результирующей таблицы — `group_total` из ответа.
- **D-9. `useNotificationApi` мемоизирован** (`useMemo` по `notification` из `App.useApp()`, который antd сам мемоизирует):
объект уведомлений стабилен между рендерами, поэтому `loadData`/`loadResData` — `useCallback([notification])`, а эффекты
загрузки зависят от них без лишних перезапросов.
## Known issues
Открытые проблемы ветки на 601a125 (ревью, раунд 3), которые исправляет автор PR; спека описывает целевое поведение.
Открытые проблемы ветки (ревью, раунд 3), которые исправляет автор PR; спека описывает целевое поведение.
1. Строки «Итого» под матрицей и под результирующей таблицей считаются на клиенте (`sumAmounts`) — убрать (D-8).
2. Поиск в дереве счетов: отметки считаются по отфильтрованному дереву, отметка единственного видимого субсчёта отмечает
1. Поиск в дереве счетов: отметки считаются по отфильтрованному дереву, отметка единственного видимого субсчёта отмечает
родителя, и на бэк уходит весь родительский счёт (`TreeFilterDropdown.tsx`).
3. Выбрана одна сторона Дт/Кт: таблица показывает прежние данные, подсказка — всплывающее уведомление и постоянный текст внутри
2. Выбрана одна сторона Дт/Кт: таблица показывает прежние данные, подсказка — всплывающее уведомление и постоянный текст внутри
выпадающего окна, «Экспорт» активен и выгружает режим `all`.
4. Стили: правило тегов в `App.css` и класс на форме ЮЛ (`CatalogueJurForm.tsx`) — вне экрана; у селекта Кт класса нет;
3. Стили: правило тегов в `App.css` и класс на форме ЮЛ (`CatalogueJurForm.tsx`) — вне экрана; у селекта Кт класса нет;
`.resRow`, `.empty-cell` не под `.chessTable`; у `Tree` снят `className='filterTree'`.
5. Желательно: запасные имена файлов (`exportFilename` добавляет `Сводная_ОСВ_`) и общий `exportLoading` на две кнопки;
нечисловое значение в тыс./млн/млрд искажается (`0.abc`); `sumAmounts(...) ?? '0'`; `as any` в форматтере; мёртвый код
(скобки в форматтере, `formatted === '—'`); ячейки по макету (скобки у расхождения, «—», значок `skipped_osv_entry_count`);
заглушки «Год»/«Квартал»; `services/consodilation`, типы вне `types/api.ts`, `withJsonBody`, `Account.kind`.
## Decisions made without discussion
@ -67,7 +66,7 @@
один компонент (`OsvTabs`).
- **2026-10-22 (е). Спека переписана на целевое поведение** (раунд 3 ревью): владелец решил, что спеки и тесты чужих PR ведём
мы, а автор правит продуктовый код; целевая спека даёт автору однозначный ориентир, расхождения кода — в «Known issues».
Цена ошибки: до исправлений спека и код ветки расходятся; PR не сливается, пока «Known issues» 1–4 не закрыты.
Цена ошибки: до исправлений спека и код ветки расходятся; PR не сливается, пока «Known issues» не закрыты.
- **2026-10-22 (ж). Выбрана одна сторона Дт/Кт — пустая таблица с текстом** «Для расчёта по счетам выберите счета и в Дт,
и в Кт» у таблицы и у фильтров, «Экспорт» матрицы недоступен. Альтернатива — оставить прежние данные с подсказкой; отвергнута:
на экране были бы данные, не соответствующие фильтру. Цена ошибки: правка текста и одного условия.
@ -76,7 +75,19 @@
аналитик захочет «родитель + выбранные субсчета» как отдельный режим — MODIFIED требования.
- **2026-10-22 (и). Запасные имена файлов** `Шахматка_<ГК>_<год>_<квартал>.xlsx` и
`Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx`. Цена ошибки: низкая, имя из `Content-Disposition` приоритетнее.
- **2026-10-22 (к). Тесты форматтера** `utils/chessTableCellFormatValue.test.ts` написаны ревьюером: проверяют сдвиг единиц,
точное округление, большие суммы, «-0,00» и пустые значения; случай нечислового значения в тыс./млн/млрд не покрыт — он
в Known issues (5) и тест добавляется вместе с исправлением.
- **2026-10-22 (к). Тесты форматтера** `utils/chessTableCellFormatValue.test.ts` написаны ревьюером: сдвиг единиц, точное
округление, большие суммы, «-0,00», пустые и нечисловые значения при любых единицах.
- **2026-10-22 (л). В ветку влит `main`** (PR #159), чтобы выгрузка результирующей таблицы работала на стенде из ветки.
- **2026-10-22 (м). Желательные пункты ревью закрыты ревьюером** (решение владельца): форматтер (проверка числа до сдвига
запятой, `Intl.StringNumericLiteral` через `ES2023.Intl` в `lib` tsconfig вместо `as any`, без мёртвого разбора скобок),
запасные имена (`utils/download.xlsxFilename`), отдельные флаги выгрузки, зависимости эффектов (D-9), «—» вместо выдуманного
нуля, ячейки по макету, «Год»/«Период» версии только для чтения, сервис `services/api/intercompanyMatrix.ts` с `withJsonBody`,
типы шахматки в `types/api.ts`, `Account.kind: 'A' | 'P' | 'AP' | null`. Цена ошибки: конфликты слияния у автора в
`ConsolidatedChessContent.tsx` и `ConsolidationChessTableFilter.tsx` — он правит те же файлы по «Known issues»; автору сказано
начать с `git pull`.
- **2026-10-22 (н). «-0,00» убирается проверкой готовой строки, а не опцией `signDisplay: 'negative'`.** Обоснование: на движке
без Intl.NumberFormat v3 неизвестное значение `signDisplay` бросает `RangeError` и ломает весь экран, а проверка строки
безопасна везде. Цена ошибки: нет.
- **2026-10-22 (о). Расхождение в скобках всегда**, в том числе нулевое — `(0,00)`: в API `variance_amount` — модуль разности
(неотрицательный), скобки в макете 31-01 — способ показа третьей строки, а не знак. Значок пропущенных строк ОСВ — оранжевый
`WarningOutlined` у первого числа. Подпись «Период» (не «Квартал») — как в макете. Цена ошибки: правка вида ячейки.

View File

@ -25,10 +25,14 @@
Экран SHALL загружать матрицу при открытии вкладки (`GET /consolidations/versions/{id}/intercompany-matrix/all`) и показывать
таблицу: первая колонка «ДБ / КТ» (закреплена слева) — компании периметра в порядке ответа (`companies[]`), остальные колонки —
те же компании. В ячейке пары (строка A, колонка Б) SHALL быть три числа друг под другом: сумма `amount_a`, сумма `amount_b`
и расхождение `variance_amount`; расхождение выделяется красным, если `exceeds_threshold = true`. Если ячейки пары в ответе нет
(в том числе на диагонали), SHALL показываться прочерк «—» на приглушённом фоне. Итоговые суммы (строка «Итого») экран SHALL
NOT вычислять сам: агрегаты отдаёт бэкенд, пока API их не возвращает — строки «Итого» под матрицей нет. Пока идёт загрузка,
таблица показывает индикатор загрузки; ошибка API показывается уведомлением с текстом сервера.
и расхождение `variance_amount` в скобках; расхождение выделяется красным, если `exceeds_threshold = true`. Если у пары есть
строки ОСВ без сопоставленного счёта (`skipped_osv_entry_count > 0`), рядом с первым числом SHALL показываться значок
предупреждения с подсказкой «Строк ОСВ без сопоставленного счёта: N; в суммы не вошли». Если ячейки пары в ответе нет
(в том числе на диагонали), SHALL показываться прочерк «—» на приглушённом фоне. Ниже таблицы закреплена строка «Итого»: до
появления итогов в API (AURORA-1756, AURORA-1757) она временно считается на клиенте точным сложением десятичных строк — сумма
`amount_a` по колонке видимых ячеек; итог, который не удалось сложить, показывается прочерком «—», а не нулём. Пока идёт
загрузка, таблица показывает индикатор загрузки; ошибка API показывается уведомлением с текстом сервера. Панель фильтров
показывает год и квартал версии неактивными полями «Год» и «Период» (например, `2024` и `К1`): версия задаётся адресом.
#### Scenario: Ячейка с расхождением выше порога
- **WHEN** для пары `(A, Б)` сервер вернул `exceeds_threshold = true`
@ -38,16 +42,17 @@ NOT вычислять сам: агрегаты отдаёт бэкенд, по
- **WHEN** в `cells[]` нет ячейки для пары компаний
- **THEN** на их пересечении показан прочерк «—»
#### Scenario: Итоги не считаются на клиенте
- **WHEN** матрица загружена
- **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 не отдаёт итог по статьям
(клиент суммы не складывает). У таблицы свои выбор единиц и знаков (по правилам требования «Единицы и знаки», независимо от
колонка «Итого» со значением `group_total` из ответа; пустая сумма — прочерк «—». Ниже таблицы закреплена строка «Итого»: до
появления итогов в API (AURORA-1756, AURORA-1757) она временно считается на клиенте точным сложением сумм всех статей по
колонке (итог, который не удалось сложить, — «—»). У таблицы свои выбор единиц и знаков (по правилам требования «Единицы и знаки», независимо от
матрицы), кнопка «Экспорт» и кнопка «На весь экран». Пока идёт загрузка, таблица показывает индикатор; ошибка API (в том числе
422 `RESULT_ACCOUNTS_MISSING`) показывается уведомлением с текстом сервера.
@ -87,7 +92,7 @@ NOT вычислять сам: агрегаты отдаёт бэкенд, по
#### Scenario: Две компании из периметра
- **WHEN** выбраны две компании из пяти
- **THEN** матрица содержит две строки и две колонки
- **THEN** матрица содержит две строки и две колонки, «Итого» считается по оставшимся ячейкам
### Requirement: Фильтр счетов Дт и Кт и режимы расчёта
Экран SHALL загружать план счетов `GET /directories/accounts` один раз при открытии и строить из него два дерева по иерархии

View File

@ -2,10 +2,11 @@
- [x] 1.1 Спека `intercompany-matrix-ui` (ревьюер; с раунда 3 — целевое поведение).
- [x] 1.2 Тесты форматтера сумм `utils/chessTableCellFormatValue.test.ts` (ревьюер).
- [ ] 1.3 Автор исправляет «Known issues» 1–4 из `design.md` (желательное — 5 — по возможности).
- [ ] 1.4 Перед слиянием: `make web-check`, `npm test`, `npm run lint` — зелёные, вывод в описание PR.
- [ ] 1.5 Сверка экрана с макетом 31-01 / 31-01-01 в браузере (`docs/mockup/INDEX.md`), в том числе полноэкранный режим.
- [x] 1.3 Желательные пункты ревью раунда 3 (ревьюер, решение (м) в `design.md`).
- [ ] 1.4 Автор исправляет «Known issues» из `design.md`.
- [ ] 1.5 Перед слиянием: `make web-check`, `npm test`, `npm run lint` — зелёные, вывод в описание PR.
- [ ] 1.6 Сверка экрана с макетом 31-01 / 31-01-01 в браузере (`docs/mockup/INDEX.md`), в том числе полноэкранный режим.
## 2. После слияния
- [ ] 2.1 Итоги «Итого» из API — AURORA-1756 (бэк), AURORA-1757 (фронт).
- [ ] 2.1 Итоги «Итого» из API вместо клиентских — AURORA-1756 (бэк), AURORA-1757 (фронт).