19 KiB
MODIFIED Requirements
Requirement: Шапка документа и схема группировок
Парсер SHALL извлечь из области выше заголовка таблицы: organization_name (первая непустая текстовая строка, trim),
account_code_raw (после «по счету»/«по счёту», как в файле: «60», «58.03»), period_text (после «за» до «г.»/конца),
data_type («Выводимые данные: БУ/НУ/сумма»), currency («Валюта …: RUB/руб.» → RUB), header_variant (1 — группировки
строками первой колонки блока заголовка; 2 — перечисление «субконто: …»). group_schema SHALL начинаться с ACCOUNT и далее
перечислять группировки в порядке вложенности по словарю rules/osv_groups.yaml; ячейка ИНН в строке группировки →
has_inn = true. Элемент вида <группировка>.ИНН (суффикс после последней точки — по словарю service_columns.inn,
префикс — имя группировки COUNTERPARTY этой же шапки; вариант 2 — элемент списка «субконто: …», вариант 1 — строка блока
заголовка) MUST NOT попадать в group_schema: группировка-владелец получает has_inn = true, а элемент служит
подсказкой для строк ИНН (требование «Строки ИНН рядом с контрагентом»): стоит после владельца — ИНН под
наименованием, перед владельцем — над. period_quarter/is_cumulative SHALL вычисляться только по тексту по
rules/periods.yaml (§1.5, ASSUMPTION(OQ-02)), period_year — четыре цифры года. Отсутствие любого поля шапки, кроме
обязательных по контракту, — null и предупреждение; отсутствие organization_name/period_text — пустая строка и
предупреждение (контракт требует строку).
Scenario: Вариант 1 с тремя строками группировок
- WHEN разбирается
schastl/2024-Q3/…62 за 3 квартал 2024 г..xls - THEN
group_schema = [ACCOUNT, DEPARTMENT, COUNTERPARTY(has_inn=true)],header_variant = 1,account_code_raw = "62",period_text = "3 квартал 2024 г.",period_quarter = "Q3",is_cumulative = false,data_type = "BU",currency = "RUB"
Scenario: ОСВ по субсчёту и годовой период
- WHEN разбираются
rb/2024-Q3/сч 583_3 кв 2024.xlsxиrb/2024-FY/ОСВ_66 за 2024.xls - THEN у первого
account_code_raw = "58.03"; у второгоperiod_quarter = "Q4",is_cumulative = true
Scenario: Вариант 2
- WHEN разбирается синтетическая ОСВ с шапкой «Период: 1 квартал 2026 г.», «Детализация по субсчетам, субконто: Контрагенты, Договоры», заголовком «Субконто»
- THEN
header_variant = 2,group_schema = [ACCOUNT, COUNTERPARTY, CONTRACT],period_quarter = "Q1"
Scenario: Реквизит ИНН после группировки
- WHEN разбирается
osv-dkb/novopetrovskaya/2025-Q3/60_ 9мес.2025г.xls(шапка «субконто: Контрагенты, Контрагенты.ИНН») - THEN
group_schema = [ACCOUNT, COUNTERPARTY(has_inn=true)], подсказка «ИНН под наименованием»
Scenario: Реквизит ИНН перед группировкой
- WHEN в синтетической ОСВ шапка «субконто: Контрагенты.ИНН, Контрагенты»
- THEN
group_schema = [ACCOUNT, COUNTERPARTY(has_inn=true)], подсказка «ИНН над наименованием»
Requirement: Классификация строк
Классификация SHALL выполняться над деревом, из которого уже убраны склеенные строки ИНН (требование «Строки ИНН рядом с
контрагентом»). Каждая строка данных SHALL получить group_type: ACCOUNT — текст матчит ACCOUNT_RE (регистр
учитывается, IGNORECASE нет): две-три цифры и до двух сегментов субсчёта через точку, где сегмент — \d{1,2} или 1–3
заглавные буквы кириллицы/латиницы («76.АВ», «76.ВА», «76.ОТ», R-16), далее опционально запятая и название:
^\d{2,3}(\.(\d{1,2}|[А-ЯЁA-Z]{1,3})){0,2}(,\s*.*)?$ с флагами re.ASCII | re.DOTALL (после запятой допустим любой
пробел или его отсутствие, R-18; цифры — только 0–9; название после запятой может занимать несколько строк ячейки — M-1);
account_code_raw — код как в файле, без названия после запятой. Не-счёт — группировка из group_schema по позиции
(число не-счётных предков после последнего ACCOUNT + 1), при выходе за схему — OTHER; строка ИНН без пары — OTHER;
последняя строка уровня 0 с текстом из словаря «Итого» — TOTAL.
Для COUNTERPARTY counterparty_name SHALL быть текстом строки без ИНН в конце и разделителя перед ним (row_value —
исходный текст; OQ-100), а counterparty_inn — первым найденным из:
- колонки ИНН: цифры текстовой ячейки («ИНН 352819549855» → «352819549855», R-15), склеенная «ИНН/КПП» (
inn_kpp_cell) → ИНН; результат только при 10 или 12 цифрах, иначеnull; число из 9/11 цифр (ИНН регионов 01–09 с потерянным ведущим нулём) дополняется нулём слева (R-24); - строки ИНН, склеенной с этой строкой (требование «Строки ИНН рядом с контрагентом»);
- конца текста названия: 10 или 12 цифр после запятой, скобки, «/», пробела или метки «ИНН»
(
counterparty_inn_suffix; «Полиграф, 3528315710», «ООО Альфа (ИНН 7701234567)»). Контрольная сумма ИНН из колонки и из названия MUST NOT проверяться. Строки «Вал.», «Кол.», трёхбуквенного кода валюты SHALL получатьgroup_type = OTHER,data_typeCURRENCY/QUANTITY, MUST NOT занимать позицию вgroup_schemaи MUST NOT наследоватьcounterparty_name/counterparty_inn(account_code_rawнаследуется от ветки, R-19); их суммы остаются в шести полях. Остальные строки получаютdata_typeшапки. Все строки, включая TOTAL, SHALL присутствовать вrows(ASSUMPTION(OQ-01): хранить ли «Итого», решает ядро); склеенные строки ИНН вrowsMUST NOT попадать.
Scenario: Подразделение, контрагент с ИНН, физлицо
- WHEN разбирается
schastl/2024-Q3/…62 за 3 квартал 2024 г..xls - THEN «БП Аренда» → DEPARTMENT; «МАЛЕЧКИНСКАЯ ПТИЦЕФАБРИКА ООО» → COUNTERPARTY с
counterparty_innиз 10 цифр; «Ведомость в счет з/платы» → COUNTERPARTY сcounterparty_inn = null
Scenario: ИНН в конце названия
- WHEN разбирается синтетическая ОСВ
s17(ИНН в тексте названия с разными разделителями) - THEN у контрагентов
counterparty_nameбез ИНН,counterparty_inn— ИНН из текста,row_value— исходный текст
Scenario: «ИНН/КПП» в одной ячейке колонки ИНН
- WHEN разбирается синтетическая ОСВ
s19 - THEN
counterparty_inn— 10 цифр до «/»
Scenario: Название субсчёта в строке счёта
- WHEN в синтетической ОСВ строка «60.01, Расчеты с поставщиками»
- THEN
group_type = ACCOUNT,account_code_raw = "60.01",row_value— исходный текст
Scenario: Буквенный субсчёт
- WHEN в ОСВ 76 строка «76.АВ» (реальные файлы РБ и Счастливочной) либо «60.АВ, …» (синтетика)
- THEN
group_type = ACCOUNT, строка наследуется детьми как счёт ветки; «76.ав» (строчные) счётом не считается
Scenario: Строки Вал./Кол.
- WHEN в синтетической ОСВ под контрагентом строки «USD» и «Кол.»
- THEN
group_type = OTHER,data_type = CURRENCYиQUANTITY,counterparty_name/counterparty_innравныnull,account_code_rawсовпадает с родителем, строки исключены из проверки «сумма детей = родитель», статусdone
ADDED Requirements
Requirement: Строки ИНН рядом с контрагентом
Между построением иерархии и классификацией парсер SHALL найти строки ИНН и сопоставить каждую с её строкой-наименованием в любой из восьми раскладок: ИНН над / под наименованием × в дереве (родитель или ребёнок наименования) / не в дереве (сосед того же родителя) × с суммами / без сумм.
Строка ИНН — не счёт, не «Итого», не строка Вал./Кол., подпись которой целиком — ИНН по словарю inn_only_row
(10 или 12 цифр числом или текстом, «ИНН 7701234567», «ИНН: 7701234567 / 770101001»); числовая ячейка из 9/11 цифр
дополняется нулём слева (R-24, #34). Без подсказки <группировка>.ИНН в шапке ИНН MUST пройти контрольную сумму ИНН
(алгоритм ФНС); строка из 10/12 цифр с неверной контрольной суммой рядом с наименованием MUST NOT считаться строкой ИНН:
она классифицируется как обычно, в warnings — «строка N похожа на ИНН …, контрольная сумма не сходится», документ —
needs_check. С подсказкой контрольная сумма не проверяется, а пустая подпись строки-ребёнка наименования — строка ИНН
«ИНН не указан» (склейка без ИНН, без needs_check, R-1 #32). Наименование — строка не счёт, не «Итого», не Вал./Кол.,
не строка ИНН. С подсказкой «под» единственный ребёнок наименования с теми же суммами и непустой подписью, которая не
ИНН, — строка ИНН с нераспознанным ИНН (без пары, «ИНН не распознан»).
Пара строки ИНН (связь в дереве важнее соседства):
- у строки ИНН есть дети → пара — её единственный ребёнок-наименование; несколько детей — пары нет. Если в
group_schemaбольше одной группировки и ни одна строка листа (кроме Вал./Кол.) не стоит глубже схемы, строка ИНН не склеивается и без предупреждения классифицируется по схеме; - родитель строки ИНН — наименование → пара — родитель; несколько строк ИНН у одного наименования — пары нет. Если у такой строки ИНН есть дети, пара — родитель только при подсказке «под» или (без подсказки) если родитель по схеме — COUNTERPARTY; иначе действует правило «есть дети»;
- иначе — непосредственный сосед того же родителя: при суммах — сосед с теми же суммами (совпали оба — по направлению); без сумм — сосед по направлению листа (над → следующий, под → предыдущий).
Если у строки ИНН есть суммы, все шесть MUST совпасть с суммами пары (пустая ячейка = 0), иначе пары нет. Направление
листа — первое определённое из: порядок <группировка>.ИНН в шапке; пары соседей, найденные по суммам; однозначные блоки
детей одного родителя из несопоставленных строк ИНН и наименований (начинается строкой ИНН — над; кончается строкой ИНН —
под; начинается и кончается — блок сломан, его строки ИНН без пары). Противоречие сведений или их отсутствие — направление
неизвестно, строки ИНН без сумм, которым оно нужно, остаются без пары. Две строки ИНН с одной парой — обе без пары.
Склейка: строка ИНН MUST NOT попадать в rows, её ИНН — наименованию (источник 2 требования «Классификация строк»),
её дети переходят к наименованию, при «над, в дереве» наименование с поддеревом поднимается на её место; в warnings —
«строка N: ИНН … отнесён к контрагенту в строке M». ИНН колонки ИНН у наименования, отличный от ИНН строки, остаётся,
в warnings — расхождение, документ — needs_check.
Без пары: строка ИНН остаётся в rows с group_type = OTHER (в свод ядра не попадает), в warnings — «строка N:
ИНН … без пары — <причина>», документ — needs_check. Структура под склейку MUST NOT подгоняться.
Scenario: Восемь раскладок без подсказки
- WHEN разбираются синтетические ОСВ
s20…s27(по одной на раскладку; ИНН с верной контрольной суммой; шапка безКонтрагенты.ИНН) - THEN у каждого контрагента
counterparty_inn— ИНН его строки ИНН, строк ИНН вrowsнет, контрагентов столько же, сколько наименований, контрольные суммы сходятся, статусdone
Scenario: ИНН под наименованием не уходит следующему контрагенту
- WHEN в синтетической ОСВ
s27(ИНН под наименованием, не в дереве, без сумм) идут «ООО Альфа», ИНН Альфы, «ООО Бета», ИНН Беты - THEN ИНН Альфы — у «ООО Альфа», ИНН Беты — у «ООО Бета»
Scenario: ИНН над наименованием (OQ-130)
- WHEN разбирается синтетическая ОСВ
s18(строка ИНН без сумм над наименованием, ИНН с верной контрольной суммой) - THEN ИНН — у контрагента под строкой, строк ИНН в
rowsнет, статусdone
Scenario: Реквизит «Контрагенты.ИНН» (OQ-162)
- WHEN разбирается
osv-dkb/novopetrovskaya/2025-Q3/60_ 9мес.2025г.xls - THEN результат совпадает с golden до изменения: 713 из 716 контрагентов с ИНН (включая ИНН с неверной контрольной
суммой), 3 физлица без ИНН, статус
done
Scenario: Неверная контрольная сумма без подсказки
- WHEN в синтетической ОСВ без подсказки над наименованием строка «7701234567» (контрольная сумма не сходится)
- THEN строка не склеивается, в
warnings— «похожа на ИНН, контрольная сумма не сходится», статусneeds_check
Scenario: Ведущий ноль у числовой строки ИНН
- WHEN строка ИНН без подсказки — числовая ячейка
123456788(9 цифр;0123456788проходит контрольную сумму) - THEN
counterparty_inn = "0123456788"
Scenario: Неоднозначное направление
- WHEN под счётом блок «наименование, ИНН без сумм, наименование» и других сведений о направлении нет
- THEN строка ИНН без пары,
group_type = OTHER, предупреждение «направление неизвестно», статусneeds_check
Scenario: Несколько детей у строки ИНН
- WHEN у строки ИНН в дереве два ребёнка-наименования
- THEN строка ИНН без пары,
group_type = OTHER, статусneeds_check