From 22d5733d164e2112b972a21826300f2bc3b6767f Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Thu, 22 Oct 2026 16:42:00 +0400 Subject: [PATCH] =?UTF-8?q?docs(openspec):=20intercompany-matrix-ui=20?= =?UTF-8?q?=E2=80=94=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D1=81=D0=BA=D0=B8?= =?UTF-8?q?=D0=B5=20=C2=AB=D0=98=D1=82=D0=BE=D0=B3=D0=BE=C2=BB,=20=D0=B2?= =?UTF-8?q?=D0=B8=D0=B4=20=D1=8F=D1=87=D0=B5=D0=B5=D0=BA,=20=D1=80=D0=B5?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=80=D0=B0=D1=83=D0=BD=D0=B4?= =?UTF-8?q?=D0=B0=203=20(=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#158)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../changes/intercompany-matrix-ui/design.md | 45 ++++++++++++------- .../specs/intercompany-matrix-ui/spec.md | 25 ++++++----- .../changes/intercompany-matrix-ui/tasks.md | 9 ++-- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/openspec/changes/intercompany-matrix-ui/design.md b/openspec/changes/intercompany-matrix-ui/design.md index eafd997..35b62f3 100644 --- a/openspec/changes/intercompany-matrix-ui/design.md +++ b/openspec/changes/intercompany-matrix-ui/design.md @@ -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` у первого числа. Подпись «Период» (не «Квартал») — как в макете. Цена ошибки: правка вида ячейки. diff --git a/openspec/changes/intercompany-matrix-ui/specs/intercompany-matrix-ui/spec.md b/openspec/changes/intercompany-matrix-ui/specs/intercompany-matrix-ui/spec.md index e569e3d..bc16be6 100644 --- a/openspec/changes/intercompany-matrix-ui/specs/intercompany-matrix-ui/spec.md +++ b/openspec/changes/intercompany-matrix-ui/specs/intercompany-matrix-ui/spec.md @@ -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` один раз при открытии и строить из него два дерева по иерархии diff --git a/openspec/changes/intercompany-matrix-ui/tasks.md b/openspec/changes/intercompany-matrix-ui/tasks.md index 0cdaf87..ce4b124 100644 --- a/openspec/changes/intercompany-matrix-ui/tasks.md +++ b/openspec/changes/intercompany-matrix-ui/tasks.md @@ -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 (фронт).