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

16 KiB
Raw Blame History

Контракт 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 остаются).

Сохраняет все поля строки целиком (как в 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 (сокращено):

{
  "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"
  }
}