19 KiB
Контракт API таблицы гудвилла (AURORA-1543 / AURORA-1544)
Контракт таблицы гудвилла версии консолидации — по факту реализации arm-core (#222, OpenSpec change goodwill-table).
Машиночитаемая копия — dev/api-contract-goodwill.openapi.yaml: она выгружена из app.openapi() и сверяется с
приложением тестом arm-core/api/tests/test_goodwill_contract.py. Если файлы расходятся, прав код, а оба файла
правятся вслед за ним.
Источники, в порядке приоритета:
- DOC-259025 «Гудвилл» (вики аналитики, версия 03.11.2026, Лысенко) — пары, жизненный цикл строк, формулы, итоги, проверки ввода.
05-domain-rules.md§8 «Гудвилл» — выжимка того же с решениями по допущениям.- DBML v5.24:
Table goodwill,consolidation_version.goodwill_enabled. - Макет
[31-03]«Гудвилл» (таблица, режим «Редактировать»).
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") илиnull;null— «не рассчитано», а не ноль. Перевод в тыс./млн руб. — на фронте, после суммирования; - доля владения — строка с двумя знаками (
"80.00") илиnull; - порядок проверок правок: право (403) → видимость (404) → версия редактируема (409
VERSION_NOT_EDITABLE,LOCK_REQUIRED,LOCKED_BY_OTHER) → операция. Фронт берётeditableиread_only_reasonиз ответа таблицы и правило сам не повторяет; у пользователя безCONSOLIDATION_EDIT—read_only_reason = "VERSION_NOT_EDITABLE".
2. Понятия
- Пара ГО → ДО. ГО — компания периметра, у которой в сводной ОСВ версии есть строки счёта
58.01или его потомков (поchart_of_account.parent_id) с сопоставленным контрагентом из периметра; этот контрагент — ДО. Признакis_head_entityне используется: одна компания может быть ГО в одном блоке и ДО в другом, встречные направления — разные пары. Пустой контрагент, вложение в себя и контрагент вне периметра пару не дают. Ручного добавления пар нет. - Финансовые вложения (
financial_investment_amount, ФВ) — сумма заполненныхclosing_debitподходящих строк пары; ФВ = 0 — пары нет. - «Нет вложений» (
has_investments = false). Сохранённая пара, которая больше не находится (замена ОСВ, нулевое сальдо, компания вышла из периметра). Строка остаётся с сохранёнными долей, комментарием и галочкой, все денежные поля —null, в итоги и КФО не входит. Повторное появление пары восстанавливает расчёт по текущим данным. - Уставный капитал ДО (
charter_capital_amount, УК) — стр.1310подтверждённого ББ ДО, привязанного к версии, по колонке конца отчётного квартала (не поis_current), в рублях: единицы формы читаются словарём единицarm_statements(«тыс.руб.», «в тысячах рублей» → тыс. руб.). Повторы кода 1310 суммируются. Ноль — допустимое значение. Нет ББ, строки 1310 или колонки даты, единицы не распознаны —nullи предупреждениеCAPITAL_SOURCE_MISSING; у ДО несколько подходящих ББ —nullиCAPITAL_SOURCE_AMBIGUOUS. - Добавочный капитал (
additional_capital_amount) — стр.1350того же ББ, справочно; в формулу не входит (ASSUMPTION OQ-10). - Доля владения (
ownership_share) — ручной ввод, % от0до100, не больше двух знаков после запятой. - Доля участия (
participation_amount, P) =round(УК × доля / 100, 2)(ROUND_HALF_UP), гудвилл (goodwill_amount, G) =ФВ − P, может быть отрицательным и нулевым. P и G считаются только у действующей отмеченной строки (include_in_kfo = true) с заполненными долей и УК, иначеnull. - Учёт в отчёте (
include_in_kfo) — галочка строки. У отмеченной действующей строки обязательны доля и непустой комментарий. Снятие галочки не стирает долю и комментарий. - Признак учёта гудвилла (
goodwill_enabled) — переключатель версии (решение OQ-27: на вкладке «Гудвилл», не в модалке создания). Выключен — таблица и ручной ввод не меняются, но в КФО ничего не уходит (goodwill_in_kfo_amount = "0.00"). - Предупреждения (
warnings[]) —{code, message}, не блокируют сохранение:CAPITAL_SOURCE_MISSING,CAPITAL_SOURCE_AMBIGUOUS(см. УК),OWNERSHIP_TOTAL_EXCEEDED— сумма заполненных долей действующих пар разных ГО в одной ДО больше 100 % (показывается у всех строк этой ДО).
3. Эндпоинты
| Метод и путь | Право | Запрос | Ответ | Ошибки |
|---|---|---|---|---|
GET /consolidations/versions/{version_id}/goodwill |
VIEW | — | 200 GoodwillTableOut |
404 NOT_FOUND |
PUT /consolidations/versions/{version_id}/goodwill |
EDIT | GoodwillBatchIn |
200 GoodwillTableOut |
404 NOT_FOUND (версия или пара), 409 правок версии, 422 INVALID_SHARE, COMMENT_REQUIRED, MONEY_OUT_OF_RANGE, DUPLICATE_ROW, 422 валидации тела |
PUT /consolidations/versions/{version_id}/goodwill-settings |
EDIT | GoodwillSettingsIn |
200 GoodwillTableOut |
404, 409 правок версии |
GET /consolidations/versions/{version_id}/goodwill/export?sign=all|positive|negative|zero |
VIEW | — | файл xlsx | 404 NOT_FOUND, 422 неизвестный sign |
3.1 GET …/goodwill — таблица
Все строки одним ответом, без страниц. Порядок строк — имя ГО, имя ДО, затем id; groups — в том же порядке ГО.
Чтение ничего не пишет (записи goodwill создаются только сохранением). Нет пар и сохранённых строк — rows = [],
groups = [], итоги "0.00".
3.2 PUT …/goodwill — сохранить набор строк
Тело — изменённые аналитиком строки целиком (ownership_share, include_in_kfo, comment каждой строки приходят
каждый раз). Пакет сохраняется в одной транзакции: сначала проверяются все строки, ошибка любой — ответ с её ключом
(detail.head_legal_entity_id, detail.subsidiary_legal_entity_id) и ничего не сохраняется.
- Пара должна быть в текущей таблице (действующая или «Нет вложений»), иначе 404
NOT_FOUNDс ключом пары. - Одна пара дважды в пакете — 422
DUPLICATE_ROW. ownership_share—nullили строка0…100, не больше двух знаков после запятой, запятая или точка ("80,5"="80.5"). Лишние знаки, отрицательные, экспонента — 422INVALID_SHARE(без округления). У отмеченной строки доля обязательна —nullдаётINVALID_SHARE.comment— до 1000 символов; у отмеченной строки пустой после обрезки — 422COMMENT_REQUIRED.- У строки «Нет вложений»
nullв доле или комментарии не стирает сохранённое значение. - Строка, ввод которой совпадает с сохранённым (или для пары без записи — с умолчанием «не отмечена, доли и комментария
нет»), не перезаписывается:
updated_by/updated_atне меняются, аудита нет. Поэтому фронт может отправлять весь набор отмеченных строк, но лучше — только изменённые. - У изменённой действующей строки вместе с вводом сохраняется снимок сумм (ФВ, УК, 1350, P, G); сумма вне
numeric(18,2)— 422MONEY_OUT_OF_RANGE. - Аудит —
GOODWILL_EDITна каждую изменённую строку (object_type = goodwill,before/after— строка ответа).
Ответ — пересчитанная таблица целиком (строки, итоги по ГО и общие).
3.3 PUT …/goodwill-settings — переключатель версии
Меняет consolidation_version.goodwill_enabled. Повтор прежнего значения ничего не пишет. Изменение — аудит
GOODWILL_EDIT (object_type = consolidation_version, changed_field = goodwill_enabled). Ручной ввод строк не
трогается.
3.4 GET …/goodwill/export — xlsx
Лист «Гудвилл»: восемь колонок экранной таблицы (Учёт в отчёте, Наименование дочерней организации, Доля владения,
Фондовые вложения головной организации, Доля участия ГО в УК, Уставный капитал, Гудвилл (+/−), Комментарий), блок на
каждую ГО со строкой «Всего», в конце — «Итого по листу». Деньги — в рублях, null — пустая ячейка; у строки «Нет
вложений» в колонке ФВ — текст «Нет вложений». sign оставляет
строки с гудвиллом нужного знака (нерассчитанные в фильтры по знаку не попадают), итоги остаются по полному составу.
Выгружается последнее сохранённое состояние. Имя — Гудвилл_<ГК>_<год>_<квартал>.xlsx в Content-Disposition
(filename*). Аудит EXPORT с {report: "goodwill", rows: <число строк в файле>}.
4. Схемы
Поля без ? есть всегда; null указан явно. money — строка с двумя знаками, share — строка с двумя знаками.
GoodwillTableOut
version_id uuid
goodwill_enabled bool
editable bool
read_only_reason null | "VERSION_NOT_EDITABLE" | "LOCK_REQUIRED" | "LOCKED_BY_OTHER"
rows[] GoodwillRowOut
groups[] GoodwillGroupOut итог «Всего» по каждой ГО
totals GoodwillTotalsOut «Итого по листу»
GoodwillRowOut
head_legal_entity Ref {id, name}
subsidiary_legal_entity Ref
ownership_share share | null
financial_investment_amount money | null null у «Нет вложений»
charter_capital_amount money | null null — нет однозначного 1310 или «Нет вложений»
additional_capital_amount money | null справочно, в формулу не входит
participation_amount money | null только у действующей отмеченной строки
goodwill_amount money | null может быть < 0 и = 0
include_in_kfo bool
comment string | null
has_investments bool
warnings[] {code, message}
updated_by Ref | null
updated_at datetime | null
GoodwillGroupOut {head_legal_entity: Ref, totals: GoodwillTotalsOut}.
GoodwillTotalsOut — по действующим строкам (без «Нет вложений»):
financial_investment_amount money все действующие строки, независимо от галочки
charter_capital_amount money все действующие строки (УК одной ДО у нескольких ГО входит несколько раз)
participation_amount money только отмеченные
goodwill_amount money только отмеченные, отрицательные и нулевые тоже
goodwill_in_kfo_amount money положительные G отмеченных строк с долей и комментарием; 0.00 при goodwill_enabled = false
GoodwillBatchIn {rows: GoodwillRowKeyIn[]} (минимум одна строка).
GoodwillRowKeyIn {head_legal_entity_id: uuid, subsidiary_legal_entity_id: uuid, ownership_share: string | null, include_in_kfo: bool, comment: string | null (≤ 1000)}.
GoodwillSettingsIn {goodwill_enabled: bool}.
5. Граница этапа и открытые вопросы
- КФО. Применение гудвилла в КФО (1170 ГО − ФВ, 1310 ДО − P, строка
GOODWILL+ G), исключение обычного ББ-2 по паре, пометка результата КФО устаревшим и фиксация при VERIFIED — задача AURORA-1546, этим API не делается. - OQ-10 — 1350 в базу участия не входит (DOC-259025 §6: «Для УК используется 1310»), колонка — справочно.
- OQ-37 — служебный код
GOODWILLдля строки КФО (DOC-259025 §7).
6. Что изменилось против черновика 30.10
- ГО — по фактическим вложениям 58.01, а не по
is_head_entity; строк «все ДО под каждой ГО» больше нет. - Новые поля строки:
has_investments,warnings; УК, 1350, P, G и ФВ — nullable. - Новые поля ответа:
groups[],totals.charter_capital_amount. - P и G — только у отмеченных строк; итоги P и G — по отмеченным.
- Доля — два знака, а не четыре.
- Построчный
PUT …/goodwill/{head}/{sub}заменён пакетнымPUT …/goodwill(одна транзакция, ответ — вся таблица). - У экспорта — параметр
sign.
7. Пример
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": "80.00",
"financial_investment_amount": "180000.00",
"charter_capital_amount": "100000.00",
"additional_capital_amount": "0.00",
"participation_amount": "80000.00",
"goodwill_amount": "100000.00",
"include_in_kfo": true,
"comment": "Доля подтверждена уставом",
"has_investments": true,
"warnings": [],
"updated_by": {"id": "u…", "name": "Иванов И. И."},
"updated_at": "2026-11-06T12:00:00Z"
},
{
"head_legal_entity": {"id": "a…", "name": "Альфа"},
"subsidiary_legal_entity": {"id": "c…", "name": "Гамма"},
"ownership_share": "80.00",
"financial_investment_amount": "50000.00",
"charter_capital_amount": "100000.00",
"additional_capital_amount": null,
"participation_amount": "80000.00",
"goodwill_amount": "-30000.00",
"include_in_kfo": true,
"comment": "Доля подтверждена уставом",
"has_investments": true,
"warnings": [],
"updated_by": null,
"updated_at": null
}
],
"groups": [
{
"head_legal_entity": {"id": "a…", "name": "Альфа"},
"totals": {
"financial_investment_amount": "230000.00",
"charter_capital_amount": "200000.00",
"participation_amount": "160000.00",
"goodwill_amount": "70000.00",
"goodwill_in_kfo_amount": "100000.00"
}
}
],
"totals": {
"financial_investment_amount": "230000.00",
"charter_capital_amount": "200000.00",
"participation_amount": "160000.00",
"goodwill_amount": "70000.00",
"goodwill_in_kfo_amount": "100000.00"
}
}
PUT /api/v1/consolidations/versions/7b…/goodwill:
{"rows": [
{"head_legal_entity_id": "a…", "subsidiary_legal_entity_id": "b…", "ownership_share": "80", "include_in_kfo": true, "comment": "Доля подтверждена уставом"},
{"head_legal_entity_id": "a…", "subsidiary_legal_entity_id": "d…", "ownership_share": null, "include_in_kfo": false, "comment": null}
]}
Ошибка строки:
{"detail": {"code": "COMMENT_REQUIRED", "message": "Укажите комментарий",
"head_legal_entity_id": "a…", "subsidiary_legal_entity_id": "b…"}}