docs: автоподтверждение чистых документов в CLAUDE.md и README (#64)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
256ddcb34a
commit
e7bef704cf
@ -76,14 +76,14 @@
|
|||||||
advisory-lock, SAVEPOINT на файл, `delete`), `services/file_status.py` (единственное место смены `stored_file.status`
|
advisory-lock, SAVEPOINT на файл, `delete`), `services/file_status.py` (единственное место смены `stored_file.status`
|
||||||
по ТЕКУЩЕМУ заданию; `PROCESSED`/`SUPERSEDED` обменом не перезаписываются), `services/result_mapping.py` (цикл маппинга:
|
по ТЕКУЩЕМУ заданию; `PROCESSED`/`SUPERSEDED` обменом не перезаписываются), `services/result_mapping.py` (цикл маппинга:
|
||||||
`pick_candidate` → проверка ключа результата (OQ-70) → чтение S3 вне транзакции → `map_file` в одной транзакции →
|
`pick_candidate` → проверка ключа результата (OQ-70) → чтение S3 вне транзакции → `map_file` в одной транзакции →
|
||||||
автозамена `FILE_REPLACE`), `services/documents.py` (карточки, `confirm`), `domain/osv_mapping.py` (чистые функции:
|
автозамена `FILE_REPLACE`), `services/documents.py` (карточки, `confirm`), `services/auto_confirm.py` (автоподтверждение чистых документов в транзакции маппинга: `_map_candidate`: `map_file` → `auto_confirm` → `on_documents_mapped`; `confirmed_by` NULL, `DOCUMENT_CONFIRM` без пользователя, переход версии — от `uploaded_by`; OQ-157), `domain/osv_mapping.py` (чистые функции:
|
||||||
`normalize_account_code`, `build_entries`, `counterparty_check`, `document_status`), `repositories/counterparties.py`
|
`normalize_account_code`, `build_entries`, `counterparty_check`, `document_status`), `repositories/counterparties.py`
|
||||||
(`CounterpartyIndex` — резолв контрагента без policy). **Фоновых циклов три** (запускаются в lifespan при
|
(`CounterpartyIndex` — резолв контрагента без policy). **Фоновых циклов три** (запускаются в lifespan при
|
||||||
`NATS_ENABLED`; цикл маппинга — ещё и при подключённом S3 (storage)): публикатор outbox, вахтёр сроков и цикл маппинга
|
`NATS_ENABLED`; цикл маппинга — ещё и при подключённом S3 (storage)): публикатор outbox, вахтёр сроков и цикл маппинга
|
||||||
(`MAPPING_POLL_SECONDS`, `MAPPING_MAX_ATTEMPTS`); inbox результат не читает и документов не создаёт. **Порядок блокировок: задание → файл → документы** (inbox, вахтёр, публикатор, маппер,
|
(`MAPPING_POLL_SECONDS`, `MAPPING_MAX_ATTEMPTS`); inbox результат не читает и документов не создаёт. **Порядок блокировок: задание → файл → документы** (inbox, вахтёр, публикатор, маппер,
|
||||||
`confirm`, `delete`; с Среза 4 далее — advisory-lock ГК → версии консолидации, см. «Консолидации») — иначе
|
`confirm`, `delete`; с Среза 4 далее — advisory-lock ГК → версии консолидации, см. «Консолидации») — иначе
|
||||||
взаимоблокировки; автозамена дополнительно берёт advisory-lock по ЮЛ. Аудит: `FILE_UPLOAD`,
|
взаимоблокировки; автозамена дополнительно берёт advisory-lock по ЮЛ. Аудит: `FILE_UPLOAD`,
|
||||||
`FILE_REPLACE` (системное, `user_id` пуст), `FILE_DELETE`, `DOCUMENT_CONFIRM`; смена статусов обмена и маппинга не аудируется
|
`FILE_REPLACE` (системное, `user_id` пуст), `FILE_DELETE`, `DOCUMENT_CONFIRM` (пользователь или система при автоподтверждении); смена статусов обмена и маппинга не аудируется
|
||||||
(OQ-55). `osv_entry` пишет только маппер, один раз на файл (очистка перед вставкой); `TOTAL` не хранится.
|
(OQ-55). `osv_entry` пишет только маппер, один раз на файл (очистка перед вставкой); `TOTAL` не хранится.
|
||||||
- **Формы ББ/ОФР (Срез 3b)** — `map_file` (`services/result_mapping.py`) мапит и формы ББ/ОФР: `domain/statement_mapping.py` (чистые
|
- **Формы ББ/ОФР (Срез 3b)** — `map_file` (`services/result_mapping.py`) мапит и формы ББ/ОФР: `domain/statement_mapping.py` (чистые
|
||||||
функции) + `repositories/statements.py` (`financial_statement_meta/column/line/value`); форма создаётся с тем, что есть в результате (колонки могут отсутствовать);
|
функции) + `repositories/statements.py` (`financial_statement_meta/column/line/value`); форма создаётся с тем, что есть в результате (колонки могут отсутствовать);
|
||||||
@ -110,8 +110,8 @@
|
|||||||
mapping), сервисы: `consolidations` (создание, список, карточка, периметр `PUT …/members`), `consolidation_guard`
|
mapping), сервисы: `consolidations` (создание, список, карточка, периметр `PUT …/members`), `consolidation_guard`
|
||||||
(`lock_visible_version`/`lock_editable_version`: версия `FOR UPDATE` → видимость 404 → статус «в работе» → своя блокировка),
|
(`lock_visible_version`/`lock_editable_version`: версия `FOR UPDATE` → видимость 404 → статус «в работе» → своя блокировка),
|
||||||
`consolidation_locks` (взять/перехватить/снять; без истечения, OQ-119), `consolidation_status` (`transition` + ручной
|
`consolidation_locks` (взять/перехватить/снять; без истечения, OQ-119), `consolidation_status` (`transition` + ручной
|
||||||
`POST …/status`), `consolidation_documents` (`fits`, `bind_confirmed`, `unbind_entity`, хуки `on_document_confirmed` /
|
`POST …/status`), `consolidation_documents` (`fits`, `bind_confirmed`, `unbind_entity`, хуки `on_document_confirmed(changed_by, comment)` /
|
||||||
`on_documents_superseded` / `on_documents_mapped`), `consolidated_osv` (единая сборка `_build`: страница, сводка, кандидаты,
|
`on_documents_superseded` / `on_documents_mapped`; `bound_versions` / `unbind_documents` — снятие привязок автоподтверждённых документов при удалении файла, OQ-157), `consolidated_osv` (единая сборка `_build`: страница, сводка, кандидаты,
|
||||||
экспорт), `counterparty_mapping` (ручное сопоставление, алиас, автоприменение), `osv_export` (openpyxl, лист «Пробелы»).
|
экспорт), `counterparty_mapping` (ручное сопоставление, алиас, автоприменение), `osv_export` (openpyxl, лист «Пробелы»).
|
||||||
Создание и `PUT …/members` проверяют периметр одной функцией `_validate_perimeter` (#42); ячейки чек-листа самоописывающие
|
Создание и `PUT …/members` проверяют периметр одной функцией `_validate_perimeter` (#42); ячейки чек-листа самоописывающие
|
||||||
(`document_type`, `account`); `members[].osv_accounts` — `repositories/consolidations.osv_accounts` («что загружено к периоду
|
(`document_type`, `account`); `members[].osv_accounts` — `repositories/consolidations.osv_accounts` («что загружено к периоду
|
||||||
|
|||||||
@ -470,11 +470,12 @@ curl -s "localhost:8000/api/v1/files/<file_id>" -H "Authorization: Bearer $TOKEN
|
|||||||
|
|
||||||
- `RECOGNIZED` — задание `done`, проверки парсера без нарушений, шапка не противоречит владельцу
|
- `RECOGNIZED` — задание `done`, проверки парсера без нарушений, шапка не противоречит владельцу
|
||||||
(`counterparty_check ≠ MISMATCH`), предупреждений маппинга у листа нет;
|
(`counterparty_check ≠ MISMATCH`), предупреждений маппинга у листа нет;
|
||||||
|
- чистый документ (`RECOGNIZED`) подтверждается системой сразу в маппинге; `RECOGNIZED` остаётся у документов с замечаниями и у форм, не прошедших условия подтверждения (после правки формы автоподтверждения нет);
|
||||||
- `NEEDS_CHECK` — иначе: задание `needs_check`, нарушения `checks`, `counterparty_check = MISMATCH`, повтор счёта
|
- `NEEDS_CHECK` — иначе: задание `needs_check`, нарушения `checks`, `counterparty_check = MISMATCH`, повтор счёта
|
||||||
в файле, строки без родителя, нарастающая по данным Q1;
|
в файле, строки без родителя, нарастающая по данным Q1;
|
||||||
- для формы ББ/ОФР условия `RECOGNIZED`/`NEEDS_CHECK` — правило D-6 (раздел «Формы ББ/ОФР»): проверки §7 по суммам формы вместо
|
- для формы ББ/ОФР условия `RECOGNIZED`/`NEEDS_CHECK` — правило D-6 (раздел «Формы ББ/ОФР»): проверки §7 по суммам формы вместо
|
||||||
проверок парсера;
|
проверок парсера;
|
||||||
- `CONFIRMED` — аналитик нажал «Подтвердить» (`POST /documents/{id}/confirm`, `confirmed_by/at`, аудит);
|
- `CONFIRMED` — аналитик нажал «Подтвердить» (`POST /documents/{id}/confirm`, `confirmed_by/at`, аудит) либо система при автоподтверждении чистого документа (`confirmed_by = null`, аудит `DOCUMENT_CONFIRM` без пользователя; OQ-157);
|
||||||
- `ERROR` — зарезервирован: в Срезе 2c ядро документ в `ERROR` не создаёт (результат без документов — «в результате нет документов» — переводит в `ERROR` файл).
|
- `ERROR` — зарезервирован: в Срезе 2c ядро документ в `ERROR` не создаёт (результат без документов — «в результате нет документов» — переводит в `ERROR` файл).
|
||||||
|
|
||||||
`counterparty_check` (`MATCH` / `MISMATCH` / `UNKNOWN`) сверяет шапку (ИНН, иначе имя или алиас) с ЮЛ — владельцем файла;
|
`counterparty_check` (`MATCH` / `MISMATCH` / `UNKNOWN`) сверяет шапку (ИНН, иначе имя или алиас) с ЮЛ — владельцем файла;
|
||||||
@ -600,7 +601,7 @@ advisory-блокировкой.
|
|||||||
|
|
||||||
**Удаление.** `DELETE /files/{id}` удаляет формы ББ/ОФР (шапки, колонки, строки, значения), комментарии документов, строки ОСВ, документы, задания и `stored_file`, проставляет объектам S3
|
**Удаление.** `DELETE /files/{id}` удаляет формы ББ/ОФР (шапки, колонки, строки, значения), комментарии документов, строки ОСВ, документы, задания и `stored_file`, проставляет объектам S3
|
||||||
(`uploads`, `results`) из папок этого файла (`uploads/{file_id}/`, `results/{file_id}/`) `expires_at = now()`
|
(`uploads`, `results`) из папок этого файла (`uploads/{file_id}/`, `results/{file_id}/`) `expires_at = now()`
|
||||||
(физически объект не удаляется — ретеншн OQ-22, OQ-111) и пишет `FILE_DELETE` с карточкой файла в `before_value`. Нельзя удалить файл с документом `CONFIRMED` (`409 FILE_HAS_CONFIRMED_DOCUMENTS`)
|
(физически объект не удаляется — ретеншн OQ-22, OQ-111) и пишет `FILE_DELETE` с карточкой файла в `before_value`. Нельзя удалить файл с документом, подтверждённым пользователем (`confirmed_by` задан), и с автоподтверждённым документом, привязанным к версии вне статусов «в работе» `INITIATED`/`DOCUMENTS_PROCESSING`/`DATA_CORRECTION` (`409 FILE_HAS_CONFIRMED_DOCUMENTS`); автоподтверждённые привязки к версиям «в работе» снимаются (`FILE_DELETE.after_value.unbound_version_ids`, OQ-157)
|
||||||
и файл, который заменил другие (`409 FILE_SUPERSEDES_OTHERS`); `SUPERSEDED` файл удалить можно. Блокировки — в порядке
|
и файл, который заменил другие (`409 FILE_SUPERSEDES_OTHERS`); `SUPERSEDED` файл удалить можно. Блокировки — в порядке
|
||||||
«задания → файл → документы».
|
«задания → файл → документы».
|
||||||
|
|
||||||
@ -840,7 +841,7 @@ email без учёта регистра проверяет только сер
|
|||||||
| `ALREADY_CONFIRMED` | 409 | подтверждение: документ уже `CONFIRMED` |
|
| `ALREADY_CONFIRMED` | 409 | подтверждение: документ уже `CONFIRMED` |
|
||||||
| `FILE_SUPERSEDED` | 409 | подтверждение: документ файла, заменённого новой версией |
|
| `FILE_SUPERSEDED` | 409 | подтверждение: документ файла, заменённого новой версией |
|
||||||
| `DOCUMENT_NOT_CONFIRMABLE` | 409 | подтверждение: статус документа не `RECOGNIZED`/`NEEDS_CHECK` (например, `ERROR`) |
|
| `DOCUMENT_NOT_CONFIRMABLE` | 409 | подтверждение: статус документа не `RECOGNIZED`/`NEEDS_CHECK` (например, `ERROR`) |
|
||||||
| `FILE_HAS_CONFIRMED_DOCUMENTS` | 409 | удаление файла с `CONFIRMED` документом |
|
| `FILE_HAS_CONFIRMED_DOCUMENTS` | 409 | удаление файла с документом, подтверждённым пользователем, или с автоподтверждённым документом в версии вне «в работе» (OQ-157) |
|
||||||
| `FILE_CONTENT_NOT_FOUND` | 404 | `GET /files/{id}/content`: файл есть, объекта нет в S3 (истёк или пропал) |
|
| `FILE_CONTENT_NOT_FOUND` | 404 | `GET /files/{id}/content`: файл есть, объекта нет в S3 (истёк или пропал) |
|
||||||
| `DOCUMENT_NOT_STATEMENT` | 409 | `…/statement`: документ — не форма ББ/ОФР (ОСВ, расшифровка, ББ/ОФР без данных формы — созданные до Среза 3b) |
|
| `DOCUMENT_NOT_STATEMENT` | 409 | `…/statement`: документ — не форма ББ/ОФР (ОСВ, расшифровка, ББ/ОФР без данных формы — созданные до Среза 3b) |
|
||||||
| `DOCUMENT_READONLY` | 409 | правка/акцепт формы: форма уже `CONFIRMED` (исправление — новым файлом) |
|
| `DOCUMENT_READONLY` | 409 | правка/акцепт формы: форма уже `CONFIRMED` (исправление — новым файлом) |
|
||||||
|
|||||||
@ -109,3 +109,7 @@
|
|||||||
| 5 | 2026-10-08 | Существующие `RECOGNIZED` не мигрируются | контур без продовых данных; миграция данных с аудитом без пользователя — лишний риск | на стенде старые документы подтверждаются кнопкой |
|
| 5 | 2026-10-08 | Существующие `RECOGNIZED` не мигрируются | контур без продовых данных; миграция данных с аудитом без пользователя — лишний риск | на стенде старые документы подтверждаются кнопкой |
|
||||||
| 6 | 2026-10-08 | Комментарий перехода версии — «автоподтверждение документа <тип> <счёт>», описание аудита — «автоподтверждение: без замечаний» | история версии и журнал объясняют, откуда переход без клика | тексты меняются без миграции |
|
| 6 | 2026-10-08 | Комментарий перехода версии — «автоподтверждение документа <тип> <счёт>», описание аудита — «автоподтверждение: без замечаний» | история версии и журнал объясняют, откуда переход без клика | тексты меняются без миграции |
|
||||||
| 7 | 2026-10-08 | Удаление: проверка статусов версий только тех, к которым привязаны документы файла; `FILE_DELETE.after_value.unbound_version_ids` | симметрично `FILE_REPLACE.unbound_version_ids` | — |
|
| 7 | 2026-10-08 | Удаление: проверка статусов версий только тех, к которым привязаны документы файла; `FILE_DELETE.after_value.unbound_version_ids` | симметрично `FILE_REPLACE.unbound_version_ids` | — |
|
||||||
|
| 8 | 2026-10-08 | Тест `form_confirmable` ломает строку 2200 (строгое соотношение), а не 2400 (соотношения с 2400 в `statement_checks.yaml` нежёсткие) | иначе тест не проверяет жёсткое нарушение | только тест |
|
||||||
|
| 9 | 2026-10-08 | Тесты автоподтверждения, маппинга и удаления берут `uploaded_by` у реального пользователя (FK `app_user`), а не случайный uuid (ошибка плана) | случайный uuid не проходит FK | нет |
|
||||||
|
| 10 | 2026-10-08 | В `tests/test_api_files_delete.py` тесты, имитирующие подтверждение пользователем (`test_confirmed_document_blocks_delete`, `test_delete_rereads_state_after_locks`), получили `confirmed_by` | иначе по правилу удаления (D-4) документ считается автоподтверждённым и удаление проходит | нет |
|
||||||
|
| 11 | 2026-10-08 | Импорт `auto_confirm` в `result_mapping._map_candidate` — локальный | цикл `documents` → `result_mapping` → `auto_confirm` → `statements` → `documents` | техдолг: вынести `form_confirmable`/`FORM_TYPES` в модуль без обратной зависимости |
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user