Andrey Epifancev 5634bcd691 Синтетика s48–s57 под tp#81
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:32:29 +04:00

95 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` | у «ООО Альфа» и «ООО Гамма» ИНН с верной контрольной суммой (`7701234560`, `5001234561`) стоит отдельной строкой над названием (без сумм, тот же уровень), колонки ИНН нет (OQ-130); без подсказки в шапке строка с неверной контрольной суммой не склеивается (#35) | строка с ИНН в `rows` не попадает и не уходит в `OTHER`; ИНН — у контрагента, предупреждение «строка N: ИНН … отнесён к контрагенту в строке M»; `done` |
| `s19_inn_kpp_cell.xlsx` | колонка «ИНН/КПП»: в ячейках склеенное «7701234567/770101001» (OQ-100) | `counterparty_inn` — только ИНН; колонка распознана как колонка ИНН; `done` |
| `s20_inn_above_sibling_blank.xlsx` | ИНН строкой **над** наименованием, сосед того же уровня, **без сумм** (#35) | ИНН — у своего контрагента, строк ИНН в `rows` нет, `done` |
| `s21_inn_above_sibling_sums.xlsx` | ИНН строкой над наименованием, сосед, **с теми же суммами** | то же; пара — по равенству сумм |
| `s22_inn_above_parent_blank.xlsx` | строка ИНН — **родитель** наименования (уровень выше), без сумм | наименование поднимается на её место, ИНН — ему, `done` |
| `s23_inn_above_parent_sums.xlsx` | строка ИНН — родитель наименования, с суммами | то же |
| `s24_inn_below_child_blank.xlsx` | строка ИНН — **ребёнок** наименования (уровень ниже), без сумм | ИНН — родителю, строка из `rows` уходит, `done` |
| `s25_inn_below_child_sums.xlsx` | строка ИНН — ребёнок наименования, с суммами (как «Контрагенты.ИНН» в 1С, но без подсказки в шапке) | то же |
| `s26_inn_below_sibling_sums.xlsx` | ИНН строкой **под** наименованием, сосед, с суммами | ИНН — своему контрагенту, `done` |
| `s27_inn_below_sibling_blank.xlsx` | ИНН строкой под наименованием, сосед, без сумм (дефект main: ИНН уходил следующему контрагенту) | ИНН — своему контрагенту; направление — по блоку 60.02, кончающемуся строкой ИНН; `done` |
| `s28_inn_bad_checksum.xlsx` | раскладка `s20` («над, не в дереве, без сумм»), но у ООО Альфа строка ИНН `7701234567` с неверной контрольной суммой (#35) | строка остаётся обычной, у Альфы ИНН нет, предупреждение «похожа на ИНН … контрольная сумма не сходится», `needs_check`; остальные контрагенты — со своими ИНН (направление «над» — по блоку 60.02) |
| `s29_xls_no_codepage.xls` | xls BIFF5 без записи CODEPAGE, строки в cp1251 (собран `tests/synthetic/xls_writer.py`); отступ — ведущими пробелами (AURORA-1662) | кириллица читается как cp1251, предупреждение «xls без кодовой страницы — строки прочитаны как cp1251», `done` |
| `s30_val_kol_vo_materials.xlsx` | счёт 10 (вариант 2, номенклатура): материал «Вал» без точки, под материалами строки «Кол-во» (AURORA-1663) | «Вал» — обычная строка (`data_type` шапки, `OTHER`), «Кол-во» — `QUANTITY`, `done` |
| `s31_rows_below_total.xlsx` | под «Итого» дописаны «Ответственный:», блок «ООО Альфа (ГК)» с числами и строка «Итого по ГК» (AURORA-1664) | таблица кончается на первой «Итого», хвост вне документа, предупреждение «ниже таблицы … есть числа», `done` |
| `s32_total_with_suffix.xlsx` | итоговая строка подписана «Итого по счету 60», точного «Итого» нет (I-1: правило `total_row` — запасное после `total_row_exact`) | `TOTAL` — последняя строка, `done` |
| `s40_flat_header_account.xlsx` | плоская форма 1С (#59, AURORA-1661): «по счету: 76.Н.1» с двоеточием, вид аналитики «Контрагенты» строкой между названием и периодом, организация ниже периода; строк-счетов нет, без outline и отступов; «Итого развернутое» перед «Итого» | `account_code_raw=76.Н.1`, `hierarchy=header_account`, строки `COUNTERPARTY`, «Итого развернутое» и «Итого» — `TOTAL`, `done` |
| `s41_flat_chart_of_accounts.xlsx` | плоская форма: вид аналитики «Организации», период «за 2 Квартал 2026 г. План счетов ООО Хреновская Нива» одной строкой, «Итого развернутое» перед «Итого» | организация из хвоста «План счетов», `account_code_raw=60`, `Q2`/2026, `hierarchy=header_account`, строки `COUNTERPARTY` без предупреждения о виде субконто, `done` |
| `s42_subaccounts_totals_reversed.xlsx` | под счётом 76 в шапке идут строки-субсчета «76.2», «76.5», «76.Н», «76.Н.1» (корня «76» нет), «Итого развернутое» перед «Итого» | `account_code_raw=76`, «Итого развернутое» — `TOTAL`, сверка по основной «Итого», `done` |
| `s43_subkonto_unnamed_60.xlsx` | счёт 60: корень «60.01» и два элемента аналитики с отступом, вид субконто в шапке не назван; «Итого» перед «Итого развернутое» | `hierarchy=indent`, подстроки — `COUNTERPARTY` по плану счетов с предупреждением `OSV_ROWS`, `done` |
| `s44_subkonto_unnamed_10.xlsx` | то же, что `s43`, но счёт 10 (материалы «Мука пшеничная», «Сахар-песок») | счёт 10 не расчётный: подстроки остаются `OTHER` без имени, предупреждения нет, `done` |
| `s45_account_label_value_cells.xlsx` | выгрузка 1С «ОСВ по счёту 60 по контрагентам» (tabular-parser#71, AURORA-1714): слов «по счету» нет, счёт — «Счет Поставщика» \| «60*» в соседних ячейках, «Счет Клиента» без значения; в первой колонке голые числовые коды 441, 431, 199; период «За период» \| «01.01.25..30.06.25» | `account_code_raw=60`, 2025 Q2 нарастающий, голые коды не счета, строки `COUNTERPARTY`, `done` |
| `s46_counterparty_code_blocks.xlsx` | та же выгрузка целиком: вид субконто «Поставщики» в колонке суммы первой строки данных; блоки субсчетов 60.111, 60.112 (сумм в строке нет); в блоке — код контрагента с суммами, строка названия без сумм, договоры (в том числе «441»); «ИТОГ по 60.111» с суммами блока; в конце «ИТОГ» | `hierarchy=code_blocks`, субсчета `ACCOUNT` с суммами из «ИТОГ по …», коды — `COUNTERPARTY` с названием, договоры — `CONTRACT`, строки «ИТОГ по …», названий и «Поставщики» в `rows` нет, «ИТОГ» — `TOTAL`, `done` |
| `s47_indent_hierarchy_code_sums.xlsx` | три листа «Субконто» без вида аналитики в шапке, иерархия по отступам (AURORA-1858, tabular-parser#78): «68 сч.» — подуровень `68.01.1` на том же отступе, что `68.01`; «90 сч.» — безымянная строка закрытия сразу за счётом `90.09` (пустая ячейка отступа не хранится); «91 сч.» — аналитика на одном отступе, вложенность видна только по суммам (`100 = 60 + 40`, `30 = 20 + 10`, `40 ⊃ 40`) | `hierarchy=indent`, `68.01.1` — ребёнок `68.01`, строка закрытия — ребёнок `90.09`/`91.09`, аналитика 91 вложена по суммам, три листа `done` |
`s17`–`s19` — регрессия извлечения ИНН из текста (issue #9). `s14`–`s16` добавлены тестом покрытия словарей `tabular-parser` (`rules/*.yaml`, решение R-22): каждая запись словаря
должна сработать на реальных или синтетических файлах; эти файлы закрывают записи, которых нет в реальных ОСВ.
`s29`–`s32` — tabular-parser#47 (кодировка xls без CODEPAGE, «Вал»/«Кол-во», строки ниже «Итого», итог «Итого по счету»).
`s20`–`s27` — восемь раскладок строки ИНН рядом с контрагентом (issue tabular-parser#35); ИНН с верной контрольной суммой — без подсказки в шапке другие не склеиваются.
`s48`–`s57` — ОСВ других учётных систем (tabular-parser#81, AURORA-1717/1719/1732), контрольный набор. Позитивы
`s48`–`s54`: названия ведомостей («Оборотная ведомость», «ОСВ по сч.», «Оборотный баланс», «Фин. Обороты Листок»,
«Отчет по Главной книге»), итог «ВСЕГО», группы «Остаток на начало/конец», «Оборот по дебету», «Остаток по дебету на
начало», SAP «Сальдо вх/исх» и «…ДТВВ», Navision без названия ведомости (запасной признак по заголовку таблицы), книга
«форма + Navision + справка», те же раскладки в xls и xlsb; проверяют точные суммы по сторонам. Негативы `s55`–`s57`:
названия не с начала ячейки, «Оборотный капитал», 1С «Обороты счета» с корр. счетами между «Оборот Дт» и «Оборот Кт»,
почти-ОСВ без названия (расшифровка с остатками, без «начала», свёрнутое начало, заголовок ниже 30-й строки), форма ББ
со словами «оборотная ведомость» и слабым продолжением — вид листов не меняется. Подписи взяты из реальных файлов банка
первичных документов (sha256 — в `admin/osv-other-systems-regress/headers.md` workspace).
## О файле 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 и форматирования ячеек, отступ нужно продублировать ведущими пробелами в колонке текста до сохранения.