11 KiB
statement-checks Specification
Purpose
Логические проверки форм ББ/ОФР §7 в ядре: чистые функции над текущими суммами документа, без хранения результата; акцепт непройденных проверок аналитиком.
Requirements
Requirement: Соотношения §7 по колонкам
Проверки SHALL считаться чистой функцией по текущим financial_statement_value.amount документа для каждой колонки
отдельно по словарю §7 копии пакета arm_statements (statement-normalization; своей копии словаря ядро не держит):
соотношение посчитано, если непуста цель (левая часть) или хотя бы один член (есть строка ok с кодом и непустой
суммой); если пусто всё — соотношение пропускается. В посчитанном соотношении отсутствующий код и пустая сумма в
арифметике — 0, но пустая цель при непустых членах и непустая цель при пустых членах — нарушение (пустая цель даёт
expected = null, P1-21 пакета). Выполнено, если |левая − правая| ≤ tolerance
(1, в единицах формы) хотя бы в одном варианте правой части — как записано или с кодами abs_terms по модулю. Нарушение
жёсткого (strict) соотношения, не превышающее rounding_tolerance_percent (0,001 %) от наибольшего по модулю числа
соотношения, SHALL считаться мягким («в пределах округления»). Мягкие: соотношения strict: false и «сумма пятизначных
подстрок = четырёхзначный родитель». Результат — {failed: [...], soft_failed: [...]}, элемент — {column_index, relation, expected, actual}, где expected и actual могут быть null (expected = null — пустая цель); не хранится как есть: нарушения при приёме и пересчёте записываются в document_issue.
Присутствующими SHALL считаться суммы агрегата формы по коду (требование «Агрегат формы по коду»): строки ok формы из БД, кроме строк, созданных правкой аналитика (row_index IS NULL), у которых все суммы пустые; строки detail, unreadable, missing и строки, достроенные в ответе по справочнику (documents-api, id = null), в проверках MUST NOT участвовать. Созданная правкой строка с хотя бы одной непустой суммой проверяется по всем колонкам; в колонке, где её сумма пуста, она — пустая цель (или член с суммой 0). Повтор кода в форме суммируется. Результат нарушения несёт codes (коды цели и членов соотношения) и line_ids (все строки ok этих кодов). Соотношения считает точка входа пакета для пересчёта по агрегату формы; запись в БД — только в виде document_issue при приёме и пересчёте, api/rules/statement_checks.yaml и код его загрузки в ядре MUST NOT существовать.
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посчитано и нарушено:expected = null,actual = 2371333;1600 = 1700(цель 1600 есть в форме, 1700 пуста) тоже нарушено; потерявшая итоговую строку форма блокирует подтверждение (CHECKS_NOT_PASSED) до правки строки или акцепта (P3-30)
Scenario: Все стороны пусты
- WHEN в колонке нет ни цели, ни членов соотношения
- THEN соотношение пропускается, нарушения нет
Scenario: Заполненная шаблонная строка проверяется
- WHEN аналитик заполнил 1700 = 2 371 333 только в колонке 0, а в колонке 1 1300 + 1400 + 1500 = 2 000 000
- THEN в колонке 0 соотношение выполнено; в колонке 1
failedсодержит1700 = 1300 + 1400 + 1500сexpected = null(1700 в колонке 1 пуста),actual = 2000000
Scenario: Очищенная шаблонная строка
- WHEN затем аналитик очищает 1700 в колонке 0 (
amount = null) - THEN строка 1700 снова не участвует в проверках как значение: пустая цель при непустых членах — нарушение
expected = nullв каждой колонке (прежнее «очищенная строка не цель» не действует, P3-30)
Scenario: Повтор кода суммируется
- WHEN в ББ две строки 1230 со значениями 100 и 50 в колонке 0
- THEN соотношения берут 1230 = 150
Scenario: Копии словаря §7 в ядре нет
- WHEN проверяется репозиторий ядра после перехода на пакет
- THEN файла
api/rules/statement_checks.yamlнет,load_check_rules/run_checksвapi/srcне встречаются; допускtoleranceберётся из правил пакета
Requirement: Межформенная проверка
Для документа BALANCE или INCOME SHALL считаться мягкая проверка 1370(колонка отчётной даты ББ) − 1370(колонка 31 декабря прошлого года ББ) = 2400(колонка отчётного периода ОФР) с допуском tolerance, если найдена форма-пара:
документ другого типа формы того же ЮЛ, period_year и period_quarter, файла не SUPERSEDED (подтверждённый, затем
самый поздний по created_at), и все три колонки. Значение 1370 / 2400 берётся по агрегату формы по коду (сумма строк ok с этим кодом). Нарушение 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
Scenario: Межформенная проверка по агрегату
- WHEN в ББ две строки 1370 (сумма 500 и 300 на отчётную дату)
- THEN межформенная проверка берёт 1370 = 800
Requirement: Акцепт непройденных проверок
Акцепт SHALL записывать financial_statement_meta.checks_accepted_by, checks_accepted_at,
checks_accepted_comment; документ с акцептом SHALL считаться прошедшим жёсткие проверки для статуса и подтверждения.
Любая правка значений или шапки формы SHALL сбрасывать акцепт (три поля — NULL).
Scenario: Акцепт и правка
- WHEN аналитик акцептовал нарушение 1600 и затем поправил любое значение
- THEN поля акцепта пусты, при непройденной проверке документ
NEEDS_CHECK
Requirement: Агрегат формы по коду
Все чтения формы «по коду» SHALL идти через одну чистую функцию «агрегат формы по коду» без хранения (DECISION-5):
для кода и колонки — сумма amount строк ok с этим кодом (null, если ни одной непустой), список line_id,
справочное имя. На неё переводятся межформенная проверка 1370 / 2400, суммы формы для консолидации и выгрузок,
parent_code подстрок, раскладка строк на экране, правка ячеек по line_code, метрики fields_*. Строки detail,
unreadable, missing в агрегат, КФО и снимок ЕХ MUST NOT попадать.
Scenario: Межформенная проверка по агрегату
- WHEN в ББ две строки 1370 (сумма 500 и 300 на отчётную дату)
- THEN межформенная проверка берёт 1370 = 800