Andrey Epifancev f9b8a21410 docs: README/CLAUDE.md Среза 2c, tasks.md
README: разделы «Первичные документы: загрузка», «Статусы файла и документа», «Цикл маппинга», «API файлов и документов»,
«Удаление и замена», «Ограничения Среза 2c»; настройки UPLOAD_MAX_BYTES/MAPPING_POLL_SECONDS/MAPPING_MAX_ATTEMPTS; каталог
кодов ошибок файлов и документов. CLAUDE.md: модули Среза 2c, три фоновых цикла, порядок блокировок, маркер e2e.
OpenSpec: tasks.md (все [x], кроме 5.3; формулировки 1.2/2.1/3.1 по коду), дельта documents-api (job.mapping_error,
DOCUMENT_NOT_CONFIRMABLE), design.md — решения №40–50.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 00:11:52 +04:00

4.1 KiB
Raw Blame History

Spec Delta: documents-api

Purpose

Чтение файлов, документов и строк ОСВ для панели «Первичные документы» (подсрез 2d) и подтверждение документа.

ADDED Requirements

Requirement: Файлы организации и карточка файла

GET /api/v1/legal-entities/{id}/files (DOCUMENT_VIEW, policy; include_superseded=false по умолчанию) SHALL возвращать Page файлов ЮЛ по убыванию uploaded_at: поля stored_file, текущее задание (status, error_code, error_message, mapping_error (metrics.mapping_error: причина ERROR файла после неудачного маппинга, когда у задания error_code пуст), metrics.warnings, metrics.mapping_warnings, finished_at), документы файла (id, document_type, osv_account_code, period_year, period_quarter, is_cumulative, status, period_check, counterparty_check). GET /api/v1/files/{file_id} SHALL отдавать ту же карточку; чужой или несуществующий файл — 404.

Scenario: Список после обработки

  • WHEN у ЮЛ два файла: PROCESSED с документом и ERROR
  • THEN оба в списке; у первого documents непустой, у второго job.error_code заполнен

Requirement: Документ и строки

GET /api/v1/documents/{document_id} (DOCUMENT_VIEW, policy по ЮЛ владельца) SHALL отдавать документ, статус, проверки, locator, схему группировок листа из recognition_job.group_schema и file_id. GET /api/v1/documents/{document_id}/entries SHALL отдавать Page строк по возрастанию row_number (limit ≤ 2000, по умолчанию 500) с полями osv_entry, включая parent_entry_id, account_id, counterparty_id.

Scenario: Строки деревом

  • WHEN запрошены строки документа ОСВ 66
  • THEN первая строка — счёт 66 уровня 0 без родителя, у строк уровня 2 parent_entry_id указывает на субсчёт

Requirement: Подтверждение документа

POST /api/v1/documents/{document_id}/confirm (DOCUMENT_EDIT, policy) SHALL переводить документ из RECOGNIZED или NEEDS_CHECK в CONFIRMED (confirmed_by, confirmed_at) с audit_event(DOCUMENT_CONFIRM, PRIMARY_DOCUMENTS); из CONFIRMED повторно — 409 ALREADY_CONFIRMED; документ файла SUPERSEDED — 409 FILE_SUPERSEDED; документ в любом другом статусе (например, ERROR) — 409 DOCUMENT_NOT_CONFIRMABLE. Если совпали несколько условий, приоритет у FILE_SUPERSEDED. Подтверждение берёт блокировки в порядке «файл → документ» и перечитывает оба под FOR UPDATE; документ или файл, исчезнувшие за время ожидания блокировки, — 404 NOT_FOUND.

Scenario: Причина ошибки маппинга в карточке файла

  • WHEN файл в ERROR после неудачного маппинга (задание done, error_code пуст)
  • THEN job.mapping_error содержит причину, job.error_code пуст

Scenario: Документ не подтверждается

  • WHEN подтверждается документ в статусе ERROR
  • THEN 409 DOCUMENT_NOT_CONFIRMABLE, статус не изменился

Scenario: Подтверждение

  • WHEN ka_rf подтверждает документ NEEDS_CHECK своего филиала
  • THEN status = CONFIRMED, confirmed_by = пользователь, audit_event(DOCUMENT_CONFIRM) с before_value.status = NEEDS_CHECK