Черновик для параллельной разработки бэкенда и фронта, по аналогии с api-contract-corrections: фронт строит экран на фейковых данных, не дожидаясь методологов (AURORA-1369, срок 02.11) и бэкенда. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
191 lines
16 KiB
Markdown
191 lines
16 KiB
Markdown
# Контракт 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"
|
||
}
|
||
}
|
||
```
|