20 KiB
Raw Blame History

ADDED Requirements

Requirement: Шаг 2 — разрез кандидата по смене формы

Перед шагами 2–8 кандидат SHALL разрезаться на части по смене формы (AURORA-1734, решение владельца 06.11.2026). Сегменты кандидата ищутся по правилу «Шаг 2 — сегменты, повторная шапка и границы листов». Тип формы сегмента — по первым min_codes кодам (порог словаря диапазонов): все они одной формы (отрезок → document_type, как на шаге 6) — это тип, которым сегмент открывается; иначе тип не определён. Новая часть SHALL начинаться с первой строки сегмента, если у сегмента своя строка-шапка и он открывается формой, отличной от типа текущей части (тип части — по большинству кодов её первого сегмента с кодами; после разреза — тип, которым открылась часть). Сегменты без шапки, с числом кодов меньше порога или той же формы остаются в текущей части; строки другой формы, приклеенные к сегменту без своей шапки (сегмент открывается кодами текущей формы), разреза не дают.

Часть — обычный FormCandidate для шагов 2–8: строки сетки с первой строки сегмента до начала следующей части, segment_breaks — сдвинутые на начало части; header — тот же, что у исходного кандидата (шапка файла ИС одна на таблицу); source тот же. Первая часть сохраняет locator, type_hint, evidence и warnings исходного кандидата; следующая часть k (с 1) получает locator = "<locator исходного>;form:<k>", type_hint = null, пустые evidence, из warnings — только предупреждения источника XLSB_NO_FORMATS (без них шаг 4 неверно проверяет масштаб xlsb) — её тип определяется на шаге 6 только по кодам, без TYPE_CONFLICT от заголовка таблицы. Кандидат без смены формы SHALL оставаться одним кандидатом без изменений.

Пакет SHALL экспортировать функцию разреза (split_by_form(candidate, rules) → tuple[FormCandidate, ...]); хост вызывает её на каждый кандидат и передаёт части в normalize_candidate по порядку. Документы частей — отдельные документы результата (ядро различает их по file_ordinal, Р-10); модель данных и контракт не меняются. Правило общее для OCR и Excel.

Scenario: ББ и ОФР одной таблицей ИС (АК-ЮЛ)

  • WHEN таблица ИС «Бухгалтерский баланс» содержит строки 1110…1700 (две страницы ББ с повторной шапкой на строке 19), а со строки 41 — шапку «Наименование показателя | Коды | За I полугодие 2026 года | …» и строки 2110…2400
  • THEN две части: ББ — строки 0–40, locator = "file:<json>;table:0", колонки ББ; ОФР — строки 41–60, locator = "file:<json>;table:0;form:1", колонки и периоды по своей шапке, TYPE_CONFLICT нет; повторная шапка строки 19 разреза не даёт (тот же тип)

Scenario: Раздел 25xx после ОФР

  • WHEN в таблице ОФР повторная шапка открывает сегмент со строками 2510…2910
  • THEN разреза нет: тип сегмента тот же (INCOME), сегмент — продолжение ОФР

Scenario: ОФР без своей шапки после пассива

  • WHEN после повторной шапки ББ идут строки 1310, 1300, 1700, а следом без шапки — 2110, 2120, 2100, 2400
  • THEN разреза нет: сегмент открывается кодами ББ (как и до изменения)

Scenario: Пара строк другой формы

  • WHEN после строк ББ повторная шапка открывает сегмент с двумя кодами 2xxx (меньше порога min_codes)
  • THEN разреза нет, сегмент остаётся в части ББ (как раньше)

MODIFIED Requirements

Requirement: Шаг 1 — многостраничная форма

Требование относится к адаптеру Excel: у OCR каждая таблица ИС — отдельный кандидат, склейки таблиц нет (повторная шапка внутри таблицы ИС — сегмент шага 2; смена формы внутри таблицы — разрез кандидата, требование «Шаг 2 — разрез кандидата по смене формы»). У Excel одна форма SHALL быть одной сеткой на выходе шага 1. Строки продолжения дописываются в конец сетки по маркеру «Форма … с.2» или по позиции листа; граница листа записывается в segment_breaks. Тип из маркера продолжения SHALL сверяться с type_hint формы: расхождение — отдельный кандидат и предупреждение CONTINUATION_TYPE_CONFLICT (error). Лист без маркера и без шапки присоединяется, только если его коды в диапазоне открытой формы и, при трёх и более кодах, число колонок сумм совпадает с формой; иначе — отдельный кандидат и предупреждение SHEET_NOT_JOINED (error).

