Откатены к main правки справочников, шахматки, корректировок и types/api.ts (обработка ошибок, Alert, удалённые комментарии) — не относятся к AURORA-1544 и конфликтовали с #219/#221; шахматка переведена на общий фильтр единиц components/ConsolidationFormatTableFilter; удалены тестовые MOCK_DATA; формат. План доводки — docs/superpowers/plans/2026-11-06-goodwill-review-front.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
14 KiB
Гудвилл: доводка фронта по ревью (arm-core #220) — план
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: довести PR arm-core #220 (ветка feat/goodWill, AURORA-1544) до мержа: убрать правки вне задачи, влить main,
перевести вкладку «Гудвилл» на фактический API бэка (#222 после доводки по плану 2026-11-06-goodwill-review-back.md),
закрыть расхождения с DOC-259025 и макетом 31-03.
Architecture: чистые функции вкладки — web/src/utils/goodwill.ts (+ vitest); типы — web/src/types/goodwill/goodwill.ts
по схемам api/src/schemas/goodwill.py; запросы — web/src/services/api/goodwill.ts; экран —
web/src/widgets/ConsolidationGoodwill/*. Агрегаты (итоги «Всего» по ГО и по листу) фронт не считает — берёт groups[].totals
и totals из ответа.
Tech Stack: React 18 + TS strict, antd 6, vitest, biome + ESLint/Prettier.
Spec: контракт ../docs/dev/api-contract-goodwill.md (обновлён в docs #204), DOC-259025 «Гудвилл» §4–§6, макет
../docs/mockup/screens/31-03-goodwill.png, 31-03-01-goodwill-edit.png.
Рабочий каталог: /Users/andrey.epifancev/projects/awp-ca/.wt/review-220/arm-core (ветка feat/goodWill). Бэк для ручной
проверки — ветка feat/goodwill-back (worktree .wt/review-222/arm-core), пока #222 не в main.
Global Constraints
- Деньги — строки; арифметика только через
toCents/fromCents(utils/money.ts), никакихNumberнад суммами. null— «—»,0.00— ноль по формату единиц; нерассчитанный гудвилл не попадает ни в один фильтр знака.- Доля: ввод с запятой или точкой, 0–100, не больше двух знаков; ошибку показать у поля и заблокировать «Сохранить», значение не обрезать и не подменять.
- Все запросы — через
api/client.ts; ошибки показываются только дляApiError, ошибки валидации форм antd тостом не показываются. - Код вне
widgets/ConsolidationGoodwill,types/goodwill,services/api/goodwill.ts,utils/goodwill*,hooks/useFullScreen.tsx,components/ConsolidationFormatTableFilterи вкладок отчёта (ConsolidationReportPage.tsx,OsvTabs.tsx) совпадает сmain(кроме строки импорта фильтра вConsolidatedChessContent.tsx). - Коммиты — по-русски,
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>.
Review Focus
- Снять галочку у строки, где доля ни разу не вводилась: пакет уходит с
ownership_share: null, сервер отвечает 200. - Сервер вернул 422 по одной строке пакета: поле этой строки подсвечено, режим редактирования не закрыт, введённое не потеряно.
- «Выделить все» в блоке, где есть «Нет вложений» и скрытые фильтром строки: отмечаются все действующие строки блока, «Нет вложений» — нет.
- Версия без своей блокировки (
read_only_reason = LOCK_REQUIRED): «Редактировать» и переключатель недоступны, видна причина. - Фильтр «Положительные» + Экспорт: в файл уходит тот же фильтр (
sign=positive).
Task 1: Ветка — только гудвилл
Files:
-
Restore from
origin/main:web/src/layouts/CatalogueGroups.tsx,web/src/types/api.ts,web/src/widgets/CatalogueCompanyGroup/CompanyGroupForm/CompanyGroupForm.tsx,web/src/widgets/CatalogueJur/**,web/src/widgets/RelatedGroup/**,web/src/widgets/CorrectionTable/CorrectionContent.tsx,web/src/widgets/ConsolidationChess/**(кроме удаленияConsolidationChessFormatTableFilter— см. Step 2) -
Modify:
web/src/widgets/ConsolidationChess/ConsolidationChessContent/ConsolidatedChessContent.tsx(только импорт фильтра),web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent/ConsolidationGoodwillContent.tsx(удалитьMOCK_DATA) -
Step 1:
git merge origin/main(конфликты вCatalogueGroups.tsx,ConsolidatedChessContent.tsx,ConsolidationChessTable.tsx— брать сторонуmain), затемgit checkout origin/main -- <файлы из списка>. -
Step 2: общий фильтр единиц — оставить
components/ConsolidationFormatTableFilter, удалитьwidgets/ConsolidationChess/ConsolidationChessFormatTableFilter/, в шахматке поменять только импорт и имя компонента. -
Step 3:
git diff --stat origin/main...HEAD— изменены только файлы из Global Constraints;useFullscreenиспользует только вкладка гудвилла. -
Step 4: из
web/:npm run format, затемmake -C .. web-check,npm test,npm run lint— зелёные. -
Step 5: коммит «Гудвилл: ветка без правок вне задачи, влит main».
Task 2: Типы, запросы и чистые функции
Files:
- Modify:
web/src/types/goodwill/goodwill.ts,web/src/services/api/goodwill.ts - Create:
web/src/utils/goodwill.ts,web/src/utils/goodwill.test.ts
Interfaces:
-
Produces (типы, по
api/src/schemas/goodwill.pyветкиfeat/goodwill-back):GoodwillRow— суммыstring | null,has_investments: boolean,warnings: {code: string; message: string}[];GoodwillTotals+charter_capital_amount;GoodwillGroup {head_legal_entity: Ref; totals: GoodwillTotals};GoodwillTableResponse.groups: GoodwillGroup[];GoodwillRowKeyIn {head_legal_entity_id; subsidiary_legal_entity_id; ownership_share: string | null; include_in_kfo: boolean; comment: string | null};GoodwillSign = 'all' | 'positive' | 'negative' | 'zero'. -
Produces (запросы):
saveGoodwillRows(versionId, rows: GoodwillRowKeyIn[]): Promise<GoodwillTableResponse>(PUT …/goodwill, тело{rows});saveGoodwillSettings(versionId, {goodwill_enabled});exportGoodwillTable(versionId, sign: GoodwillSign)(?sign=).saveGoodwillRowудалить. -
Produces (
utils/goodwill.ts):rowKey(row: Pick<GoodwillRow,'head_legal_entity'|'subsidiary_legal_entity'>): string(${head}:${sub});parseShare(input: string): {ok: true; value: string | null} | {ok: false; error: string}(пусто →null; запятая → точка);previewAmounts(row: GoodwillRow, share: string | null, include: boolean): {participation: string | null; goodwill: string | null};matchesSign(goodwill: string | null, sign: GoodwillSign): boolean;changedRows(rows: GoodwillRow[], edits: Record<string, GoodwillEdit>): GoodwillRowKeyIn[], гдеGoodwillEdit = {include_in_kfo?: boolean; ownership_share?: string | null; comment?: string | null}. -
Step 1: тесты
goodwill.test.ts:parseShare:"80,12"→{ok, "80.12"},"100"ok,""→{ok, null},"80,123","100,01","-1","abc"→{ok:false};previewAmounts(DOC-259025 §11.1): ФВ"180000.00", УК"100000.00", доля"80", отмечена →{participation:"80000.00", goodwill:"100000.00"}; ФВ"50000.00"→ goodwill"-30000.00"; УК"371.17", доля"99.99"→ participation"371.13"(HALF_UP: 371.13288…); не отмечена или доляnullили УКnull→{null, null};matchesSign:null→ false для всех, кромеall;"0.00"— толькоzero/all;changedRows: правка, совпадающая с исходной строкой, не попадает; снятая галочка у строки без доли даётownership_share: null. -
Step 2:
npm test -- goodwill— FAIL; реализовать (previewAmounts— в копейках черезtoCents/fromCents, доля в сотых долях процентаBigInt,P = round(УК_коп × доля_сотых / 10000)HALF_UP); PASS. -
Step 3:
npx tsc --noEmit— ошибки только в компонентах вкладки (чинятся в Task 3); коммит «Гудвилл: типы и запросы по API бэка, чистые функции вкладки».
Task 3: Вкладка по API, DOC-259025 и макету
Files:
- Modify:
web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent/ConsolidationGoodwillContent.tsx,.../ConsolidationGoodwillTable/{ConsolidationGoodwillTable.tsx,config.tsx,ConsolidationGoodwillTable.css},.../ConsolidationGoodwillSummary/ConsolidationGoodwillSummary.tsx
Interfaces:
-
Consumes: Task 2.
-
Step 1: отображение. Суммы —
null→ «—», иначе формат единиц (ноль —0,00); строки «Нет вложений» (!has_investments) — серым, подпись «Нет вложений» в колонке сумм, чекбокс и поля недоступны;warnings— иконкаWarningOutlinedсTooltipизmessageу названия ДО; «Всего» блока — изgroups[].totals, «Итого по листу» — изtotals(безsumAmounts/Number). -
Step 2: режим «Редактировать». Правки —
Record<rowKey, GoodwillEdit>, стартует пустым; P и G в режиме —previewAmounts; доля —parseShareс ошибкой под полем; групповой чекбокс отмечает/снимает все действующие строки блока, включая скрытые фильтром,indeterminateпри частичном выборе; «Сохранить» недоступно, если у отмеченной действующей строки нет доли, доля с ошибкой или пустой комментарий; сохранение — одинsaveGoodwillRows(changedRows(...)), ответ заменяет таблицу и закрывает режим;ApiErrorсbody.detail.subsidiary_legal_entity_idподсвечивает поле этой строки (COMMENT_REQUIRED→ комментарий,INVALID_SHARE→ доля), режим не закрывается; «Отменить изменения» — сброс правок. -
Step 3: переключатель.
Switch«Учитывать гудвилл в КФО» в панели инструментов, значениеgoodwill_enabled, доступен приeditable; смена →saveGoodwillSettings, ответ заменяет таблицу; при выключенном — подпись «Гудвилл не учитывается в КФО». Если!editable— у «Редактировать»Tooltipс причиной (LOCK_REQUIRED— «Возьмите версию в работу»,LOCKED_BY_OTHER— «Версия в работе у другого пользователя»,VERSION_NOT_EDITABLE— «Версия недоступна для изменения»). -
Step 4: фильтр и экспорт. Варианты «Все значения», «Положительные», «Отрицательные», «Нулевые» через
matchesSign; экспорт передаёт текущийsign. -
Step 5:
npm run format,make -C .. web-check,npm test,npm run lint— зелёные; коммит «Гудвилл: вкладка по API и DOC-259025».
Task 4: UI-спека и проверка на стенде
Files:
-
Create:
openspec/changes/goodwill-ui/{proposal.md,design.md,tasks.md,specs/goodwill-ui/spec.md} -
Step 1: OpenSpec change
goodwill-ui— требования Steps 1–4 Task 3 со сценариями WHEN/THEN, ссылки на контракт и DOC-259025;design.md— раздел## Decisions made without discussion(R-1: правки вне задачи откатены; R-2: итоги с бэка; R-3: предпросмотр P/G только по строкам, итоги — после сохранения);openspec validate goodwill-ui --strict. -
Step 2: стенд. Поднять бэк из
.wt/review-222/arm-core(веткаfeat/goodwill-back, порт 8000, БД стенда), фронт отсюда (REACT_APP_ROOT_PATH=/ npm run start), версия «РБ 2024 Q3» или любая с ОСВ 58.01; в Playwright пройти: открыть вкладку, сверить с31-03-goodwill.png, «Редактировать» — сверить с31-03-01-goodwill-edit.png, ввести долю80,5и комментарий, сохранить, снять галочку у строки без доли и сохранить, переключить «Учитывать гудвилл», фильтр «Нулевые», экспорт. Скриншоты — в scratchpad, найденное — чинить в Task 3. -
Step 3: коммит «Гудвилл: UI-спека goodwill-ui».