From 5f2b0e890f48385ac4f26eb608cf6592c457adfe Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Fri, 6 Nov 2026 18:44:02 +0400 Subject: [PATCH] =?UTF-8?q?=D0=93=D1=83=D0=B4=D0=B2=D0=B8=D0=BB=D0=BB:=20U?= =?UTF-8?q?I-=D1=81=D0=BF=D0=B5=D0=BA=D0=B0=20goodwill-ui,=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=BA=D0=B5=20=D0=BD=D0=B0=20=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BD=D0=B4=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenSpec change goodwill-ui (таблица, редактирование, переключатель/фильтр/экспорт; вкладка «Гудвилл» в intercompany-matrix-ui больше не заглушка; R-1…R-3). По стенду: стрелка раскрытия блока — у названия, «Выделить все» в одну строку, текст пустой таблицы. Co-Authored-By: Claude Opus 5.5 --- openspec/changes/goodwill-ui/.openspec.yaml | 2 + openspec/changes/goodwill-ui/design.md | 26 ++++++++ openspec/changes/goodwill-ui/proposal.md | 29 +++++++++ .../goodwill-ui/specs/goodwill-ui/spec.md | 62 +++++++++++++++++++ .../specs/intercompany-matrix-ui/spec.md | 38 ++++++++++++ openspec/changes/goodwill-ui/tasks.md | 6 ++ .../ConsolidationGoodwillTable.tsx | 3 +- .../ConsolidationGoodwillTable/config.tsx | 4 +- 8 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 openspec/changes/goodwill-ui/.openspec.yaml create mode 100644 openspec/changes/goodwill-ui/design.md create mode 100644 openspec/changes/goodwill-ui/proposal.md create mode 100644 openspec/changes/goodwill-ui/specs/goodwill-ui/spec.md create mode 100644 openspec/changes/goodwill-ui/specs/intercompany-matrix-ui/spec.md create mode 100644 openspec/changes/goodwill-ui/tasks.md diff --git a/openspec/changes/goodwill-ui/.openspec.yaml b/openspec/changes/goodwill-ui/.openspec.yaml new file mode 100644 index 0000000..8a94d76 --- /dev/null +++ b/openspec/changes/goodwill-ui/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-11-06 diff --git a/openspec/changes/goodwill-ui/design.md b/openspec/changes/goodwill-ui/design.md new file mode 100644 index 0000000..196dd0f --- /dev/null +++ b/openspec/changes/goodwill-ui/design.md @@ -0,0 +1,26 @@ +## Context + +Экран — по контракту `../docs/dev/api-contract-goodwill.md`, DOC-259025 §4–§6 и макету `[31-03]`, `[31-03-01]`. Суммы — +строки, арифметика только в копейках (`utils/money.ts`), чистые функции вкладки — `utils/goodwill.ts` с vitest. + +## Decisions + +- Итоги «Всего» и «Итого по листу» берутся из ответа (`groups[].totals`, `totals`), фронт их не считает. +- В режиме редактирования P и G строки — предпросмотр (`previewAmounts`, та же формула и округление, что на бэке). +- Сохранение — один `PUT …/goodwill` с изменёнными строками (`changedRows`); ошибка строки (422 с ключом пары) + подсвечивает поле этой строки, режим не закрывается. +- Переключатель `goodwill_enabled` меняется вне режима редактирования, отдельным запросом. + +## Decisions made without discussion + +Ревью arm-core #220 (06.11.2026, владелец: «давай всё сделаем сами»). + +- **R-1 (2026-11-06). Правки вне задачи в PR откатены к `main`.** Обработка ошибок в 8 файлах справочников, `Alert` в + `CatalogueJurTable`, удалённые комментарии в `types/api.ts`, шахматке и корректировках. Обоснование: не относятся к + AURORA-1544, давали ложный тост на незаполненной форме (`validateFields` бросает не `Error`) и конфликтовали с #219/#221. + Оставлены общий фильтр единиц и `useFullscreen` (используется только вкладкой гудвилла). Цена ошибки: если правки нужны — + отдельной задачей. +- **R-2 (2026-11-06). Итоги — только с бэка** (правило владельца «агрегаты отдаёт бэк»). Цена ошибки: нет. +- **R-3 (2026-11-06). Предпросмотр — только у строк;** «Всего» и «Итого по листу» в режиме правки показывают сохранённое + и обновляются после «Сохранить». Обоснование: агрегаты не считаем на фронте (R-2). Цена ошибки: аналитик видит итог + после сохранения, а не во время ввода (DOC-259025 §5.1 п. 3 говорит «предварительные … итоги»). diff --git a/openspec/changes/goodwill-ui/proposal.md b/openspec/changes/goodwill-ui/proposal.md new file mode 100644 index 0000000..e784ddb --- /dev/null +++ b/openspec/changes/goodwill-ui/proposal.md @@ -0,0 +1,29 @@ +## Why + +AURORA-1544: вкладка «Гудвилл» страницы отчёта версии. Первая версия экрана (PR arm-core #220, Голов) строилась на +фейковых данных по черновику контракта 30.10, а бэкенд (#222, AURORA-1543) сделан по аналитике DOC-259025 «Гудвилл» +(Лысенко, 03.11.2026): пары по фактическим вложениям, строки «Нет вложений», nullable суммы, предупреждения, итоги по ГО, +пакетное сохранение. Ревью 06.11.2026: экран переведён на фактический API и DOC-259025. + +## What Changes + +Репозиторий — arm-core, только `web/`. Контракт — `../docs/dev/api-contract-goodwill.md` (docs #204). + +- Вкладка «Гудвилл» (`…/versions/{id}/goodwill`) доступна. +- Таблица по макету `[31-03]`: блоки ГО, строки ДО, «Всего» блока и «Итого по листу» из ответа (`groups`, `totals`). +- Режим «Редактировать» (`[31-03-01]`): галочки, доля, комментарий, предпросмотр P/G, пакетное сохранение. +- Переключатель «Учитывать гудвилл в КФО» (`goodwill_enabled`, OQ-27), фильтр знака, экспорт с фильтром. + +## Capabilities + +### New Capabilities +- `goodwill-ui`: вкладка «Гудвилл». + +### Modified Capabilities +- `intercompany-matrix-ui`: вкладка «Гудвилл» больше не заглушка. + +## Impact + +`web/src/widgets/ConsolidationGoodwill/*`, `web/src/utils/goodwill.ts` (+ тесты), `web/src/types/goodwill/goodwill.ts`, +`web/src/services/api/goodwill.ts`, `web/src/hooks/useFullScreen.tsx`, общий фильтр единиц +`web/src/components/ConsolidationFormatTableFilter` (шахматка переведена на него), вкладки отчёта. diff --git a/openspec/changes/goodwill-ui/specs/goodwill-ui/spec.md b/openspec/changes/goodwill-ui/specs/goodwill-ui/spec.md new file mode 100644 index 0000000..0424a29 --- /dev/null +++ b/openspec/changes/goodwill-ui/specs/goodwill-ui/spec.md @@ -0,0 +1,62 @@ +## ADDED Requirements + +### Requirement: Таблица гудвилла +Вкладка `goodwill` страницы отчёта версии SHALL загружать таблицу одним запросом `GET /consolidations/versions/{id}/goodwill` +(контракт `../docs/dev/api-contract-goodwill.md`) и показывать блоки по ГО в порядке ответа: строка ГО, строки ДО, строка +«Всего» блока из `groups[].totals`, внизу «Итого по листу» из `totals`. Колонки — по макету `[31-03]`: «Учет в отчете», +«Наименование дочерней организации», «Доля владения», «Фондовые вложения головной организации», «Доля участия головной +организации в уставном капитале», «Уставный капитал», «Гудвилл (+/-)», «Комментарий». Сумма `null` SHALL показываться +прочерком, ноль — нулём в выбранных единицах; итоги фронт MUST NOT считать сам. + +#### Scenario: Нулевой и нерассчитанный гудвилл +- **WHEN** у одной строки `goodwill_amount = "0.00"`, у другой `null` +- **THEN** первая показывает «0,00», вторая — «—» + +#### Scenario: Строка «Нет вложений» +- **WHEN** у строки `has_investments = false` +- **THEN** строка серая, с меткой «Нет вложений», чекбокс недоступен, суммы — прочерки, сохранённые доля и комментарий видны + +#### Scenario: Предупреждения +- **WHEN** у строки есть `warnings` (например, `CAPITAL_SOURCE_MISSING`) +- **THEN** рядом с названием ДО иконка предупреждения, по наведению — тексты `message` + +### Requirement: Редактирование таблицы гудвилла +Кнопка «Редактировать» SHALL быть доступна при `editable = true`; иначе — недоступна с подсказкой причины +(`read_only_reason`). В режиме редактирования (баннер «Доступны для редактирования столбцы «Доля владения» и +«Комментарий».») у действующих строк доступна галочка; у отмеченной действующей строки — поля доли и комментария, P и G +строки SHALL пересчитываться предварительно по введённой доле. Доля — 0–100, не больше двух знаков, запятая или точка; +ошибочная доля MUST NOT обрезаться или подменяться, а показывается ошибкой у поля. «Сохранить» SHALL быть недоступно, +пока у отмеченной действующей строки нет корректной доли или комментария. Групповой чекбокс блока SHALL отмечать и снимать +все действующие строки блока, включая скрытые фильтром, и показывать промежуточное состояние при частичном выборе. +«Отменить изменения» SHALL возвращать последнее сохранённое состояние. + +#### Scenario: Сохранение набора +- **WHEN** аналитик отметил две строки, ввёл доли «80,5» и «100» и комментарии и нажал «Сохранить» +- **THEN** уходит один `PUT …/goodwill` только с изменёнными строками; ответ заменяет таблицу, режим редактирования закрывается + +#### Scenario: Снятие галочки у строки без доли +- **WHEN** аналитик снимает галочку у строки, где доля не вводилась, и сохраняет +- **THEN** строка уходит с `ownership_share: null` и сохраняется без ошибки + +#### Scenario: Ошибка строки от сервера +- **WHEN** сервер отвечает 422 `COMMENT_REQUIRED` с ключом пары +- **THEN** поле комментария этой строки подсвечено ошибкой, режим редактирования не закрыт, введённое не потеряно + +#### Scenario: Лишние знаки доли +- **WHEN** аналитик вводит долю «80,123» +- **THEN** у поля ошибка «Число от 0 до 100, не больше двух знаков после запятой», значение в поле не меняется, «Сохранить» недоступно + +### Requirement: Переключатель, фильтр и экспорт гудвилла +Панель вкладки SHALL содержать переключатель «Учитывать гудвилл в КФО» (`PUT …/goodwill-settings`, доступен при +`editable` вне режима редактирования) с подписью суммы `goodwill_in_kfo_amount` или «Гудвилл не учитывается в КФО»; +фильтр «Гудвилл»: «Все значения», «Положительные», «Отрицательные», «Нулевые» (нерассчитанный гудвилл — только во «Все +значения»); единицы и знаки после запятой; «Настройка таблицы»; «Экспорт» — `GET …/goodwill/export` с текущим фильтром +(`sign`); «На весь экран». + +#### Scenario: Экспорт с фильтром +- **WHEN** выбран фильтр «Положительные» и нажат «Экспорт» +- **THEN** запрос уходит с `sign=positive` + +#### Scenario: Выключение гудвилла +- **WHEN** аналитик выключает переключатель +- **THEN** таблица перечитывается из ответа, под переключателем подпись «Гудвилл не учитывается в КФО», ручной ввод строк не меняется diff --git a/openspec/changes/goodwill-ui/specs/intercompany-matrix-ui/spec.md b/openspec/changes/goodwill-ui/specs/intercompany-matrix-ui/spec.md new file mode 100644 index 0000000..88185e4 --- /dev/null +++ b/openspec/changes/goodwill-ui/specs/intercompany-matrix-ui/spec.md @@ -0,0 +1,38 @@ +## MODIFIED Requirements + +### Requirement: Вкладки страницы отчёта по версии +Страница `/groups/:group_id/versions/:version_id/:tab` SHALL показывать шапку версии (ГК, период, статус отчёта) один раз +и под ней ряд вкладок шагов консолидации и содержимое активной вкладки. Активная вкладка определяется сегментом `:tab`: +`osv` — «ОСВ» (сводная ОСВ), `chess` — «Шахматка», `correction` — «Таблица корректировки» (спека `corrections-table-ui`), `goodwill` — «Гудвилл» (спека `goodwill-ui`). +Выбор вкладки SHALL менять последний сегмент адреса на ключ вкладки +(навигация, не локальное состояние) заменой текущей записи истории браузера, без новой записи: кнопка «Назад» в шапке и +кнопка «Назад» браузера ведут туда, откуда открыт отчёт, а не по переключениям вкладок (AURORA-1851). Активная вкладка +подсвечена зелёным и выделена жирным. Неизвестный ключ вкладки SHALL +заменяться на `osv` без новой записи в истории браузера. Вкладки «КФО», «КФО Общий», +«Подтверждение КФО клиента» SHALL быть недоступны с подсказкой «Будет в следующих срезах». При смене `version_id` всё +состояние страницы (карточка версии, данные, фильтры) SHALL создаваться заново. + +#### Scenario: Переход на шахматку +- **WHEN** открыта сводная ОСВ версии по адресу `…/versions/{id}/osv` и нажата вкладка «Шахматка» +- **THEN** адрес становится `…/versions/{id}/chess`, шапка версии остаётся, под вкладками показана шахматка + +#### Scenario: Переход на таблицу корректировки +- **WHEN** открыта шахматка версии по адресу `…/versions/{id}/chess` и нажата вкладка «Таблица корректировки» +- **THEN** адрес становится `…/versions/{id}/correction`, шапка версии остаётся, под вкладками показана таблица корректировок + +#### Scenario: Прежний адрес сводной ОСВ +- **WHEN** открыт адрес `…/versions/{id}/osv` +- **THEN** показана сводная ОСВ, вкладка «ОСВ» активна + +#### Scenario: Неизвестная вкладка +- **WHEN** открыт адрес `…/versions/{id}/abc` +- **THEN** адрес заменяется на `…/versions/{id}/osv`, показана сводная ОСВ; кнопка «Назад» браузера не возвращает на `…/abc` + +#### Scenario: Назад после переключения вкладок +- **WHEN** аналитик открыл отчёт версии кнопкой «К отчётности» в списке консолидаций, переключился «Шахматка» → «ОСВ» → + «Шахматка» и нажал «Назад» в шапке +- **THEN** одним нажатием открыт список консолидаций ГК + +#### Scenario: Переход на гудвилл +- **WHEN** открыта таблица корректировки версии и нажата вкладка «Гудвилл» +- **THEN** адрес становится `…/versions/{id}/goodwill`, шапка версии остаётся, под вкладками показана таблица гудвилла diff --git a/openspec/changes/goodwill-ui/tasks.md b/openspec/changes/goodwill-ui/tasks.md new file mode 100644 index 0000000..51f1cef --- /dev/null +++ b/openspec/changes/goodwill-ui/tasks.md @@ -0,0 +1,6 @@ +## 1. Доводка по ревью (план docs/superpowers/plans/2026-11-06-goodwill-review-front.md) + +- [x] 1.1 Ветка без правок вне задачи, влит main (R-1). +- [x] 1.2 Типы и запросы по API бэка, чистые функции `utils/goodwill.ts` с тестами. +- [x] 1.3 Вкладка по API, DOC-259025 и макету. +- [x] 1.4 UI-спека `goodwill-ui`, проверка на стенде. diff --git a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx index 4253d7c..4ac6abf 100644 --- a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx +++ b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx @@ -66,12 +66,13 @@ export const ConsolidationGoodwillTable: React.FC = rowKey='key' pagination={false} loading={loading} + locale={{ emptyText: 'Вложений по 58.01 между компаниями периметра нет' }} scroll={{ x: 'max-content', y: isFullscreen ? 'calc(100vh - 200px)' : undefined }} size='small' bordered title={() => toolbar} key={treeData.map((g) => g.key).join('|')} - expandable={{ defaultExpandAllRows: true }} + expandable={{ defaultExpandAllRows: true, expandIconColumnIndex: 1 }} summary={() => } rowClassName={rowClassName} /> diff --git a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/config.tsx b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/config.tsx index e636d24..bd4e473 100644 --- a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/config.tsx +++ b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/config.tsx @@ -88,7 +88,7 @@ export const getGoodwillColumns = ({ { title: 'Учет в отчете', key: 'include_in_kfo', - width: 120, + width: 150, align: 'center', render: (_, node) => { if (node.kind === 'total') return —; @@ -101,7 +101,7 @@ export const getGoodwillColumns = ({ checked={active.length > 0 && checked === active.length} indeterminate={checked > 0 && checked < active.length} onChange={(e) => onToggleGroup(node.headId, e.target.checked)}> - + Выделить все