Scenario: Лист-продолжение с одной строкой

  • WHEN после листа ОФР идёт лист без шапки с единственной строкой 2400
  • THEN лист присоединяется к ОФР (код в диапазоне формы, кодов меньше трёх — число колонок не сверяется), граница листа — в segment_breaks

Scenario: Лист другой ширины с тремя кодами

  • WHEN лист без маркера и шапки содержит три кода ББ и четыре колонки сумм при трёх у открытой формы
  • THEN лист — отдельный кандидат, предупреждение SHEET_NOT_JOINED уровня error

Requirement: Шаг 2 — подпись и дата колонки

Подпись колонки SHALL разбираться одним словарём периодов statement_periods.yaml, объединяющим словарь tabular-parser и шаблоны dates.py scan-gateway; строки test_dates.py::test_parses_real_forms scan-gateway — обязательные тесты словаря. Результат — period_date (конец периода колонки) и period_kind:

  • абсолютная подпись («На 31 марта 2025 г.», «31.12.2024», «30/09/25», «30092025», «За 9 месяцев 2025 г.», «с 01.01.2025 по 31.03.2025», «2024», хвост «0:00:00», клетки «2|0|2|4|») → absolute;
  • относительная: «На отчётную дату», «За отчётный период» → relative:current (= эффективная дата); «На 31 декабря предыдущего года» → relative:prev_year_end (31.12 года эффективной даты − 1); «На 31 декабря года, предшествующего предыдущему» → relative:prev_prev_year_end (31.12 года − 2); «За аналогичный период предыдущего года» → relative:prev_period (эффективная дата − 1 год, 29 февраля → 28 февраля);
  • подписи нет → none.

Эффективная дата документа SHALL быть датой отчёта из шапки, иначе самой поздней абсолютной датой колонок; нет ни той, ни другой → у относительных колонок period_date = null, period_kind остаётся относительным.

Подпись из словаря исключений («Изменение», «Отклонение», «%», «Темп», «Доля», «Примечание») SHALL пропускаться с предупреждением COLUMN_SKIPPED (info). Подпись, не разобранная ни как период, ни как исключение, при числах в столбце в строках с кодами SHALL оставлять колонку с подписью как есть, period_date = null, period_kind = none и предупреждением COLUMN_WITHOUT_DATE (error, column_index); без чисел — пропуск. Подпись OCR с уверенностью ниже 100, разобранная в дату, подтверждается, если дата входит в ожидаемые: эффективная дата, она же минус один и минус два года, 31 декабря предыдущего и предшествующего ему года; иначе предупреждение COLUMN_DATE_UNCERTAIN (error, column_index). Уверенность подписи — label_confidence (у Excel 100; подписи нет — null).

Если среди колонок значений сегмента есть хотя бы одна с подписью периода (абсолютной или относительной), столбец без текста подписи правее последней такой колонки SHALL НЕ считаться колонкой сумм: его числа не попадают в значения строк, COLUMN_WITHOUT_DATE не выдаётся, вместо этого выдаётся одно предупреждение NUMBERS_OUTSIDE_TABLE (info) с адресами ячеек, собранными по всем сегментам формы (в тексте — первые 10, дальше «и ещё N»). Предупреждение SHALL НЕ влиять на статус документа. Решение владельца 18.10.2026 (Р-44). Правило общее для Excel и OCR и живёт в пакете. У сегмента без подписанных колонок (лист-продолжение без шапки) столбцы без текста подписи сверх числа колонок документа SHALL считаться числами правее таблицы. Подписанный столбец без чисел в строках с кодами границей таблицы не служит. Адрес ячейки — <лист>!<A1> у Excel и row:<n> у OCR. Без подписанных колонок, а также для столбца без подписи между подписанными и для столбца с любым текстом подписи, не разобранным как период или исключение, поведение прежнее (COLUMN_WITHOUT_DATE), кроме редкого столбца ниже.

Редкий столбец с неразобранной подписью (AURORA-1735, решение владельца 06.11.2026) SHALL НЕ считаться колонкой сумм, если одновременно: у столбца есть текст подписи, не разобранный ни как период, ни как исключение; левее и правее него в сегменте есть колонки значений с подписью периода; число стоит не более чем в одной строке с кодом этого столбца, а в каждой колонке значений сегмента с подписью периода — не менее чем в трёх; в строке этого числа у всех колонок периода тоже есть числа (число лишнее, а не сдвинутое OCR из пустой ячейки периода). Его числа не попадают в значения строк, COLUMN_WITHOUT_DATE не выдаётся; адреса его чисел добавляются в то же предупреждение NUMBERS_OUTSIDE_TABLE (info). Если среди адресов предупреждения есть адреса такого столбца, текст — «числа вне колонок формы не учитываются: …», иначе прежний «числа правее таблицы формы не учитываются: …». Это разорванная OCR подпись периода («31» + «а I полугодие 2025 года») с посторонним числом под обрывком; столбец с числами в двух и более строках с кодом остаётся колонкой с COLUMN_WITHOUT_DATE; единственное число в строке, где ячейка колонки периода пуста, — тоже.

