КФО к старту спринта 4: §8, DBML v5.26, контракт API КФО (AURORA-1546/1547, #206) #207
@ -174,9 +174,9 @@ side_1 AggregateSideOut дебетовая сторона (
|
|||||||
side_2 AggregateSideOut кредитовая сторона (компания 2)
|
side_2 AggregateSideOut кредитовая сторона (компания 2)
|
||||||
deviation_amount money
|
deviation_amount money
|
||||||
deviation_percent percent | null к меньшей стороне; null — меньшая сторона ≤ 0
|
deviation_percent percent | null к меньшей стороне; null — меньшая сторона ≤ 0
|
||||||
exceeds_threshold bool deviation_percent ≥ 5, или одна сторона пуста при ненулевой другой
|
exceeds_threshold bool deviation_percent ≥ 5, или одна сторона пуста при ненулевой другой; у min_or_full — всегда false
|
||||||
status "AUTO" | "DISCREPANCY" | "ONE_SIDED" | "MANUAL" как EliminationTotalItemOut
|
status "AUTO" | "DISCREPANCY" | "ONE_SIDED" | "MANUAL" как EliminationTotalItemOut
|
||||||
eliminated_amount money автоматическая сумма элиминации агрегата (§5), справочно
|
eliminated_amount money автосумма агрегата по режиму правила (§8 «КФО» п. 4) — её исключает КФО, если нет корректировки
|
||||||
composition_changed bool состав или суммы изменились после применённой корректировки (ответ 5; ответ п. 10 — подсвечивать)
|
composition_changed bool состав или суммы изменились после применённой корректировки (ответ 5; ответ п. 10 — подсвечивать)
|
||||||
correction CorrectionOut | null действующая корректировка (APPLIED; DRAFT — зарезервирован)
|
correction CorrectionOut | null действующая корректировка (APPLIED; DRAFT — зарезервирован)
|
||||||
```
|
```
|
||||||
@ -257,7 +257,12 @@ rule_id? (uuid, для ASSIGN)}`.
|
|||||||
агрегаты и нераспределённые строки (с `line_code` и `candidate_rule_ids`). Нынешняя упаковка считает каждое правило
|
агрегаты и нераспределённые строки (с `line_code` и `candidate_rule_ids`). Нынешняя упаковка считает каждое правило
|
||||||
отдельно (TODO в `intercompany_matrix.build_pairs`) — для таблицы корректировок строка должна попадать не более чем в одно
|
отдельно (TODO в `intercompany_matrix.build_pairs`) — для таблицы корректировок строка должна попадать не более чем в одно
|
||||||
правило.
|
правило.
|
||||||
- Правила ББ 1 и 2 (DOC-274230) имеют свой расчёт и не наследуют min; что идёт в `eliminated_amount` по ним — по DOC-274230.
|
- Правила ББ 1 и 2 (DOC-274230) имеют свой расчёт и не наследуют min. **Правило 2** — режим `min_or_full` (DBML v5.26,
|
||||||
|
`05-domain-rules.md` §8 «КФО» п. 4; seed и `services/correction_source.py` правятся в AURORA-1546): обе стороны > 0 →
|
||||||
|
`eliminated_amount = min`, `status = AUTO`; сторона 2 пуста → `eliminated_amount = amount_1`, `status = ONE_SIDED`;
|
||||||
|
сторона 1 пуста → 0, `ONE_SIDED`; `exceeds_threshold = false` всегда (порога 5 % у правила нет). **Правило 1** остаётся
|
||||||
|
`manual` (`status = MANUAL`, 0) до переработки seed (OQ-193). Автосумма — **та же функция, по которой считает КФО**:
|
||||||
|
что аналитик видит в `eliminated_amount`, то и исключает КФО, если корректировки нет (корректировка её заменяет).
|
||||||
- ОФР: тот же ответ с `statement_type = income` **(ждёт ответа в AURORA-1396)**; до него сервер может отдавать пустые
|
- ОФР: тот же ответ с `statement_type = income` **(ждёт ответа в AURORA-1396)**; до него сервер может отдавать пустые
|
||||||
`aggregates` и `unallocated` для `income`.
|
`aggregates` и `unallocated` для `income`.
|
||||||
|
|
||||||
|
|||||||
@ -284,7 +284,7 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: deviation_percent ≥ 5, или одна сторона пуста при ненулевой другой
|
description: deviation_percent ≥ 5, или одна сторона пуста при ненулевой другой
|
||||||
status: { type: string, enum: [AUTO, DISCREPANCY, ONE_SIDED, MANUAL] }
|
status: { type: string, enum: [AUTO, DISCREPANCY, ONE_SIDED, MANUAL] }
|
||||||
eliminated_amount: { $ref: '#/components/schemas/Money' }
|
eliminated_amount: { $ref: '#/components/schemas/Money', description: 'Автосумма агрегата по elimination_mode (min / min_or_full / manual; 05-domain-rules.md §8 «КФО» п. 4); её исключает КФО, если нет корректировки' }
|
||||||
composition_changed: { type: boolean, description: Состав или суммы изменились после применённой корректировки }
|
composition_changed: { type: boolean, description: Состав или суммы изменились после применённой корректировки }
|
||||||
correction:
|
correction:
|
||||||
oneOf:
|
oneOf:
|
||||||
|
|||||||
177
dev/api-contract-kfo.md
Normal file
177
dev/api-contract-kfo.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# Контракт API результата КФО (AURORA-1546 / AURORA-1547)
|
||||||
|
|
||||||
|
Контракт вкладки «КФО» отчёта версии консолидации — **до реализации** (docs #206, OpenSpec change
|
||||||
|
`kfo-calculation-contract`). Машиночитаемая копия — `dev/api-contract-kfo.openapi.yaml` с тремя полными примерами
|
||||||
|
ответа (их можно брать как фейк для экрана). Когда расчёт появится в `arm-core`, копия выгружается из `app.openapi()` и
|
||||||
|
сверяется тестом, как у гудвилла; если файлы разойдутся с кодом — прав код, оба файла правятся вслед за ним.
|
||||||
|
|
||||||
|
Источники, в порядке приоритета:
|
||||||
|
1. `05-domain-rules.md` §8 «КФО» — алгоритм (п. 1–12) и сквозной пример. Здесь формулы не повторяются — только
|
||||||
|
ссылки «п. N».
|
||||||
|
2. DBML v5.26: `kfo_result`, `kfo_result_line`, `kfo_result_line_company`, `consolidation_version`.
|
||||||
|
3. DOC-274647 «Экран: КФО» (черновик) и макет `[31-04]`, `[31-04-01]` — состав колонок, состояния экрана.
|
||||||
|
|
||||||
|
## 1. Общее
|
||||||
|
|
||||||
|
Как в `dev/api-contract-corrections.md` §1 и `dev/api-contract-goodwill.md` §1:
|
||||||
|
- префикс `/api/v1`, `Authorization: Bearer <JWT>`;
|
||||||
|
- **чтение — право `KFO_VIEW`** (не `CONSOLIDATION_VIEW`, как у корректировок и гудвилла: право в seed есть и означает
|
||||||
|
ровно это), **правки — `CONSOLIDATION_EDIT`** (`KFO_EDIT` в seed нет);
|
||||||
|
- версия вне видимости — 404 `NOT_FOUND`, как несуществующая;
|
||||||
|
- доменные ошибки — `{"detail": {"code", "message", ...}}`, 422 валидации тела — массив pydantic;
|
||||||
|
- **деньги — строки с двумя знаками в тыс. руб.** (`"588500.00"`), поле `units = "thousand_rub"`. Это отличие от
|
||||||
|
корректировок и гудвилла, где рубли: результат КФО по определению в тысячах (округление — часть расчёта, §8 «КФО»
|
||||||
|
п. 6), рубли из него не восстановить. Переключатели «Единицы» (тыс. / млн) и «Знаков после запятой» — только показ;
|
||||||
|
- проценты — строки с двумя знаками (`"70.42"`), `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. Понятия
|
||||||
|
|
||||||
|
- **Строки** — бланк ББ и ОФР редакции на отчётную дату версии (66н до 31.12.2024, ФСБУ 4 позже) плюс служебная
|
||||||
|
`GOODWILL` в разделе I сразу после 1170 (§8 «КФО» п. 1, 8). Приходят все строки бланка в его порядке (`ordinal`),
|
||||||
|
включая нулевые; `is_total` — итоговая строка.
|
||||||
|
- **По компании** (`companies[]` строки, порядок — как `KfoResultOut.companies`): «По данным клиента»
|
||||||
|
(`client_amount`), «В том числе взаимные обязательства / обороты» (`vgo_amount`), «Очищенные показатели»
|
||||||
|
(`cleaned_amount = client_amount − vgo_amount`), «Доля в показателе по группе, %» (`share_percent`). Строки расходов
|
||||||
|
(2120, 2210, 2220, 2330, 2350) — со знаком минус, и их `vgo_amount` тоже (п. 2, 6). У `GOODWILL` разреза нет.
|
||||||
|
- **По строке:** `sum_amount` (Σ клиента), `vgo_amount` (Σ взаимных = `eliminated_auto + eliminated_manual`),
|
||||||
|
`goodwill_adjust` (у `GOODWILL`, 1100, 1600), **`bank_amount`** — «КФО, подготовленная банком»
|
||||||
|
(`sum_amount − vgo_amount + goodwill_adjust`), `deviation_amount` — «Расхождения» (у итогов `null`), `comment`.
|
||||||
|
- **Сводка расхождений** (`summary.balance`, `summary.income`) — две плашки экрана: сумма расхождений, база (`base_kind`:
|
||||||
|
ЧА / ВБ / прибыль от продаж / выручка), предел и процент от базы, `exceeded` — красная плашка (п. 10). При превышении
|
||||||
|
у строки базы `is_threshold_base = true` — подсветка.
|
||||||
|
- **Обоснование** (`threshold_justification`) — принятие риска при превышении; `justification_required` — превышение
|
||||||
|
есть хотя бы по одному отчёту. Обязательность перед отправкой на верификацию проверяет переход статуса (AURORA-2002),
|
||||||
|
не этот API.
|
||||||
|
- **Реквизиты формы** (`requisites`, п. 11): ГК, ГСК, отчётная дата, номер и статус версии, сценарий, подход (пакет
|
||||||
|
документов), причины отклонений от Методики (`methodology_deviations` — редактируется здесь), решение УОБ (только
|
||||||
|
чтение), корректировки — число агрегатов с применённой корректировкой и Σ их исключений.
|
||||||
|
- **Предупреждения** (`warnings[]`, п. 12) — не блокируют: `FORM_MISSING`, `FORM_AMBIGUOUS`, `FORM_UNITS_UNKNOWN`,
|
||||||
|
`LINE_OUTSIDE_BLANK`, `UNALLOCATED_ROWS` (`count` — строк), `INCOME_RULES_MISSING`, `GOODWILL_NOT_APPLIED`,
|
||||||
|
`GOODWILL_ROW_REASSIGNED`. Тексты `message` — с сервера, фронт показывает как есть.
|
||||||
|
|
||||||
|
## 3. Эндпоинты
|
||||||
|
|
||||||
|
| Метод и путь | Право | Запрос | Ответ | Ошибки |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `GET /consolidations/versions/{version_id}/kfo` | `KFO_VIEW` | — | 200 `KfoResultOut` | 404 `NOT_FOUND` |
|
||||||
|
| `PUT /consolidations/versions/{version_id}/kfo/annotations` | `CONSOLIDATION_EDIT` | `KfoAnnotationsIn` | 200 `KfoResultOut` | 404 `NOT_FOUND`, 409 правок версии, 422 `UNKNOWN_LINE`, 422 валидации тела |
|
||||||
|
|
||||||
|
Выгрузки («Таблица», «Форма 2.03.01.01с») — AURORA-1565, отдельным контрактом.
|
||||||
|
|
||||||
|
### 3.1 `GET …/kfo` — результат
|
||||||
|
|
||||||
|
Весь результат одним ответом, без страниц. **Пока версия не заморожена, ответ — по текущим данным версии**: если
|
||||||
|
что-то изменилось после `computed_at` (документы, сопоставление, разнесение, корректировки, гудвилл), сервер
|
||||||
|
пересчитывает и сохраняет результат до ответа (как он это обнаруживает — AURORA-1417). Кнопки «Рассчитать» нет. У
|
||||||
|
замороженной версии (`is_frozen = true`, ставится при «Верифицирован») — сохранённый результат без пересчёта,
|
||||||
|
`editable = false`.
|
||||||
|
|
||||||
|
Версия без компаний или без форм — не ошибка: строки бланка с нулями и `warnings` (`FORM_MISSING` по каждой компании
|
||||||
|
и отчёту).
|
||||||
|
|
||||||
|
### 3.2 `PUT …/kfo/annotations` — ручные поля
|
||||||
|
|
||||||
|
Тело:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"comments": [{"statement_type": "balance", "line_code": "1520", "comment": "Акт сверки на 01.10 не получен"}],
|
||||||
|
"threshold_justification": "Расхождение по 1520 — сверка в работе; риск принят",
|
||||||
|
"methodology_deviations": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Поле, которого нет в теле, не меняется; `null` — очищает. Пустой объект `{}` — допустим, ничего не пишет.
|
||||||
|
- `comments[]` — только изменённые строки; `comment` ≤ 2000 символов, `null` или пустой после обрезки — очистить.
|
||||||
|
Строки нет в бланке версии (или `GOODWILL` в `income`) — 422 `UNKNOWN_LINE` с `detail.statement_type`,
|
||||||
|
`detail.line_code`; ничего не сохраняется.
|
||||||
|
- `threshold_justification`, `methodology_deviations` — ≤ 4000 символов; длиннее — 422 массивом pydantic.
|
||||||
|
- Обоснование можно сохранить и без превышения — сервер его не стирает; `justification_required` от этого не меняется.
|
||||||
|
- Всё одной транзакцией; комментарии и обоснование переживают пересчёт (по `statement_type`, `line_code`).
|
||||||
|
- Аудит — одно событие `KFO_EDIT` на запрос (`object_type = kfo_result`, раздел `KFO`), `before` / `after` — только
|
||||||
|
изменённые поля. Запрос без изменений аудит не пишет.
|
||||||
|
|
||||||
|
Ответ — `KfoResultOut` целиком (с пересчётом, если он нужен).
|
||||||
|
|
||||||
|
## 4. Схемы
|
||||||
|
|
||||||
|
Полностью — в OpenAPI. Кратко:
|
||||||
|
|
||||||
|
```
|
||||||
|
KfoResultOut
|
||||||
|
version_id uuid; computed_at date-time; is_frozen bool; editable bool; read_only_reason enum|null
|
||||||
|
units "thousand_rub"
|
||||||
|
companies[] {legal_entity_id, name, inn} — порядок колонок (по имени)
|
||||||
|
requisites KfoRequisitesOut
|
||||||
|
summary {balance: KfoThresholdOut, income: KfoThresholdOut}
|
||||||
|
justification_required bool; threshold_justification string|null
|
||||||
|
goodwill {enabled bool, total money}
|
||||||
|
balance, income {lines: KfoLineOut[]}
|
||||||
|
warnings[] KfoWarningOut {code, message, legal_entity_id?, statement_type?, count?}
|
||||||
|
|
||||||
|
KfoLineOut
|
||||||
|
line_code, line_name, ordinal, is_total, is_threshold_base
|
||||||
|
companies[] {legal_entity_id, client_amount, vgo_amount, cleaned_amount, share_percent|null} (у GOODWILL — [])
|
||||||
|
sum_amount, vgo_amount, eliminated_auto, eliminated_manual, goodwill_adjust, bank_amount money
|
||||||
|
deviation_amount money|null (у итогов null)
|
||||||
|
comment string|null
|
||||||
|
|
||||||
|
KfoThresholdOut
|
||||||
|
deviation_total money; base_kind NET_ASSETS|BALANCE_TOTAL|SALES_PROFIT|REVENUE; base_amount money
|
||||||
|
limit_percent "10.00"|"1.00"; limit_amount money; deviation_percent pct|null; exceeded bool
|
||||||
|
|
||||||
|
KfoRequisitesOut
|
||||||
|
company_group_name, related_group_name|null, reporting_date, version_no, version_status, scenario, approach
|
||||||
|
methodology_deviations|null, uob_decision_no|null, uob_decision_date|null
|
||||||
|
corrections_balance, corrections_income {count int, amount money}
|
||||||
|
|
||||||
|
KfoAnnotationsIn {comments?: [{statement_type, line_code, comment|null}], threshold_justification?, methodology_deviations?}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Состояния экрана (DOC-274647) → поля ответа
|
||||||
|
|
||||||
|
| Состояние | Как видно из ответа |
|
||||||
|
|---|---|
|
||||||
|
| Нет форм у части компаний | `warnings[].code = FORM_MISSING` с `legal_entity_id`, `statement_type`; у компании нули |
|
||||||
|
| ОФР не исключается автоматически | `INCOME_RULES_MISSING` (до AURORA-1999); взаимные обороты — только корректировками |
|
||||||
|
| Есть нераспределённые строки | `UNALLOCATED_ROWS`, `count` |
|
||||||
|
| Превышение порога | `summary.*.exceeded = true`, `is_threshold_base` у строки базы, `justification_required = true` |
|
||||||
|
| Гудвилл учтён | `goodwill.enabled = true`, `goodwill.total`, строка `GOODWILL` с `bank_amount` |
|
||||||
|
| Только чтение | `editable = false`, `read_only_reason`; при «Верифицирован» ещё `is_frozen = true` |
|
||||||
|
|
||||||
|
## 6. Примеры
|
||||||
|
|
||||||
|
Три полных ответа — в OpenAPI (`examples` у `GET …/kfo`), на числах сквозного примера §8 «КФО» (три компании, бланк
|
||||||
|
сокращён до строк примера; настоящий ответ содержит все строки бланка):
|
||||||
|
- `goodwill_exceeded` — гудвилл включён, превышение порога ББ (42 900 > 37 100), `justification_required = true`;
|
||||||
|
- `goodwill_disabled` — та же версия без учёта гудвилла: строка `GOODWILL` = 0, 1600 = 580 500;
|
||||||
|
- `frozen` — «Верифицирован»: `is_frozen`, `editable = false`, обоснование, комментарий 1520, реквизиты УОБ.
|
||||||
|
|
||||||
|
Фрагмент `goodwill_exceeded` — строка 1230:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"line_code": "1230", "line_name": "Дебиторская задолженность", "ordinal": 40,
|
||||||
|
"is_total": false, "is_threshold_base": false,
|
||||||
|
"companies": [
|
||||||
|
{"legal_entity_id": "1111…", "client_amount": "520000.00", "vgo_amount": "120000.00", "cleaned_amount": "400000.00", "share_percent": "70.42"},
|
||||||
|
{"legal_entity_id": "2222…", "client_amount": "130000.00", "vgo_amount": "10000.00", "cleaned_amount": "120000.00", "share_percent": "21.13"},
|
||||||
|
{"legal_entity_id": "3333…", "client_amount": "48000.00", "vgo_amount": "0.00", "cleaned_amount": "48000.00", "share_percent": "8.45"}
|
||||||
|
],
|
||||||
|
"sum_amount": "698000.00", "vgo_amount": "130000.00", "eliminated_auto": "100000.00", "eliminated_manual": "30000.00",
|
||||||
|
"goodwill_adjust": "0.00", "bank_amount": "568000.00", "deviation_amount": "2900.00", "comment": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Открытые вопросы
|
||||||
|
|
||||||
|
Варианты, принятые на старте, могут измениться по ответу заказчика — контракт меняется вместе с §8: OQ-180 (строки вне
|
||||||
|
бланка), OQ-181 (колонки), OQ-182 (значение без формы), OQ-183 (итоговая строка), OQ-184 (округление), OQ-185 (место
|
||||||
|
гудвилла), OQ-186 (объём расхождений), OQ-187 (ЧА), OQ-188 (нулевая база), OQ-189 (действие при превышении),
|
||||||
|
OQ-190/191 (подход по Методике, согласование клиентом — полей нет), OQ-192 (пересчёт).
|
||||||
2529
dev/api-contract-kfo.openapi.yaml
Normal file
2529
dev/api-contract-kfo.openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@ -653,6 +653,13 @@ legal_entity_id, counterparty_id, account_id, account_code, closing_debit?, clos
|
|||||||
Суммы — строки в рублях с двумя знаками, со знаком (как в шахматке); `deviation_amount = |ΣA − ΣB|`, `deviation_percent` —
|
Суммы — строки в рублях с двумя знаками, со знаком (как в шахматке); `deviation_amount = |ΣA − ΣB|`, `deviation_percent` —
|
||||||
к меньшей стороне, `null`, если она ≤ 0. Упаковка сумму элиминации не меняет: в КФО идёт `eliminated_amount` тройки.
|
к меньшей стороне, `null`, если она ≤ 0. Упаковка сумму элиминации не меняет: в КФО идёт `eliminated_amount` тройки.
|
||||||
|
|
||||||
|
### 5.7.3 Результат КФО (AURORA-1546/1547; контракт до реализации)
|
||||||
|
|
||||||
|
Вкладка «КФО» отчёта версии: `GET …/kfo` (право `KFO_VIEW`) и `PUT …/kfo/annotations` (`CONSOLIDATION_EDIT`, блокировка
|
||||||
|
версии). **Деньги — в тыс. руб.** (`units = "thousand_rub"`), не в рублях, как в остальных разделах. Полностью —
|
||||||
|
`dev/api-contract-kfo.md` и `dev/api-contract-kfo.openapi.yaml` (три полных примера ответа для фейка); правила —
|
||||||
|
`05-domain-rules.md` §8 «КФО».
|
||||||
|
|
||||||
### 5.8 Схемы ответов (кратко)
|
### 5.8 Схемы ответов (кратко)
|
||||||
|
|
||||||
Поля с `?` могут быть `null`, но ключ присутствует всегда. Полные схемы — `/openapi.json` и контракты по областям.
|
Поля с `?` могут быть `null`, но ключ присутствует всегда. Полные схемы — `/openapi.json` и контракты по областям.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user