Andrey Epifancev fd3bb79a9b fix(web): шахматка — отметки дерева счетов по полному дереву, стили тегов в css фильтра (AURORA-1538, ревью #158)
- toggleTreeCheck (utils/treeChecks): родитель отмечен, только если отмечены все потомки, на всех уровнях; скрытые
  поиском отметки берутся из состояния выпадашки — снятые подряд отметки больше не возвращаются; тесты.
- Правило тегов из App.css → ConsolidationChessTableFilter.css (App.css пустой, как в main); класс с формы ЮЛ снят.
- Спека: Known issues — остаток (одна сторона Дт/Кт) в техдолг AURORA-1799, решение (п), tasks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:41:28 +04:00

14 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. Перенос — технический долг: 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

Открытая проблема на момент слияния (решение владельца 23.10.2026 — сливать, остаток в техдолг AURORA-1799):

  1. Выбрана одна сторона Дт/Кт: «Экспорт» недоступен, но таблица показывает прежние данные, подсказка — всплывающее уведомление и постоянный текст внутри выпадающего окна, текста у таблицы и у фильтров нет. Целевое поведение — решение (ж).

Пункты раунда 3 про поиск в дереве счетов и стили закрыты ревьюером (решение (п)).

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» не закрыты.
  • 2026-10-22 (ж). Выбрана одна сторона Дт/Кт — пустая таблица с текстом «Для расчёта по счетам выберите счета и в Дт, и в Кт» у таблицы и у фильтров, «Экспорт» матрицы недоступен. Альтернатива — оставить прежние данные с подсказкой; отвергнута: на экране были бы данные, не соответствующие фильтру. Цена ошибки: правка текста и одного условия.
  • 2026-10-22 (з). Правило отметок дерева по полному плану счетов (родитель отмечен ⇔ отмечены все потомки), в том числе при поиске. Обоснование: бэкенд разворачивает выбранный счёт в потомков, лишняя отметка родителя меняет расчёт. Цена ошибки: если аналитик захочет «родитель + выбранные субсчета» как отдельный режим — MODIFIED требования.
  • 2026-10-22 (и). Запасные имена файлов Шахматка_<ГК>_<год>_<квартал>.xlsx и Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx. Цена ошибки: низкая, имя из Content-Disposition приоритетнее.
  • 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 у первого числа. Подпись «Период» (не «Квартал») — как в макете. Цена ошибки: правка вида ячейки.
  • 2026-10-23 (п). Остаток раунда 3 закрыт ревьюером, пункт про одну сторону Дт/Кт — в техдолг (решение владельца: «доправим сами, потом сольём»). Отметки дерева — чистая функция utils/treeChecks.toggleTreeCheck (правило (з) снизу вверх по полному дереву на всех уровнях; скрытые поиском отметки берутся из состояния выпадашки, а не из применённого фильтра — иначе снятые отметки возвращались), тесты utils/treeChecks.test.ts. Правило тегов из App.css перенесено в ConsolidationChessTableFilter.css, класс с формы ЮЛ снят. Пустая таблица с подсказкой при одной стороне — AURORA-1799. Цена ошибки: при одной стороне до AURORA-1799 на экране прежние данные, выгрузка недоступна.