arm-ka-docs/dev/api-contract-goodwill.md
Andrey Epifancev 31b8e41674 Контракт API таблицы гудвилла (AURORA-1543/1544)
Черновик для параллельной разработки бэкенда и фронта, по аналогии с
api-contract-corrections: фронт строит экран на фейковых данных, не
дожидаясь методологов (AURORA-1369, срок 02.11) и бэкенда.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-30 13:30:52 +04:00

191 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Контракт 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 <JWT>`;
- чтение — право `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"
}
}
```