# osv/synthetic — синтетические ОСВ Синтетика для форматов шапки, иерархии и колонок, которых нет в реальных файлах `osv/{rb,schastl}/`. Данных реальных организаций здесь нет: организация «ООО "Тестовая организация"», контрагенты «ООО Альфа», «ООО Бета» и т. п., ИНН вымышленные. Файлы — **вход** парсера ОСВ (`tabular-parser`), а не эталон: ожидания по каждому файлу выведены из спеки (`openspec/changes/slice-2a-osv-parser/specs/osv-parsing/spec.md`) и лежат в тесте `tabular-parser/api/tests/synthetic/test_synthetic_files.py`. Суммы согласованы арифметически (сальдо на конец = начало + обороты, родитель = сумма детей по колонкам), поэтому все файлы, кроме `s10`, сходятся по контрольным суммам §1.4 и дают статус `done`. ## Генерация Файлы собирает детерминированный генератор (openpyxl + минимальный писатель BIFF12 для xlsb); повторный запуск даёт те же байты (метки времени книги и zip зафиксированы): ``` cd tabular-parser/api .venv/bin/python -m tests.synthetic.generate ../../fixtures/osv/synthetic ``` Правка набора — в `tabular-parser/api/tests/synthetic/generate.py`, затем перегенерация и коммит файлов здесь. ## Набор | Файл | Что проверяет | Ожидание | |---|---|---| | `s01_variant2_header.xlsx` | шапка варианта 2: «Период: …», «Детализация по субсчетам, субконто: Контрагенты, Договоры», заголовок «Субконто»; данные «Сумма» | `header_variant=2`, `group_schema=[ACCOUNT, COUNTERPARTY, CONTRACT]`, `Q1`/2026, `data_type=SUM`, `hierarchy=outline` | | `s02_no_outline_indent.xlsx` | уровни только отступами ячеек (без outline level); `Валюта БУ, НУ: руб.`; период «2 квартал 2025 г.» | `hierarchy=indent`, дерево 0/1/2 | | `s03_no_outline_no_indent.xlsx` | ни outline, ни отступов: уровни по кодам счетов и жирности; период «I кв. 2025 г.» (римский квартал) | `hierarchy=account_pattern`, дерево как у `s02` | | `s04_currency_quantity_rows.xlsx` | под контрагентом строки «USD», «Кол.» (и «Вал.» у другого) | `data_type` `CURRENCY`/`QUANTITY`, в проверку суммы детей не входят, `done` | | `s05_text_numbers.xlsx` | суммы текстом: «1 234 567,89», «(1 234,00)», «—»; неразрывные и узкие пробелы, прочерки «–», «-»; период «полугодие 2025 г.» | `1234567.89`, `-1234.00`, `null` | | `s06_two_osv_and_other_sheet.xlsx` | листы «ОСВ 60», «Справка», «ОСВ 62» | два документа в порядке листов, предупреждение о пропуске «Справка» | | `s07_no_opening_collapsed_closing.xlsx` | нет группы «Сальдо на начало»; сальдо на конец — одна колонка со знаком; период «9 месяцев 2025 г.» | `opening_* = null`, отрицательное сальдо — в `closing_credit`, предупреждение о свёрнутом сальдо | | `s08_extra_kpp_column.xlsx` | колонка «КПП» между «ИНН» и суммами; период «с 01.01.2025 по 31.03.2025» | `extra["КПП"]` у контрагентов, суммы не сдвинуты | | `s09_subaccount_names.xlsx` | «60.01, Расчеты с поставщиками и подрядчиками», буквенный субсчёт «60.АВ, …» | `ACCOUNT`, `account_code_raw` без названия, `row_value` — исходный текст | | `s10_broken_sum.xlsx` | у «ООО Бета» `closing_debit` увеличен на 1 | `needs_check`, нарушение тождества — строка контрагента, суммы родителя — строка «60.01» | | `s11_header_repeat.xlsx` | заголовок таблицы повторяется внутри данных (печать по страницам); период «12 месяцев 2025 г.» | строки заголовка пропущены, дерево и суммы не нарушены | | `s12_statement_and_osv.xlsx` | лист ББ («Бухгалтерский баланс», 0710001) и лист «ОСВ 60»; данные «НУ», период «январь - сентябрь 2025 г.» | один документ, предупреждение «skipped: statement» | | `s13_no_outline_indent.xlsb` | та же ведомость, что `s02`, в формате xlsb; отступ — ведущими пробелами текста | результат равен `s02` кроме предупреждения «xlsb: outline level недоступен» | | `s14_statement_forms.xlsx` | три листа форм, каждый опознаётся одним признаком: «Форма по ОКУД 0710001», «Отчет о финансовых результатах», «Форма по ОКУД 0710002»; лист «ОСВ 60» | один документ, три предупреждения «skipped: statement» | | `s15_group_title_synonyms.xlsx` | названия групп сумм: лист «ОСВ 60» — «Входящее сальдо»/«Конечное сальдо», лист «ОСВ 62» — «Начальное сальдо»/«Исходящее сальдо» | два документа, все шесть колонок сумм найдены, `done` | | `s16_header_synonyms.xlsx` | лист «ОСВ 60»: нет названия организации, период «2024», валюта «RUB (код 643)», «Счет» и «Контрагенты» отдельными строками под «Дебет/Кредит»; лист «ОСВ 62» (вариант 2): «Детализация по субсчетам: Номенклатура, Статьи затрат, Нематериальные активы, Валюта» | `organization_name=""` + предупреждение, `Q4`/2024, `currency=RUB`, схема листа 62 — `ACCOUNT` + четыре `OTHER` | | `s17_inn_in_name.xlsx` | колонки ИНН нет, ИНН записан в текст названия контрагента: «ООО Альфа, 7701234567», «ООО Бета (ИНН 7707654321)», «ООО Гамма ИНН: 5001234567», «ИП Сидоров 500100732259» (OQ-100) | `counterparty_inn` — цифры, `counterparty_name` — без ИНН и разделителя, `row_value` не меняется; физлицо без ИНН — `null`; `done` | | `s18_inn_row_above.xlsx` | у «ООО Альфа» и «ООО Гамма» ИНН стоит отдельной строкой над названием (без сумм, тот же уровень), колонки ИНН нет (OQ-130) | строка с ИНН в `rows` не попадает и не уходит в `OTHER`; ИНН — у контрагента, предупреждение «ИНН … над строкой … отнесён к ней»; `done` | | `s19_inn_kpp_cell.xlsx` | колонка «ИНН/КПП»: в ячейках склеенное «7701234567/770101001» (OQ-100) | `counterparty_inn` — только ИНН; колонка распознана как колонка ИНН; `done` | `s17`–`s19` — регрессия извлечения ИНН из текста (issue #9). `s14`–`s16` добавлены тестом покрытия словарей `tabular-parser` (`rules/*.yaml`, решение R-22): каждая запись словаря должна сработать на реальных или синтетических файлах; эти файлы закрывают записи, которых нет в реальных ОСВ. ## О файле xlsb `s13_no_outline_indent.xlsb` собран **не Excel и не LibreOffice** (их на машине разработки нет), а минимальным писателем BIFF12 `tabular-parser/api/tests/synthetic/xlsb_writer.py`: он пишет только то, что читает `pyxlsb` (workbook, таблица общих строк, лист; без стилей и объединений). Файл читается `pyxlsb` и парсером, но совместимость с Excel не проверялась и этот файл не доказывает чтение xlsb, сохранённого Excel (другая раскладка записей, стили, `BrtCellSt` и т. д.). Когда появится возможность — заменить `s13` настоящим: открыть `s02_no_outline_indent.xlsx` в Excel или LibreOffice, «Сохранить как» → Книга Excel двоичная (`.xlsb`), имя `s13_no_outline_indent.xlsb`; в xlsb нет outline level и форматирования ячеек, отступ нужно продублировать ведущими пробелами в колонке текста до сохранения.