# Контракт API таблицы гудвилла (AURORA-1543 / AURORA-1544) Черновик контракта для бэкенда (AURORA-1543, Цыганков) и фронта (AURORA-1544, Голов) — по аналогии с `dev/api-contract-corrections.md`: фронт строит экран по контракту на фейковых данных, не дожидаясь бэкенда, подключение к реальным ручкам — потом. Машиночитаемая копия — `dev/api-contract-goodwill.openapi.yaml`; при расхождении двух файлов правится тот, что ошибся, и оба держатся одинаковыми. Источники, в порядке приоритета: 1. **AURORA-1369** (решение методологов, срок 02.11.2026) — формула ещё не подтверждена, см. §5 «Открытые вопросы». Пока не закрыта, бэкенд не считает по-настоящему — но контракт (форма ответа, поля, эндпоинты) этим не затронут: методологи могут поменять *формулу* (входит ли 1350, источник УК), а не *набор полей* (поля `charter_capital_amount` / `additional_capital_amount` под обе ветки уже есть в DBML). 2. `05-domain-rules.md` §8 «Гудвилл» — текущий рабочий алгоритм (допущения OQ-10, OQ-37). 3. DBML v5.23, `Table goodwill`, `Table kfo_result_line` (`line_code = 'GOODWILL'`), `consolidation_version.goodwill_enabled`. 4. Макет: `[31-03]` «Гудвилл» (таблица, режим «Редактировать»), `[31-04]` «КФО» (строка «В т.ч. Гудвилл» под 1170). 5. ТЗ 6.7, Прил. 3 п. 2, Прил. 8 — только там, где остальное молчит. ## 1. Общее Всё как в `dev/api-contract-slice-4.md` §1 и `dev/api-contract-corrections.md` §1: - префикс `/api/v1`, `Authorization: Bearer `; - чтение — право `CONSOLIDATION_VIEW`, правки — `CONSOLIDATION_EDIT`; - версия вне видимости — 404 `NOT_FOUND`, как несуществующая; - доменные ошибки — `{"detail": {"code", "message", ...}}`, 422 валидации тела — массив pydantic; - **деньги — строки с двумя знаками** (`"1000000.00"`), всегда в **рублях**; перевод в тыс. руб. — на фронте; - порядок проверок правок: право (403) → видимость (404) → версия редактируема (409) → операция; коды — те же, что везде: 409 `VERSION_NOT_EDITABLE`, `LOCK_REQUIRED`, `LOCKED_BY_OTHER`. Фронт читает `editable` / `read_only_reason` из ответа таблицы, правило не повторяет. ## 2. Понятия - **Головная организация периметра (ГО)** — член версии консолидации с `is_head_entity = true` (как в `VersionCard.members[]`, `dev/api-contract-slice-4.md` §3). **Дочерняя организация (ДО)** — любой другой член периметра. Таблица гудвилла — по одной строке на каждую пару (ГО, ДО); строки не создаются и не удаляются пользователем, их состав определяется составом периметра (`PUT …/members`) на момент запроса. **Если в периметре несколько `is_head_entity`** — строки считаются для каждой ГО отдельно (как для независимых голов); на реальных данных такого пока не встречалось — ASSUMPTION, уточнить при первом расхождении. - **Фондовые вложения (`financial_investment_amount`, FV)** — `Σ closing_debit` счёта `58.01` ГО по контрагенту ДО (сводная ОСВ версии). Может быть `0.00` — строка всё равно показывается (полный список ДО периметра под каждой ГО, как в макете `[31-03]`). - **Уставный капитал ДО (`charter_capital_amount`, УК)** — стр. `1310` ББ ДО на отчётную дату; при наличии ОСВ ДО — `Кт 80 + Кт 83`, иначе `1310` из формы (§8 domain-rules, уточняет первую часть OQ-10). **Добавочный капитал (`additional_capital_amount`)** — стр. `1350` ББ ДО, считается и хранится всегда, независимо от того, участвует ли в формуле (см. OQ-10 ниже). - **Доля владения (`ownership_share`)** — ручной ввод аналитика, % (`numeric(7,4)`); единственное обязательное поле правки наряду с `comment`. - **Доля участия (`participation_amount`)** = `(charter_capital_amount [+ additional_capital_amount, если решение методологов это подтвердит]) × ownership_share / 100`. - **Гудвилл (`goodwill_amount`)** = `financial_investment_amount − participation_amount`; может быть отрицательным. - **Учёт в КФО (`include_in_kfo`)** — чекбокс «Учёт в отчёте» строки (макет `[31-03]`, с «Выделить все» по ГО на фронте — пакетное действие фронта, не отдельная ручка). Комментарий обязателен **только** когда `include_in_kfo = true` (ТЗ 6.7). Положительная сумма отмеченных строк уходит в `kfo_result_line` с `line_code = 'GOODWILL'` (раздел I КФО, допущение OQ-37) — расчёт и запись при построении результата КФО, не в этом контракте. - **Признак расчёта гудвилла (`goodwill_enabled`)** — переключатель версии (`consolidation_version.goodwill_enabled`, решено OQ-27: живёт на вкладке «Гудвилл», не в модалке создания). Сейчас в контракте нет ручки, которая бы его выставляла (только чтение через `VersionCard`, `dev/api-contract-slice-4.md`) — добавляется здесь (§3.2). Выключен — таблица показывается как есть (доли и комментарии не теряются), но ничего не уходит в КФО. ## 3. Эндпоинты | Метод и путь | Право | Запрос | Ответ | Ошибки | |---|---|---|---|---| | `GET /consolidations/versions/{version_id}/goodwill` | VIEW | — | 200 `GoodwillTableOut` | 404 `NOT_FOUND` | | `PUT /consolidations/versions/{version_id}/goodwill-settings` | EDIT | `GoodwillSettingsIn` | 200 `GoodwillTableOut` | 404, 409 правок версии | | `PUT /consolidations/versions/{version_id}/goodwill/{head_legal_entity_id}/{subsidiary_legal_entity_id}` | EDIT | `GoodwillRowIn` | 200 `GoodwillRowOut` | 404 `NOT_FOUND` (версия или пара не из периметра), 409 правок версии, 422 `COMMENT_REQUIRED`, 422 `INVALID_SHARE` | | `GET /consolidations/versions/{version_id}/goodwill/export` | VIEW | — | файл xlsx | 404 `NOT_FOUND` | ### 3.1 `GET …/goodwill` — таблица Все строки одним ответом (пар — единицы, не десятки; без страниц). Порядок: по имени ГО, внутри — по имени ДО. Группировку по ГО и подсчёт «Выделить все» делает фронт. Пустой периметр (только ГО, без ДО) — `rows = []`, это не ошибка. ### 3.2 `PUT …/goodwill-settings` — переключатель версии Меняет `consolidation_version.goodwill_enabled`. Аудит — новое действие в `audit_action` (например, `GOODWILL_ENABLED_CHANGE`), результат КФО помечается устаревшим при любом изменении значения (как в AURORA-1417). Выключение не трогает сохранённые строки (`ownership_share`, `comment`, `include_in_kfo` остаются). ### 3.3 `PUT …/goodwill/{head_legal_entity_id}/{subsidiary_legal_entity_id}` — сохранить строку Сохраняет **все поля строки целиком** (как в `PUT …/corrections/aggregates/…` — текущие `ownership_share`, `include_in_kfo` и `comment` приходят каждый раз, частичного `PATCH` нет). - `head_legal_entity_id` должен быть членом периметра с `is_head_entity = true`, `subsidiary_legal_entity_id` — любым другим членом периметра; иначе 404 `NOT_FOUND` (пары не существует). - `ownership_share` — строка `0`…`100`, до 4 знаков после запятой (`numeric(7,4)`); вне диапазона или больше 4 знаков — 422 `INVALID_SHARE`. - `comment` обязателен, если `include_in_kfo = true`; пустой после обрезки в этом случае — 422 `COMMENT_REQUIRED` (как `COMMENT_REQUIRED` в контракте корректировок); не длиннее 1000 символов. При `include_in_kfo = false` комментарий необязателен и может быть `null`. - `financial_investment_amount`, `charter_capital_amount`, `additional_capital_amount`, `participation_amount`, `goodwill_amount` в тело **не входят** — это вычисляемые поля, пересчитываются сервером из текущей ОСВ версии при каждом ответе, в запросе их нет. - Аудит `GOODWILL_ROW_EDIT` (поле нужно добавить в `audit_action`, как `CORRECTION_*` для корректировок) с `before`/`after`; результат КФО помечается устаревшим. Ответ — пересчитанная строка (а не вся таблица — в отличие от корректировок, строки гудвилла друг на друга не влияют). ### 3.4 `GET …/export` — xlsx Таблица гудвилла одним листом, группировка по ГО, итоговая строка «Всего» (макет `[31-03]`). Имя файла — `Гудвилл_<название ГК>_<год>_<квартал>.xlsx` в `Content-Disposition` (как в экспорте корректировок). Аудит `EXPORT`. ## 4. Схемы Поля без `?` есть всегда; `null` указан явно. **`GoodwillTableOut`** ``` version_id uuid goodwill_enabled bool editable bool read_only_reason null | "VERSION_NOT_EDITABLE" | "LOCK_REQUIRED" | "LOCKED_BY_OTHER" rows[] GoodwillRowOut totals GoodwillTotalsOut ``` **`GoodwillRowOut`** ``` head_legal_entity Ref {id, name} subsidiary_legal_entity Ref ownership_share share | null % 4 знака; null — ещё не введена financial_investment_amount money charter_capital_amount money additional_capital_amount money participation_amount money goodwill_amount money может быть отрицательным include_in_kfo bool comment string | null updated_by Ref | null updated_at datetime | null ``` **`GoodwillTotalsOut`** — сумма по всем строкам ответа: `{financial_investment_amount, participation_amount, goodwill_amount}`, плюс `goodwill_in_kfo_amount` — сумма `goodwill_amount` только по строкам с `include_in_kfo = true` и положительным `goodwill_amount` (то, что реально уйдёт в `kfo_result_line.line_code = 'GOODWILL'`). **`GoodwillRowIn`** `{ownership_share (share-строка 0…100), include_in_kfo (bool), comment (string | null, обязателен при include_in_kfo = true, ≤ 1000 символов)}`. **`GoodwillSettingsIn`** `{goodwill_enabled (bool)}`. ## 5. Открытые вопросы (AURORA-1369, срок 02.11.2026) - **OQ-10** — входит ли стр. 1350 (добавочный капитал) в базу участия. Допущение сейчас: **нет**, `participation_amount` считается только от `charter_capital_amount`; `additional_capital_amount` хранится и показывается в таблице (колонка есть и в DBML, и на фронте — макет её не показывает явно, но поле в `goodwill` есть с пометкой ADD), но не входит в формулу. Если методологи подтвердят, что 1350 нужен — меняется только формула на бэкенде, контракт не меняется. - **OQ-37** — код строки «Гудвилл» в результате КФО: служебный `GOODWILL` (как в DBML, принято этим контрактом) или `1105` как в распознанной форме ББ (ФСБУ 4/2023). Контракта это не касается напрямую (он про таблицу `goodwill`, не про `kfo_result_line`), но влияет на отдельную задачу построения КФО — не блокирует 1543/1544. - Несколько `is_head_entity` в одном периметре — не встречалось на фикстурах, поведение не проверено отдельно. **Фронт (AURORA-1544) ничего из этого не ждёт** — строит экран по схемам §4 на фейковых данных; поля не меняются от исхода открытых вопросов, меняются только числа внутри них. ## 6. Пример `GET /api/v1/consolidations/versions/7b…/goodwill` (сокращено): ```json { "version_id": "7b1c…", "goodwill_enabled": true, "editable": true, "read_only_reason": null, "rows": [ { "head_legal_entity": {"id": "a…", "name": "АО «Русский бисквит»"}, "subsidiary_legal_entity": {"id": "b…", "name": "ООО «Пекарня Счастливочная»"}, "ownership_share": "100.0000", "financial_investment_amount": "5000000.00", "charter_capital_amount": "4500000.00", "additional_capital_amount": "0.00", "participation_amount": "4500000.00", "goodwill_amount": "500000.00", "include_in_kfo": true, "comment": "Доля подтверждена уставом от 01.01.2024", "updated_by": {"id": "u…", "name": "Иванов И. И."}, "updated_at": "2026-10-30T12:00:00+03:00" } ], "totals": { "financial_investment_amount": "5000000.00", "participation_amount": "4500000.00", "goodwill_amount": "500000.00", "goodwill_in_kfo_amount": "500000.00" } } ```