arm-core/api/src/schemas/files.py
Andrey Epifancev 17141c0a11 feat(contract): копии контракта обоих MAJOR, модели v2.0, приём конвертов 1.x/2.0, предупреждения файла структурами
Копии api/contracts/ побайтно равны docs/contracts/ (тест идентичности плана 0): схемы v2.0 основные, .v1 рядом,
examples/ — v2.0, examples/v1/ — v1.0. Модели result_v2.py и RecognitionResultMessageV2, versions.py выбирает модель
по MAJOR. Приём конвертов принимает оба MAJOR; metrics.warnings в recognition_job пишется структурами (строки 1.x
оборачиваются в LEGACY_WARNING). JobBrief.warnings отдаёт структуры, мусор пропускается, БД не переписывается.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
2026-10-18 19:26:50 +04:00

112 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Схемы API первичных файлов (spec primary-files, documents-api; design D-4, D-11).
`UploadResult` — ответ загрузки (частичный успех: принятые и отклонённые файлы). `FileOut`/`JobBrief`/`DocumentBrief` —
карточка файла для чтения (Task 9 Среза 2c): статус файла, текущее задание с причиной ошибки и предупреждениями,
документы файла.
"""
import datetime
import uuid
from typing import Literal
from pydantic import BaseModel, ConfigDict
from src.models.enums import (
DocumentCheckResult,
DocumentStatus,
DocumentType,
FileStatus,
FileType,
PeriodQuarter,
RecognitionStatus,
)
from src.schemas.issues import IssueCountsOut
class AcceptedOut(BaseModel):
"""Принятый файл: `stored_file.id`, `recognition_job.id` и очищенное имя."""
file_id: uuid.UUID
job_id: uuid.UUID
name: str
class RejectedOut(BaseModel):
"""Отклонённый файл: имя, код (`UNSUPPORTED_FILE`, `FILE_TOO_LARGE`, `DUPLICATE_FILE`, `STORAGE_UNAVAILABLE`),
пояснение; `file_id` — существующий файл при `DUPLICATE_FILE`."""
name: str
code: str
message: str
file_id: uuid.UUID | None = None
class UploadResult(BaseModel):
"""Ответ `POST /legal-entities/{id}/files`: 201, если принят хотя бы один файл, иначе 422."""
accepted: list[AcceptedOut]
rejected: list[RejectedOut]
class FileWarningOut(BaseModel):
"""Предупреждение файла от сервиса распознавания (`metrics.warnings`): код, уровень, текст и место в файле.
Старые строковые предупреждения (контракт 1.x) отдаются с кодом `LEGACY_WARNING` уровня `info`."""
code: str
severity: Literal["error", "info"]
message: str
locator: str | None
class JobBrief(BaseModel):
"""Текущее задание распознавания файла: статус, причина ошибки сервиса (`error_code`/`error_message`) и маппинга
(`mapping_error` — `metrics.mapping_error`: файл в `ERROR` после маппинга при задании `done`), предупреждения
сервиса (`metrics.warnings`) и маппинга (`metrics.mapping_warnings`)."""
id: uuid.UUID
status: RecognitionStatus
error_code: str | None
error_message: str | None
mapping_error: str | None
warnings: list[FileWarningOut]
mapping_warnings: list[str]
finished_at: datetime.datetime | None
class DocumentBrief(BaseModel):
"""Документ файла в карточке файла."""
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
document_type: DocumentType
osv_account_code: str | None
period_year: int | None
period_quarter: PeriodQuarter | None
is_cumulative: bool | None
status: DocumentStatus
period_check: DocumentCheckResult | None
counterparty_check: DocumentCheckResult | None
locator: str | None
comments_count: int = 0 # число комментариев документа (D-11); в ORM-модели поля нет — задаётся при сборке
issue_counts: IssueCountsOut = IssueCountsOut() # P3-23; так же задаётся при сборке
class FileOut(BaseModel):
"""Карточка файла: поля `stored_file`, текущее задание и документы."""
id: uuid.UUID
legal_entity_id: uuid.UUID
original_name: str | None
file_type: FileType
status: FileStatus
version_no: int
size_bytes: int | None
content_hash: str | None
uploaded_at: datetime.datetime | None
uploaded_by: uuid.UUID | None
superseded_by_file_id: uuid.UUID | None
consolidation_id: uuid.UUID | None # v5.18: консолидация, в контексте которой загружен файл; None — без контекста
job: JobBrief | None
documents: list[DocumentBrief]