# Proposal: Срез 4 — консолидация: версии, периметр, блокировка, привязка документов, сводная ОСВ, экспорт xlsx **Срез:** 4 (`../docs/context/09-delivery-plan.md`). **Репозиторий:** arm-core. **Issue:** RSHB/arm-core#18. **Родительский change:** `../docs/openspec/changes/slice-4-consolidation` (DBML v5.16, правила §2/§3/§9 по факту, OQ; RSHB/arm-ka-docs#19). Объём по решению владельца 06.10.2026: **бэкенд, API, экспорт xlsx**; UI (список, карточка, состав, вкладка ОСВ) делает другой разработчик по этим спекам. ## Why После Среза 2c строки ОСВ лежат в `osv_entry` по документам, но объекта «консолидация» в ядре нет: модели шести таблиц есть, сервисов, репозиториев и эндпоинтов нет; права `CONSOLIDATION_*` ни на одном маршруте не используются; `period_check = UNKNOWN`. Без Среза 4 нет периметра версии, нет сводной ОСВ, на которой стоят шахматка и ВГО (Срез 5), нет чек-листа комплекта и некуда показывать результат ручного сопоставления контрагентов. ## What Changes - **DBML v5.16**: enum `counterparty_match_kind` (`INN`, `NAME`, `ALIAS`, `MANUAL`, `PROPAGATED`) и колонка `osv_entry.counterparty_match_kind` — как появился `counterparty_id` (решение владельца 06.10.2026: строки, сопоставленные автоматически по имени или алиасу, должны выделяться в API). Миграция `0004_dbml_v5_16` с backfill по уже смапленным строкам. Таблиц 43, enum'ов 28. - **Маппинг (2c)** пишет `counterparty_match_kind` по шагу резолва (`CounterpartyIndex.resolve` возвращает шаг). - **Консолидации** (`consolidations-api`): `POST /consolidations` (ГК + ГСК + год + квартал → `consolidation`, `consolidation_version` №1 `INITIATED`, `consolidation_member` из текущего состава ГСК, минимум 2 ЮЛ); список по ГК с деревом версий; карточка версии с периметром, ответственным и ячейками чек-листа; `PUT …/members`; блокировка `POST/DELETE …/lock` с перехватом по причине; `POST …/status` (в Срезе 4 — только `CANCELLED` и возврат в `INITIATED`); чек-лист `GET …/checklist` (перенесён из Среза 3: без него негде показать пробелы кварталов). - **Привязка документов** (`documents-api`, `primary-files`): подтверждение документа привязывает его (`consolidation_document`) ко всем версиям в работе, которым он подходит по периметру и периоду, и двигает статус `INITIATED`/`DOCUMENTS_PROCESSING → DATA_CORRECTION`; создание версии и добавление ЮЛ подхватывают уже подтверждённые документы; автозамена файла и удаление ЮЛ из периметра снимают привязку. Загрузка файла принимает необязательный `consolidation_version_id` (`INITIATED → DOCUMENTS_PROCESSING`); маппинг документа `NEEDS_CHECK` для ЮЛ периметра — `DOCUMENTS_PROCESSING → DATA_CORRECTION`. - **Сводная ОСВ** (`consolidated-osv`): чистая функция `domain/consolidated_osv.py` от версии, периметра и привязанных ОСВ: приведение квартальных ОСВ к нарастающим (§2: ключ (счёт, контрагент), пропуск квартала → пробел, строки не строятся), признак контрагента ГСК/ГК/Внешний, дорезолв незаполненного `counterparty_id` на чтение (не сохраняется), `match_kind`/`match_stored`. `GET …/osv` (страница, фильтры), `GET …/osv/summary` (счётчики, пробелы), `GET …/counterparty-candidates`, `POST …/osv/entries/{id}/counterparty` (алиас, перенос алиаса, автоприменение, `OSV_COUNTERPARTY_MAP`), `GET …/osv/export` (xlsx, openpyxl, два листа, аудит `EXPORT`). - **Политика** (`directory-policy`): видимость консолидации = видимость её ГК; правки версии — только в статусе «в работе» и при своей активной блокировке. - **Аудит** (`audit-trail`): `CONSOLIDATION_CREATE`, `MEMBERSHIP_CHANGE`, `CONSOLIDATION_LOCK`, `CONSOLIDATION_LOCK_TAKEOVER`, `CONSOLIDATION_STATUS_CHANGE`, `OSV_COUNTERPARTY_MAP`, `EXPORT` — все с `consolidation_version_id`. - **Тесты**: домен без БД (приведение периодов, пробелы, признак), API на PostgreSQL, гонки блокировок, сквозной `fixtures`-тест: консолидация группы «Русский бисквит» за Q3 2024, одно ручное сопоставление → ГСК у всех строк «Пекарня Счастливочная». - **Документы**: README среза, CLAUDE.md, спеки. ## Capabilities ### New Capabilities - `consolidations-api`: создание, список, карточка, периметр, блокировка, статусы, чек-лист. - `consolidated-osv`: расчёт сводной ОСВ, кандидаты и ручное сопоставление контрагента, экспорт xlsx. ### Modified Capabilities - `data-model`: схема равна DBML **v5.16**, миграции 0001 → 0004. - `documents-api`: подтверждение документа привязывает его к версиям и меняет их статус. - `primary-files`: загрузка с `consolidation_version_id`; автозамена снимает привязку заменённых документов. - `osv-result-mapping`: `counterparty_match_kind` при резолве; переход версии в `DATA_CORRECTION` по `NEEDS_CHECK`. - `directory-policy`: видимость консолидаций и правило редактируемости версии. - `audit-trail`: события консолидации. ## Impact - **Таблицы DBML v5.16:** `consolidation`, `consolidation_version`, `consolidation_status_history`, `consolidation_lock`, `consolidation_member`, `consolidation_document`, `osv_entry` (новая колонка), `legal_entity_alias`, `required_document_rule`, `audit_event`. - **Правила:** §2 (приведение периодов), §3 (сводная ОСВ, ручное сопоставление), §9.1 (статусы Среза 4), §9.3 (`period_check` остаётся `UNKNOWN`, см. design D-12), §9.5 (отвязка при автозамене), §10 (права), `04-data-model-guide` («что не хранится»). - **Код:** новые `api/endpoints/consolidations/`, `services/consolidations.py`, `services/consolidation_locks.py`, `services/consolidation_documents.py`, `services/consolidated_osv.py`, `services/osv_export.py`, `repositories/consolidations.py`, `domain/consolidated_osv.py`, `domain/consolidation_periods.py`, `schemas/consolidations.py`; правки `services/documents.py`, `services/result_mapping.py`, `services/primary_files.py`, `repositories/counterparties.py`, `domain/policy.py`, `api/endpoints/files/upload.py`, миграция `0004`. - **Потребители:** фронт (2d/4-UI) — по этим спекам; tabular-parser и контракт v1.1 не меняются. ## Non-goals - Маршрут согласования после `DATA_CORRECTION` (`CONSOLIDATION_RF` и далее), УОБ, `ex_snapshot`, «Добавить версию», сценарий `CONFIRM`, подход `EXTENDED` — Срезы 6–7. Переходы в эти статусы отвечают 409 `TRANSITION_NOT_ALLOWED`. - Запрет загрузки/подтверждения документов в статусах после `DATA_CORRECTION` (ТЗ 03_9 A1) — Срез 7, OQ-118. - `period_check` документа по версии (OQ-120): остаётся `UNKNOWN`; подходящесть документа версии считается на лету. - Шахматка, пары ВГО, корректировки (Срез 5), ББ/ОФР из Excel (2b), PDF (Срез 3), UI (другой разработчик). - CSV чек-листа (макет `37`) — фронт строит из JSON. - Отвязка контрагента от строки (обратное действие): перевязка покрывает исправление ошибки. - Зоны ответственности в политике (OQ-86), истечение блокировки по времени (OQ-119).