# Spec Delta: osv-result-mapping ## ADDED Requirements ### Requirement: Автоподтверждение чистого документа В транзакции маппинга после автозамены прежних версий файла и до перехода версий по `NEEDS_CHECK` цикл маппинга SHALL перевести каждый документ файла, получивший при маппинге статус `RECOGNIZED`, в `CONFIRMED` (ТЗ 03_9 п. 4, 10_10; решение владельца 08.10.2026, OQ-157): `confirmed_by = NULL`, `confirmed_at = now`; у формы `BALANCE`/`INCOME` — `financial_statement_meta.reviewed_by = NULL`, `reviewed_at = now`; `audit_event(DOCUMENT_CONFIRM, PRIMARY_DOCUMENTS, object_type = document)` с `user_id = NULL`, `before_value.status = RECOGNIZED`, `after_value.status = CONFIRMED` и `description = «автоподтверждение: без замечаний»`. Форма `BALANCE`/`INCOME` с шапкой SHALL подтверждаться автоматически, только если выполнены условия ручного подтверждения (`period_year` и `period_quarter` определены, нет непройденных неакцептованных жёстких проверок §7); иначе она MUST оставаться `RECOGNIZED` без ошибки. Документы `NEEDS_CHECK` MUST NOT подтверждаться автоматически. Автоподтверждённый документ SHALL привязываться к версиям так же, как при ручном подтверждении (`documents-api` «Подтверждение документа»: все подходящие версии «в работе», замена привязки того же ключа R-1), и каждая версия, получившая привязку, из `INITIATED` или `DOCUMENTS_PROCESSING` SHALL переходить в `DATA_CORRECTION` с `changed_by = stored_file.uploaded_by` и `comment = «автоподтверждение документа »` (счёт — только у ОСВ). Если `uploaded_by` NULL, привязка SHALL создаваться, а переход — пропускаться с записью в лог. Пересчёт статуса формы после правки или акцепта MUST NOT подтверждать документ автоматически. #### Scenario: Чистая ОСВ сразу «Загружен» - **WHEN** смаплен результат `fixtures/osv/rb/2025-Q1/ОСВ сч 60 за 1 кв 2025 год.xlsx` для ЮЛ АО «Русский бисквит» (задание `done`, шапка совпадает с владельцем, нарушений и предупреждений нет) - **THEN** документ `OSV` 60 — `CONFIRMED`, `confirmed_by` NULL, `confirmed_at` заполнен; есть `audit_event(DOCUMENT_CONFIRM)` с `user_id` NULL и описанием «автоподтверждение: без замечаний» #### Scenario: Привязка и переход версии - **WHEN** версия ГК «Русский Бисквит» 2025 Q1 в `INITIATED`, РБ в периметре; смаплен чистый результат ОСВ 60 РБ за 2025 Q1, файл загрузил `ka_go` - **THEN** `consolidation_document(version, document)` создан; версия в `DATA_CORRECTION`; запись истории `INITIATED → DATA_CORRECTION` с `changed_by` = `ka_go` и комментарием «автоподтверждение документа OSV 60» #### Scenario: Документ с замечанием ждёт аналитика - **WHEN** файл ОСВ загружен для ЮЛ «Пекарня Счастливочная», а в шапке `АО "Русский бисквит"` - **THEN** документ `NEEDS_CHECK`, `confirmed_at` пуст, события `DOCUMENT_CONFIRM` нет, привязки нет #### Scenario: Чистая форма Excel - **WHEN** смаплен `statements-xlsx/mezheninovskaya/2025-Q3/1_Форма2_бух_09` (ОФР, `done`, соотношения сходятся, период определён) - **THEN** документ `INCOME` `CONFIRMED`, `reviewed_by` NULL, `reviewed_at` заполнен #### Scenario: Форма OCR не подтверждается сама - **WHEN** смаплен эталон `ocr/expected_normalize/БО 1 кв 2025` (уверенность значений < 100, дата отчёта не разобрана) - **THEN** документы `BALANCE` и `INCOME` — `NEEDS_CHECK`, не `CONFIRMED` #### Scenario: Файл без загрузившего - **WHEN** версия в `INITIATED`, ЮЛ в периметре; смаплен чистый результат файла с `uploaded_by` NULL - **THEN** документ `CONFIRMED` и привязан к версии; версия осталась `INITIATED`; в логе — строка о пропуске перехода #### Scenario: Автозамена чистой версией файла - **WHEN** документ ОСВ 60 РБ за 2025 Q1 из файла A привязан к версии 2025 Q1; загружен и смаплен файл B того же ключа (чистый), A заменён автозаменой - **THEN** привязка документа A снята, документ B `CONFIRMED` и привязан к версии ## MODIFIED Requirements ### Requirement: Проверки шапки и статус документа `counterparty_check` SHALL быть `MATCH`, если ИНН шапки равен ИНН владельца, или (без ИНН) нормализованное имя шапки совпадает с нормализованным именем или алиасом владельца; `MISMATCH` иначе; `UNKNOWN` при пустой шапке. `period_check` SHALL быть `UNKNOWN` до появления версии консолидации (Срез 4). Для `period_quarter ∈ {Q2, Q3, Q4}` с `is_cumulative = false` ядро SHALL сверить сальдо на начало корневой строки с документом `Q1` того же года, ЮЛ и счёта (файл не `SUPERSEDED`) и при совпадении (±0.01) установить `is_cumulative = true` с предупреждением (`ASSUMPTION(OQ-02)`). Статус документа при маппинге SHALL быть `RECOGNIZED`, если задание `done`, `checks` без нарушений, `counterparty_check ≠ MISMATCH` и нет предупреждений маппинга; иначе `NEEDS_CHECK` (OQ-05). Документ `RECOGNIZED` в той же транзакции SHALL подтверждаться автоматически (требование «Автоподтверждение чистого документа»). #### Scenario: Шапка другой организации - **WHEN** файл загружен для ЮЛ «Пекарня Счастливочная», а в шапке `АО "Русский бисквит"` - **THEN** `counterparty_check = MISMATCH`, `status = NEEDS_CHECK` #### Scenario: Нарастающая по данным - **WHEN** у ЮЛ есть документ ОСВ 60 за 2024 Q1 (`opening_*` корня = X) и маппится ОСВ 60 «за 3 квартал 2024» с `opening_*` корня = X - **THEN** `is_cumulative = true`, предупреждение «нарастающая по данным Q1» #### Scenario: Чистый результат - **WHEN** задание `done`, шапка совпадает с владельцем, нарушений нет - **THEN** после маппинга `status = CONFIRMED` (автоподтверждение), `counterparty_check = MATCH`, `period_check = UNKNOWN` ### Requirement: Документ NEEDS_CHECK переводит версию в корректировку После фиксации документов файла и автоподтверждения чистых документов цикл маппинга SHALL для каждой версии в `DOCUMENTS_PROCESSING`, в периметр которой входит ЮЛ файла, проверить документы файла: если среди них есть документ `NEEDS_CHECK`, подходящий версии по периоду (правила привязки `documents-api`), версия SHALL перейти в `DATA_CORRECTION` с `changed_by = stored_file.uploaded_by` в той же транзакции маппинга (версии блокируются `FOR UPDATE` по `id` после файла). Если `uploaded_by` NULL, переход SHALL пропускаться с записью в лог. Привязка `consolidation_document` для документа `NEEDS_CHECK` при маппинге MUST NOT создаваться (привязку при маппинге создаёт только автоподтверждение). #### Scenario: Предупреждение маппинга двигает статус - **WHEN** версия 2024 Q3 в `DOCUMENTS_PROCESSING`; смапплен файл ЮЛ периметра с ОСВ 62 за 2024 Q3 в `NEEDS_CHECK` - **THEN** версия в `DATA_CORRECTION`, запись истории с `changed_by` = загрузивший; `consolidation_document` нет #### Scenario: Документ RECOGNIZED - **WHEN** версия 2024 Q3 в `DOCUMENTS_PROCESSING`; смапплен файл с единственным чистым документом за 2024 Q3 - **THEN** документ `CONFIRMED` и привязан; переход версии в `DATA_CORRECTION` записан автоподтверждением (комментарий «автоподтверждение документа …»), этот хук второго перехода не делает #### Scenario: Документ не подходит версии - **WHEN** версия 2024 Q3 в `DOCUMENTS_PROCESSING`; смапплен файл с единственным документом `NEEDS_CHECK` за 2025 Q1 - **THEN** статус версии не изменился ### Requirement: Статус документа формы Документ `BALANCE`/`INCOME` SHALL быть `RECOGNIZED`, только если одновременно: задание `done`; нет непройденных неакцептованных жёстких проверок §7 (`statement-checks`); `counterparty_check ≠ MISMATCH`; `period_year` и `period_quarter` определены; у каждого значения `is_modified = true` либо (`is_recognized` не `false` и `confidence` равна 100 или `NULL`); нет предупреждений маппинга по документу; есть хотя бы одна строка. Иначе `NEEDS_CHECK`. Статус SHALL пересчитываться при маппинге, после правки формы и после акцепта, кроме документа `CONFIRMED`. Документ `RECOGNIZED` после маппинга SHALL подтверждаться автоматически (требование «Автоподтверждение чистого документа»); `RECOGNIZED`, полученный пересчётом после правки или акцепта, — только вручную. Документ формы `NEEDS_CHECK` SHALL участвовать в переходе версии в `DATA_CORRECTION` наравне с ОСВ (требование «Документ NEEDS_CHECK переводит версию в корректировку»). #### Scenario: Чистая форма Excel - **WHEN** смаплен `mezheninovskaya/2025-Q3/1_Форма2_бух_09` (ОФР, `done`, соотношения сходятся, ИНН шапки = ИНН владельца файла) - **THEN** документ `INCOME` `CONFIRMED` (автоподтверждение) #### Scenario: Форма OCR - **WHEN** смаплен эталон `ocr/expected_normalize/aep_3` (уверенность значений < 100, ИНН шапки ≠ ИНН владельца) - **THEN** документ `BALANCE` `NEEDS_CHECK`, `counterparty_check = MISMATCH` #### Scenario: Форма двигает версию - **WHEN** версия ГК 2025 Q3 в `DOCUMENTS_PROCESSING`, в периметре ЮЛ файла; смаплена форма `BALANCE` за 2025 Q3 в `NEEDS_CHECK` - **THEN** версия в `DATA_CORRECTION`, привязки `consolidation_document` нет #### Scenario: Чистая после правки — вручную - **WHEN** форма `NEEDS_CHECK` исправлена аналитиком (`PATCH …/statement`) и пересчёт дал `RECOGNIZED` - **THEN** документ остаётся `RECOGNIZED` до `POST …/confirm` ### Requirement: Повтор формы в файле и прочие документы Второй документ `BALANCE` или `INCOME` в одном файле MUST NOT создаваться: предупреждение маппинга, первый документ — `NEEDS_CHECK`. Документы `DISCLOSURE` и `OTHER` результата SHALL давать по одному `document` каждого типа на файл без данных (`locator` — все `locator` этого типа через запятую, статус при маппинге `RECOGNIZED`, затем автоподтверждение → `CONFIRMED`). Форма `BALANCE`/`INCOME` без строк SHALL создаваться с шапкой и колонками (если колонки есть в результате). #### Scenario: Расшифровки - **WHEN** смаплен синтетический снимок `st06_header_variants` (форма `INCOME` и пять `DISCLOSURE`) - **THEN** у файла два документа: `INCOME` и один `DISCLOSURE` с пятью `locator` через запятую; `DISCLOSURE` — `CONFIRMED` #### Scenario: Форма без колонки кодов - **WHEN** смаплен синтетический снимок `st03_no_codes` (`BALANCE`, строк 0) - **THEN** документ `BALANCE` `NEEDS_CHECK` с шапкой, строк нет (колонок в снимке тоже нет — создаются те, что есть в результате)