# statement-checks Specification ## Purpose Логические проверки форм ББ/ОФР §7 в ядре: чистые функции над текущими суммами документа, без хранения результата; акцепт непройденных проверок аналитиком. ## Requirements ### Requirement: Соотношения §7 по колонкам Проверки SHALL считаться чистой функцией по текущим `financial_statement_value.amount` документа для каждой колонки отдельно по словарю `api/rules/statement_checks.yaml` (копия словаря tabular-parser): соотношение проверяется, только если присутствует его левая часть; отсутствующий код и пустая сумма — 0; выполнено, если `|левая − правая| ≤ tolerance` (1, в единицах формы) хотя бы в одном варианте правой части — как записано или с кодами `abs_terms` по модулю. Нарушение жёсткого (`strict`) соотношения, не превышающее `rounding_tolerance_percent` (0,001 %) от наибольшего по модулю числа соотношения, SHALL считаться мягким («в пределах округления»). Мягкие: соотношения `strict: false` и «сумма пятизначных подстрок = четырёхзначный родитель». Результат — `{failed: [...], soft_failed: [...]}`, элемент — `{column_index, relation, expected, actual}`; MUST NOT храниться в БД. Присутствующими SHALL считаться строки формы из БД, кроме строк, созданных правкой аналитика (`line_code_original_value IS NULL`), у которых все суммы пустые; строки, достроенные в ответе по справочнику (`documents-api`, `id = null`), в проверках MUST NOT участвовать. Созданная правкой строка с хотя бы одной непустой суммой проверяется по всем колонкам, пустые суммы — 0. #### Scenario: Сходящийся баланс - **WHEN** проверяется форма `mezheninovskaya/2025-Q3/1_Форма1_бух_09` - **THEN** `failed` пуст #### Scenario: Нарушение жёсткого соотношения - **WHEN** у баланса 1600 = 1000, 1100 = 300, 1200 = 600 в колонке 0 - **THEN** `failed` содержит `{column_index: 0, relation: "1600 = 1100 + 1200", expected: 1000, actual: 900}` #### Scenario: Расходы со знаком минус - **WHEN** ОФР 2110 = 100, 2120 = −60, 2100 = 40 - **THEN** `2100 = 2110 − 2120` выполнено через вариант с `abs_terms` #### Scenario: Правка исправляет нарушение - **WHEN** аналитик правит 1200 с 600 на 700 в форме из предыдущего сценария - **THEN** проверка по текущим суммам: `failed` пуст #### Scenario: Пустая шаблонная строка не проверяется - **WHEN** в форме нет строки 1700 (в ответе она достроена пустой), 1300 + 1400 + 1500 = 2 371 333 в колонке 0 - **THEN** соотношения с целью 1700 (`1700 = 1300 + 1400 + 1500`) не проверяются; `1600 = 1700` (цель 1600 есть в форме, 1700 = 0) нарушено — как и без достройки: потерянная строка «БАЛАНС» сама по себе даёт `NEEDS_CHECK` #### Scenario: Заполненная шаблонная строка проверяется - **WHEN** аналитик заполнил 1700 = 2 371 333 только в колонке 0, а в колонке 1 1300 + 1400 + 1500 = 2 000 000 - **THEN** в колонке 0 соотношение выполнено; в колонке 1 `failed` содержит `1700 = 1300 + 1400 + 1500` с `expected 0`, `actual 2000000` #### Scenario: Очищенная шаблонная строка - **WHEN** затем аналитик очищает 1700 в колонке 0 (`amount = null`) - **THEN** строка 1700 снова не участвует в проверках ### Requirement: Межформенная проверка Для документа `BALANCE` или `INCOME` SHALL считаться мягкая проверка `1370(колонка отчётной даты ББ) − 1370(колонка 31 декабря прошлого года ББ) = 2400(колонка отчётного периода ОФР)` с допуском `tolerance`, если найдена форма-пара: документ другого типа формы того же ЮЛ, `period_year` и `period_quarter`, файла не `SUPERSEDED` (подтверждённый, затем самый поздний по `created_at`), и все три колонки. Нарушение SHALL попадать в `cross_form` и MUST NOT блокировать подтверждение. #### Scenario: Пара найдена - **WHEN** у ЮЛ ББ за 2025 Q3 (1370 = 500 на 30.09.2025, 300 на 31.12.2024) и ОФР за 2025 Q3 (2400 = 150) - **THEN** `cross_form` — нарушение `expected 200, actual 150`; подтверждение ББ разрешено #### Scenario: Пары нет - **WHEN** у ЮЛ есть только ББ за период - **THEN** `cross_form` — `null` ### Requirement: Акцепт непройденных проверок Акцепт SHALL записывать `financial_statement_meta.checks_accepted_by`, `checks_accepted_at`, `checks_accepted_comment`; документ с акцептом SHALL считаться прошедшим жёсткие проверки для статуса и подтверждения. Любая правка значений или шапки формы SHALL сбрасывать акцепт (три поля — `NULL`). #### Scenario: Акцепт и правка - **WHEN** аналитик акцептовал нарушение 1600 и затем поправил любое значение - **THEN** поля акцепта пусты, при непройденной проверке документ `NEEDS_CHECK`