Подтверждение SHALL опираться только на уверенные источники, чтобы неуверенное не подтверждало само себя: для неуверенной подписи эффективная дата — дата отчёта с уверенностью 100, иначе самая поздняя абсолютная дата колонок с уверенной подписью (label_confidence = 100); такой нет — подпись не подтверждена. Неуверенная дата отчёта (шаг 8, поля шапки) подтверждается только самой поздней абсолютной датой колонок с уверенной подписью. Для периода документа и относительных подписей эффективная дата считается, как выше, по всем источникам.

Scenario: Бланк 66н без впечатанных дат

  • WHEN подписи колонок ББ — «На отчетную дату», «На 31 декабря предыдущего года», «На 31 декабря года, предшествующего предыдущему», дата отчёта шапки 30.09.2025
  • THEN period_date колонок 2025-09-30, 2024-12-31, 2023-12-31, period_kind — relative:current, relative:prev_year_end, relative:prev_prev_year_end; предупреждений о дате колонок нет

Scenario: Неуверенная подпись не подтверждает сама себя

  • WHEN даты отчёта в шапке нет, единственная колонка с абсолютной датой — подпись OCR «На 30.09.2О25» с уверенностью 60, остальные колонки без подписи
  • THEN эффективная дата для подтверждения строится без этой подписи — уверенных источников нет, подпись не подтверждена: COLUMN_DATE_UNCERTAIN уровня error; период документа (period_known) по-прежнему определяется этой датой

Scenario: Мусорная подпись над числами

  • WHEN подпись колонки — "| | г" с уверенностью 17, а в колонке суммы
  • THEN колонка остаётся, period_date = null, period_kind = none, предупреждение COLUMN_WITHOUT_DATE уровня error с column_index, документ needs_check

Scenario: Числа справа от таблицы

  • WHEN у ББ подписи периодов стоят над столбцами M, Q, S, а правее таблицы в строках с кодами лежат формулы аналитика (V45, W57, U58, V58, V72, W72) над пустой шапкой (Межениновская 2025-Q3)
  • THEN колонок значений три, числа U–W в значения не попадают, COLUMN_WITHOUT_DATE и SEGMENT_COLUMNS_MISMATCH нет; одно предупреждение NUMBERS_OUTSIDE_TABLE уровня info с адресами этих ячеек; документ done, если нет других причин

Scenario: Столбец без подписи между подписанными

  • WHEN между колонками с подписями периода стоит столбец без подписи с числами
  • THEN он остаётся колонкой с COLUMN_WITHOUT_DATE уровня error, NUMBERS_OUTSIDE_TABLE нет

Scenario: Подписанных колонок нет

  • WHEN ни у одного столбца значений нет подписи периода
  • THEN правило «числа справа от таблицы» не применяется, столбцы с числами — колонки с COLUMN_WITHOUT_DATE

Scenario: Обрывок подписи периода (Калтан, AURORA-1735)

  • WHEN у ОФР подписи «За 1 полугодие 2026 года» (столбец 4), «31» (столбец 5), «а I полугодие 2025 года» (столбец 6); в столбцах 4 и 6 суммы в десятке строк с кодом, в столбце 5 — одно число «$301 .» в строке 2400 и тире
  • THEN колонок значений две (4 и 6), COLUMN_WITHOUT_DATE нет; NUMBERS_OUTSIDE_TABLE уровня info с адресом ячейки строки 2400 столбца 5 и текстом «числа вне колонок формы не учитываются: row:21»; число 301 в значения не попадает

Scenario: Неразобранная подпись над двумя числами

  • WHEN между двумя колонками периодов стоит столбец с подписью «Прим.» (не из словаря исключений), числа в нём — в двух строках с кодом
  • THEN столбец остаётся колонкой с COLUMN_WITHOUT_DATE уровня error

Scenario: Значение, сдвинутое в обрывок подписи

  • WHEN у столбца «31» между колонками периодов одно число «55» в строке 2460, а ячейка колонки периода 2025 этой строки пуста
  • THEN столбец остаётся колонкой с COLUMN_WITHOUT_DATE уровня error, документ needs_check — значение не теряется молча

Scenario: Колонка «Изменение»

  • WHEN правее периодов колонка «Изменение, %»
  • THEN колонка пропускается, предупреждение COLUMN_SKIPPED уровня info