Andrey Epifancev b8f0672029 docs(openspec): intercompany-matrix-ui — целевое поведение экрана (ревью #158, раунд 3)
Итоги отдаёт бэкенд (AURORA-1756/1757), результирующая таблица и её выгрузка,
«руб.», точное округление, одна сторона Дт/Кт без запроса, правило отметок
дерева по полному плану счетов, отдельные флаги выгрузки, полноэкранный режим.
Known issues — по состоянию 601a125.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:30:01 +04:00

12 KiB
Raw Blame History

Context

Экран «Шахматка» [31-01] добавлен в arm-core/web PR #158 (ветка feat/chessTable, AURORA-1538) как вторая вкладка страницы отчёта по версии. Страница layouts/ConsolidatedOsvPage.tsx разделена: общую шапку и вкладки держит layouts/ConsolidationReportPage.tsx, содержимое вкладок — widgets/ConsolidatedOsvContent (прежняя сводная ОСВ без изменений поведения) и widgets/ConsolidatedChessContent (матрица ConsolidationChessTable и результирующая таблица ConsolidationChessResTable). Бэкенд — change 2026-10-16-intercompany-matrix (матрица, результирующая таблица) и 2026-10-22-intercompany-result-table-export (выгрузка результирующей таблицы); расчёт — чистая функция версии, ничего не хранится.

Decisions

  • D-1. Маршрут :tab. OsvTabs берёт активную вкладку из useParams().tab (по умолчанию osv) и по выбору заменяет последний сегмент адреса. Неизвестный tab заменяется на osv (navigate(…, {replace: true})).
  • D-2. Ключ версии. Страница отчёта разделена на обёртку с key={version_id} и содержимое: при смене версии карточка, фильтры и данные создаются заново (как было в ConsolidatedOsvPage).
  • D-3. Режим расчёта из выбора счетов: manual — при непустых Дт и Кт, all — при пустых обоих; при одной выбранной стороне запроса нет (бэкенд ответил бы 422 на manual, а all показал бы не то, что выбрано). Тот же признак выбирает маршрут экспорта.
  • D-4. Единицы, знаки и фильтр компаний — на клиенте. Запрос повторяется только при смене выбора счетов или версии. Единицы — сдвиг запятой в десятичной строке (utils/chessTableCellFormatValue.ts), Intl.NumberFormat получает строку и форматирует её как точное десятичное (без float).
  • D-5. План счетов — GET /directories/accounts целиком, деревья Дт и Кт строятся на клиенте по parent_id.
  • 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.

Known issues

Открытые проблемы ветки на 601a125 (ревью, раунд 3), которые исправляет автор PR; спека описывает целевое поведение.

  1. Строки «Итого» под матрицей и под результирующей таблицей считаются на клиенте (sumAmounts) — убрать (D-8).
  2. Поиск в дереве счетов: отметки считаются по отфильтрованному дереву, отметка единственного видимого субсчёта отмечает родителя, и на бэк уходит весь родительский счёт (TreeFilterDropdown.tsx).
  3. Выбрана одна сторона Дт/Кт: таблица показывает прежние данные, подсказка — всплывающее уведомление и постоянный текст внутри выпадающего окна, «Экспорт» активен и выгружает режим all.
  4. Стили: правило тегов в 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

  • 2026-10-21 (а). Спеку пишет ревьюер в ветке автора — по решению владельца (разрешено явно); альтернатива — оставить автору. Цена ошибки: автор может не согласиться с формулировками; правится одним коммитом в этом же change.
  • 2026-10-21 (б). Спека описывает фактическое поведение, дефекты вынесены в «Known issues». Отменено 22.10.2026 (е). Обоснование: спека — единственный источник истины при рулингах, а закреплять баги требованиями нельзя; иначе их закрытие превратится в «нарушение спеки». Цена ошибки: отдельные требования (например, режим all при выборе одной стороны, «Итого» из расхождений) описаны как есть и после исправления потребуют MODIFIED.
  • 2026-10-21 (в). При восстановлении затёртого фронта (коммит 175343b) из origin/main взяты целиком все файлы без шахматочных изменений, а в App.tsx, layouts/index.ts, api/client.ts (параметр init), OsvTabs.tsx, ConsolidatedOsvContent.tsx оставлены изменения шахматки. Возвращён key={version_id} (разделением страницы на обёртку и содержимое — поведение как в main). Обоснование: изменения PR в этих файлах относятся к шахматке; цена ошибки — незамеченная откатившаяся правка main в этих пяти файлах (построчно сверено с origin/main, расхождений кроме шахматочных нет).
  • 2026-10-21 (г). Механические правки biome без смены поведения (коммит e19291c): тип IntercompanyMatrixResponse у let res, Number.isNaN, key у span в OsvTabs, ?? null вместо пустого фрагмента. Предупреждения eslint (8 новых в коде шахматки: any, deps хуков, console) не исправлялись — они входят в Known issues. Цена ошибки: key на span внутри Tooltip безвреден, но избыточен.
  • 2026-10-21 (д). Дельта к consolidated-osv-ui не делается: вкладки описаны в новой спеке, текст consolidated-osv-ui не правился, чтобы не смешивать UI-половины. Цена ошибки: при архивации две спеки частично описывают один компонент (OsvTabs).
  • 2026-10-22 (е). Спека переписана на целевое поведение (раунд 3 ревью): владелец решил, что спеки и тесты чужих PR ведём мы, а автор правит продуктовый код; целевая спека даёт автору однозначный ориентир, расхождения кода — в «Known issues». Цена ошибки: до исправлений спека и код ветки расходятся; PR не сливается, пока «Known issues» 1–4 не закрыты.
  • 2026-10-22 (ж). Выбрана одна сторона Дт/Кт — пустая таблица с текстом «Для расчёта по счетам выберите счета и в Дт, и в Кт» у таблицы и у фильтров, «Экспорт» матрицы недоступен. Альтернатива — оставить прежние данные с подсказкой; отвергнута: на экране были бы данные, не соответствующие фильтру. Цена ошибки: правка текста и одного условия.
  • 2026-10-22 (з). Правило отметок дерева по полному плану счетов (родитель отмечен ⇔ отмечены все потомки), в том числе при поиске. Обоснование: бэкенд разворачивает выбранный счёт в потомков, лишняя отметка родителя меняет расчёт. Цена ошибки: если аналитик захочет «родитель + выбранные субсчета» как отдельный режим — MODIFIED требования.
  • 2026-10-22 (и). Запасные имена файлов Шахматка_<ГК>_<год>_<квартал>.xlsx и Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx. Цена ошибки: низкая, имя из Content-Disposition приоритетнее.
  • 2026-10-22 (к). Тесты форматтера utils/chessTableCellFormatValue.test.ts написаны ревьюером: проверяют сдвиг единиц, точное округление, большие суммы, «-0,00» и пустые значения; случай нечислового значения в тыс./млн/млрд не покрыт — он в Known issues (5) и тест добавляется вместе с исправлением.
  • 2026-10-22 (л). В ветку влит main (PR #159), чтобы выгрузка результирующей таблицы работала на стенде из ветки.