9.1 KiB
Spec Delta
Purpose
Дельта change quality-metrics (метрики качества первички).
MODIFIED Requirements
Requirement: Загрузка файлов организации
POST /api/v1/legal-entities/{legal_entity_id}/files (multipart, одно или несколько полей files; право
DOCUMENT_EDIT; ЮЛ в области видимости пользователя, иначе 404) SHALL для каждого файла в отдельной транзакции:
определить тип по расширению и сверить с сигнатурой содержимого (xls — BIFF8, xlsx/xlsb — zip, pdf, png,
jpg); отвергнуть файл больше UPLOAD_MAX_BYTES (50 МиБ) или неподдерживаемого типа; вычислить sha256; создать
s3_object (bucket_role = uploads, ключ uploads/{file_id}/{job_id}/{безопасное имя}, sha256, size_bytes,
content_type, created_by = user:{id}), положить объект в S3, создать stored_file (status = UPLOADED,
version_no = 1, uploaded_by, uploaded_at, content_hash, original_name, consolidation_id = NULL) и
recognition_job (status = queued, pipeline по типу: xls/xlsx/xlsb → tabular, pdf/png/jpg → image;
max_attempts 3 / 1), установить stored_file.current_recognition_job_id, записать
audit_event(FILE_UPLOAD, PRIMARY_DOCUMENTS) с after_value.consolidation_id = null. Ответ SHALL
перечислять принятые файлы (accepted[] с file_id, job_id, name) и отклонённые (rejected[] с name, code,
message); код ответа 201, если принят хотя бы один, иначе 422. Тип документа и период при загрузке MUST NOT
запрашиваться (макет 40). Без доступного S3 — 503 STORAGE_UNAVAILABLE.
Query-параметр consolidation_version_id MUST NOT приниматься (удалён в v5.18): загрузка этим маршрутом — без
контекста консолидации и не меняет статусы версий; загрузка в консолидацию — требование «Загрузка файлов в
консолидацию». Для PDF stored_file.is_scan SHALL определяться при загрузке по наличию текстового слоя в первых 10 страницах (разбор pypdf — вне event loop, asyncio.to_thread): нет текста — скан (true), есть — цифровой (false); для не-PDF — NULL. PDF со скрытым OCR-слоем считается цифровым.
Scenario: Реальная ОСВ принята и ушла в outbox
- WHEN
ka_rfзагружаетrb/2024-FY/ОСВ_66 за 2024.xlsдля ЮЛ своего филиала - THEN 201,
accepted[0].file_idсуществует;stored_file.status = UPLOADED,file_type = XLS,content_hash= sha256 файла,consolidation_id IS NULL;recognition_job.status = queued,pipeline = tabular; объект в S3 по ключуuploads/{file_id}/{job_id}/ОСВ_66 за 2024.xls; публикатор outbox публикует запрос с этим ключом
Scenario: Смесь принятых и отклонённых
- WHEN в одном запросе xlsx, файл
.docxи файл 51 МиБ - THEN 201,
accepted— один,rejected— два с кодамиUNSUPPORTED_FILEиFILE_TOO_LARGE
Scenario: Расширение не совпадает с содержимым
- WHEN загружается файл
osv.xlsx, байты которого — BIFF8 - THEN файл отклонён с кодом
UNSUPPORTED_FILE
Scenario: Чужое ЮЛ
- WHEN
ka_rfзагружает файл для ЮЛ другого филиала - THEN 404, объектов и записей нет
Scenario: Загрузка в контексте версии
- WHEN у ГК ЮЛ есть версия
INITIATEDс этим ЮЛ в периметре, файл загружен маршрутом ЮЛ с queryconsolidation_version_id(как делал клиент до v5.18) - THEN 201, параметр игнорируется;
stored_file.consolidation_id IS NULL; версия остаётсяINITIATED
Scenario: ЮЛ вне периметра
- WHEN ЮЛ не входит в периметр ни одной версии, файл загружен маршрутом ЮЛ
- THEN 201 — маршрут ЮЛ периметр не проверяет; проверка периметра — только у загрузки в консолидацию
Scenario: Признак скана
- WHEN загружается PDF без текстового слоя
- THEN
stored_file.is_scan = true; у xlsxis_scan IS NULL
Requirement: Удаление файла
DELETE /api/v1/files/{file_id} (DOCUMENT_EDIT, policy) SHALL удалить строки ОСВ, документы, задания и stored_file,
проставить s3_object.expires_at = now() (объект физически не удаляется, OQ-22) и записать audit_event(FILE_DELETE, before_value = карточка файла, after_value = {unbound_version_ids}). Удаление MUST быть отклонено 409
FILE_HAS_CONFIRMED_DOCUMENTS, если у файла есть документ CONFIRMED, подтверждённый пользователем (confirmed_by не
NULL), или если автоподтверждённый документ файла (confirmed_by NULL) привязан к версии в статусе, отличном от
INITIATED, DOCUMENTS_PROCESSING, DATA_CORRECTION (OQ-157, уточняет OQ-110); и 409 FILE_SUPERSEDES_OTHERS, если на
файл ссылаются superseded_by_file_id. При удалении файла с автоподтверждёнными документами их привязки
consolidation_document SHALL сниматься, статус версий MUST NOT меняться, after_value.unbound_version_ids — id версий,
где привязки сняты (по возрастанию; пустой список, если привязок не было). Блокировки: задания → файл → документы →
advisory-блокировка привязок ГК → версии по id. Файл SUPERSEDED удалить можно. Если у файла есть quality_intake_fact (по file_id), объект uploads файла MUST NOT получать expires_at — он нужен эталонному прогону качества; сырой ответ ИС (raw) при удалении expires_at не получает никогда. Для документов с исходом удаление SHALL писать факт исхода DELETED / DELETED_AFTER_CONFIRM в той же транзакции (спека quality-metrics).
Scenario: Удаление ошибочного файла
- WHEN файл в
ERRORудаляется владельцем - THEN 204;
stored_file,recognition_jobотсутствуют;s3_object.expires_atзаполнен;audit_event(FILE_DELETE)сafter_value.unbound_version_ids = []
Scenario: Подтверждённый документ
- WHEN удаляется файл с документом
CONFIRMED, у которогоconfirmed_by= пользователь - THEN 409
FILE_HAS_CONFIRMED_DOCUMENTS, ничего не изменилось
Scenario: Автоподтверждённый документ в корректировке
- WHEN версия 2025 Q1 в
DATA_CORRECTION, к ней привязан автоподтверждённый документ ОСВ 60 РБ; файл удаляется - THEN 204; привязка снята, версия осталась в
DATA_CORRECTION;FILE_DELETE.after_value.unbound_version_ids= [id версии]
Scenario: Версия ушла на согласование
- WHEN автоподтверждённый документ файла привязан к версии в
CONSOLIDATION_RF - THEN 409
FILE_HAS_CONFIRMED_DOCUMENTS, привязка и файл на месте
Scenario: Автоподтверждённый без привязок
- WHEN удаляется файл, все документы которого автоподтверждены и ни к одной версии не привязаны
- THEN 204;
after_value.unbound_version_ids = []
Scenario: Файл с фактом приёма
- WHEN удаляется файл, по документам которого записан
quality_intake_fact - THEN 204; объект
uploadsи сырой ответ остаются безexpires_at, результат (results) экспирится; записан факт исхода