`LegalEntityOut.memberships` — в журнале изменений гайда фронта, таблице справочников и
контракте files-directories; убран совет брать членства из `related-groups/{id}` или карточки.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
15 KiB
Контракт API: файлы и документы организации, справочники (для экранов до сводной ОСВ)
Источник — реальный код arm-core (api/src/schemas/files.py, schemas/documents.py, schemas/directories.py,
schemas/common.py, api/endpoints/files/{upload,read,documents}.py, api/endpoints/directories/*.py; Swagger — /docs).
Маршруты существуют со Срезов 1 и 2c; здесь они впервые описаны для фронта (arm-core #42, П-5). Общие правила (префикс, токен,
формат ошибок, видимость 404) — dev/api-contract-slice-4.md §1; форма ББ/ОФР, комментарии, исходный файл — dev/api-contract-slice-3b.md;
консолидации — dev/api-contract-slice-4.md. Экраны — context/10-user-journey.md, номера […] — снимки макета (mockup/INDEX.md).
1. Общее
- Права: файлы и документы — чтение
DOCUMENT_VIEW, загрузка/удаление/подтверждение —DOCUMENT_EDIT; справочники —DIRECTORY_VIEW(импорт ЕЦП —DIRECTORY_ADMIN, только у администратора: кнопку «Импорт» на [34] скрывайте поGET /me). - Страницы —
{items, total, limit, offset}: у файлов ЮЛ и справочниковlimit1…200 (по умолчанию 50), у строк ОСВ документа 1…2000 (по умолчанию 500);offset ≥ 0; вне предела — 422 (pydantic-массив). - ЮЛ, файл или документ вне видимости пользователя неотличимы от несуществующих: 404
NOT_FOUND. - Перечисления:
FileType—XLS,XLSX,XLSB,PDF,PNG,JPG;FileStatus—UPLOADED,PROCESSING,PROCESSED,ERROR,SUPERSEDED;RecognitionStatus(задание) —queued,published,processing,done,needs_check,error,timeout(нет ответа к сроку),dlq(сервис не подтвердил приём после повторов);DocumentType—BALANCE,INCOME,OSV,DISCLOSURE,OTHER;DocumentStatus—RECOGNIZED,NEEDS_CHECK,CONFIRMED,ERROR;DocumentCheckResult—MATCH,MISMATCH,UNKNOWN;EntityType—ЮЛ,ИП;RelatedGroupKind—gsk,gsz.
2. Эндпоинты: файлы и документы
| Метод и путь | Право | Запрос | Ответ | Ошибки | Экран |
|---|---|---|---|---|---|
GET /legal-entities/{legal_entity_id}/files |
VIEW | query limit, offset, include_superseded (bool, по умолчанию false — заменённые скрыты) |
Page[FileOut], новые первыми (по убыванию uploaded_at) |
404 | переключатель «Все документы организации» [39] / страница ЮЛ |
GET /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files |
VIEW | query limit, offset, include_superseded (bool, по умолчанию false) |
Page[FileOut] — рабочий стол консоли для ЮЛ (файлы с этим consolidation_id + файлы с документами, привязанными к версиям консолидации), новые первыми; SUPERSEDED — только при include_superseded=true (скрыт по умолчанию) |
404 | [39] drawer внутри версии (v5.18, docs #90) |
POST /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files |
EDIT | multipart, поле files (повторяется) — загрузка в консолидацию |
201 UploadResult (принят хотя бы один файл) / 422 UploadResult (ни один) |
404 (консолидация, ЮЛ), 409 CONSOLIDATION_NOT_EDITABLE, 422 ENTITY_NOT_IN_PERIMETER, 503 STORAGE_UNAVAILABLE |
[40] |
POST /legal-entities/{legal_entity_id}/files |
EDIT | multipart, поле files (повторяется) — без контекста (consolidation_id = null); query consolidation_version_id удалён (v5.18) |
201 / 422 UploadResult |
404, 503 STORAGE_UNAVAILABLE |
страница ЮЛ, монозаёмщики |
GET /files/{file_id} |
VIEW | — | FileOut |
404 | опрос строки файла |
DELETE /files/{file_id} |
EDIT | — | 204 | 404, 409 FILE_HAS_CONFIRMED_DOCUMENTS, 409 FILE_SUPERSEDES_OTHERS |
[39] иконка «удалить» |
GET /files/{file_id}/content |
VIEW | query disposition (attachment по умолчанию / inline) |
поток исходного файла | 404 (FILE_CONTENT_NOT_FOUND — объекта нет в хранилище), 503 |
[41] «Исходный документ» (см. контракт 3b) |
GET /documents/{document_id} |
VIEW | — | DocumentOut |
404 | [41], карточка документа |
GET /documents/{document_id}/entries |
VIEW | query limit (≤ 2000, по умолчанию 500), offset |
Page[EntryOut] по возрастанию row_number; дерево — по parent_entry_id |
404 | строки ОСВ документа (только чтение) |
POST /documents/{document_id}/confirm |
EDIT | — | DocumentOut |
404, 409 ALREADY_CONFIRMED / FILE_SUPERSEDED / DOCUMENT_NOT_CONFIRMABLE; для ББ/ОФР — PERIOD_REQUIRED, CHECKS_NOT_PASSED |
«Подтвердить данные» |
Фильтра «файлы в контексте версии консолидации» нет (решение владельца 07.10.2026, arm-core #42): drawer показывает все
документы ЮЛ, период — в колонке «Период». (пересмотрено 09.10.2026, docs #90: drawer внутри версии — рабочий стол консоли, §9.5 п. 11.)
Подходит ли документ версии, видно по ячейкам чек-листа версии (document_ids).
3. Схемы: файлы и документы
UploadResult {accepted[], rejected[]}: accepted[] — {file_id, job_id, name}; rejected[] — {name, code, message, file_id?}, где code — UNSUPPORTED_FILE (тип не из списка или сигнатура не совпала), FILE_TOO_LARGE (больше UPLOAD_MAX_BYTES, по умолчанию 50 МиБ),
DUPLICATE_FILE (такой файл у ЮЛ уже есть — file_id указывает на него), STORAGE_UNAVAILABLE. Два разных тела 422: при
отказе всех файлов — UploadResult (смотрите rejected[]); при ЮЛ вне периметра всех версий консолидации «в работе» — доменная ошибка
{"detail": {"code": "ENTITY_NOT_IN_PERIMETER", "message": …}}. Различайте по наличию detail.
FileOut {id, legal_entity_id, original_name?, file_type, status (FileStatus), version_no, size_bytes?, content_hash?, uploaded_at?, uploaded_by?, superseded_by_file_id?, job (JobBrief | null), documents[] (DocumentBrief)} — поля с ? могут быть
null. consolidation_id: uuid | null — консолидация, в которую загружен файл (v5.18); null — загружен без контекста. JobBrief {id, status (RecognitionStatus), error_code?, error_message?, mapping_error?, warnings[], mapping_warnings[], finished_at?} — причина ошибки сервиса распознавания (error_*) или маппинга (mapping_error).
DocumentBrief {id, document_type, osv_account_code?, period_year?, period_quarter?, is_cumulative?, status (DocumentStatus), period_check?, counterparty_check?, locator?, comments_count} — порядок: тип, счёт, locator.
DocumentOut = поля DocumentBrief + {file_id, legal_entity_id, confirmed_by?, confirmed_at?, group_schema? ([{type, name?, has_inn?}]), warnings[]}. EntryOut {id, row_number?, level?, parent_entry_id?, row_value?, group_type?, group_name?, data_type?, account_code?, account_root?, account_id?, counterparty_name?, counterparty_inn?, counterparty_id?, match_kind?, opening_debit?, opening_credit?, turnover_debit?, turnover_credit?, closing_debit?, closing_credit?} — деньги строками.
Как собрать строку drawer [39]
Строка — файл (FileOut); документы файла (documents[]) — подписи и проверки:
- «Период»:
period_year+period_quarter+is_cumulative— квартальный «2024 К1», нарастающий Q3 — «2024 · 9 мес.» (Q1 — «3 мес.», Q2 — «6 мес.», Q4 — «12 мес.»);period_quarter = null— «период не определён» (dev/api-contract-slice-4.md, нюанс 17). - «Проверка»: «Контрагент» —
counterparty_check(MATCH✓,MISMATCH✗,UNKNOWN/null—); «Период» —period_checkсейчас всегдаUNKNOWN→ показывайте «—» (OQ-120). - Подпись консолидации: «<год> К<квартал>» из списка консолидаций ГК (
GET /company-groups/{id}/consolidations) поFileOut.consolidation_id;null— «вне консолидации». - «Статус» (подписи — как в чек-листе и его CSV,
context/10-user-journey.md«Словарь UI»): файлUPLOADED/PROCESSING— «Обработка»; файлERROR— «Ошибка» (причина —job.error_message/job.mapping_error; заданиеtimeout/dlq— тоже ошибка, причина вjob.error_message); иначе по документу:NEEDS_CHECKиRECOGNIZED(старые и формы после правки) — «Требуется проверка»,CONFIRMED(в т.ч. автоподтверждённый) — «Загружен»,ERROR— «Ошибка». - Комментарий — у документа (
comments_count,GET/POST /documents/{id}/comments, контракт 3b); у файла без документов комментария нет. - Опрос во время распознавания: перечитывайте активный список (стол консоли
GET /consolidations/{cid}/legal-entities/{id}/filesили файлы ЮЛGET /legal-entities/{id}/files; илиGET /files/{id}для одного файла), пока файл вUPLOADED/PROCESSING; разумный интервал — 3–5 с. - Клик по строке ББ/ОФР-документа (PDF и Excel) — экран [41] (
GET /documents/{id}/statement, контракт 3b); строки ОСВ — только чтение (GET /documents/{id}/entries).
4. Эндпоинты: справочники (экраны [03], [36], [42], [60])
Все — GET, право DIRECTORY_VIEW, префикс /api/v1/directories.
| Путь | Query | Ответ | Экран |
|---|---|---|---|
/regional-offices |
— | RegionalOfficeOut[] {id, name, is_head_office, is_active} |
выбор филиала в формах (имя «Основной РФ» на [03] приходит объектом в ГК, arm-core #47) |
/company-groups |
q (подстрока name / crm_id / code), is_archived, limit, offset |
Page[CompanyGroupOut] по имени |
[03], выбор ГК в [42] |
/company-groups/{group_id} |
— | CompanyGroupOut |
заголовок [34] («N организаций» — legal_entities_count) |
/company-groups/{company_group_id}/related-groups |
— | RelatedGroupOut[] (ГСК и ГСЗ; ГСК — kind = gsk) |
выбор ГСК в [42], фильтр «ГСК» в [36] |
/related-groups/{group_id} |
— | RelatedGroupDetail (+ members[]) |
отметки [42], колонка «ГСК» в [36] |
/legal-entities |
company_group_id, outside_group (bool), inn (точно), q (подстрока имени/ИНН), closed (bool), limit, offset |
Page[LegalEntityOut] по имени |
[36] «Показать все ЮЛ в ГК», список ЮЛ в [42], монозаёмщики [60] |
/legal-entities/{entity_id} |
— | LegalEntityDetail (+ aliases[]; memberships[] — как в списке) |
карточка ЮЛ |
CompanyGroupOut {id, code, crm_id?, name, base_regional_office_id?, base_regional_office? {id, name, is_head_office}, is_archived, valid_from, legal_entities_count, created_at?, updated_at?}. RelatedGroupOut {id, code, company_group_id, kind, name, created_date?, members_count};
RelatedGroupDetail — + members[] {legal_entity_id, inn, name, valid_from} (текущий состав). LegalEntityOut {id, inn, crm_id?, entity_type?, name, company_group_id?, regional_office_id?, regional_office? {id, name, is_head_office}, close_date?, valid_from, created_at?, updated_at?, documents_count, memberships[] {related_group_id, code, kind, name, valid_from}, outside_group, closed} (outside_group — нет ГК, монозаёмщик; closed — заполнен close_date; оба вычисляет сервер; memberships — текущие ГСК/ГСЗ, arm-core #109); LegalEntityDetail — + aliases[] {id, alias, normalized_alias, created_at?}.
Нюансы:
- Модалка [42]: ЮЛ ГК —
legal-entities?company_group_id=<ГК>&closed=false(неархивные = безclose_date;limit≤ 200, а периметр — до 500 ЮЛ: дочитывайте страницы поoffset, пока не наберётеtotal), отметки — члены выбранной ГСК изrelated-groups/{id}; создание —POST /consolidationsсlegal_entity_ids(dev/api-contract-slice-4.md, нюанс 19). - Колонка «ГСК» и фильтр по ГСК/ГСЗ в [36]:
membershipsстрокlegal-entities?company_group_id=<ГК>(arm-core #109). - Монозаёмщики [60]:
legal-entities?outside_group=true; «Документы» —documents_count, статусы ОФР/ББ/ОСВ — изGET /legal-entities/{id}/filesпо ЮЛ (сводного поля нет; экран не отнесён к срезу, П-6). - Филиал (
base_regional_officeу ГК,regional_officeу ЮЛ и в истории) приходит объектом с именем,*_idрядом остаются; неактивный филиал тоже отдаётся (arm-core #47). - Поиск ГК по имени РФ не поддерживается (
q— только name/crm_id/code); пользователю филиала он не нужен (видит один РФ).