From ece851b0edee3b5929b381a111a907274bf793ee Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Mon, 19 Oct 2026 13:05:49 +0400 Subject: [PATCH] =?UTF-8?q?=D0=90=D1=80=D1=85=D0=B8=D0=B2=20OpenSpec:=20os?= =?UTF-8?q?v-indicator-column=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change перенесён в openspec/changes/archive/2026-10-19-osv-indicator-column, дельта влита в openspec/specs/osv-parsing/spec.md (строки-показатели, колонка «Показатели», «В валюте», BU по умолчанию, счёт 90 в OQ-132). Co-Authored-By: Claude Opus 5.5 --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/osv-parsing/spec.md | 0 .../2026-10-19-osv-indicator-column}/tasks.md | 0 openspec/specs/osv-parsing/spec.md | 76 +++++++++++++++++-- 6 files changed, 68 insertions(+), 8 deletions(-) rename openspec/changes/{osv-indicator-column => archive/2026-10-19-osv-indicator-column}/.openspec.yaml (100%) rename openspec/changes/{osv-indicator-column => archive/2026-10-19-osv-indicator-column}/design.md (100%) rename openspec/changes/{osv-indicator-column => archive/2026-10-19-osv-indicator-column}/proposal.md (100%) rename openspec/changes/{osv-indicator-column => archive/2026-10-19-osv-indicator-column}/specs/osv-parsing/spec.md (100%) rename openspec/changes/{osv-indicator-column => archive/2026-10-19-osv-indicator-column}/tasks.md (100%) diff --git a/openspec/changes/osv-indicator-column/.openspec.yaml b/openspec/changes/archive/2026-10-19-osv-indicator-column/.openspec.yaml similarity index 100% rename from openspec/changes/osv-indicator-column/.openspec.yaml rename to openspec/changes/archive/2026-10-19-osv-indicator-column/.openspec.yaml diff --git a/openspec/changes/osv-indicator-column/design.md b/openspec/changes/archive/2026-10-19-osv-indicator-column/design.md similarity index 100% rename from openspec/changes/osv-indicator-column/design.md rename to openspec/changes/archive/2026-10-19-osv-indicator-column/design.md diff --git a/openspec/changes/osv-indicator-column/proposal.md b/openspec/changes/archive/2026-10-19-osv-indicator-column/proposal.md similarity index 100% rename from openspec/changes/osv-indicator-column/proposal.md rename to openspec/changes/archive/2026-10-19-osv-indicator-column/proposal.md diff --git a/openspec/changes/osv-indicator-column/specs/osv-parsing/spec.md b/openspec/changes/archive/2026-10-19-osv-indicator-column/specs/osv-parsing/spec.md similarity index 100% rename from openspec/changes/osv-indicator-column/specs/osv-parsing/spec.md rename to openspec/changes/archive/2026-10-19-osv-indicator-column/specs/osv-parsing/spec.md diff --git a/openspec/changes/osv-indicator-column/tasks.md b/openspec/changes/archive/2026-10-19-osv-indicator-column/tasks.md similarity index 100% rename from openspec/changes/osv-indicator-column/tasks.md rename to openspec/changes/archive/2026-10-19-osv-indicator-column/tasks.md diff --git a/openspec/specs/osv-parsing/spec.md b/openspec/specs/osv-parsing/spec.md index 416c3a3..623edc3 100644 --- a/openspec/specs/osv-parsing/spec.md +++ b/openspec/specs/osv-parsing/spec.md @@ -144,10 +144,12 @@ SHALL пропускаться с предупреждением файла `SHE 2. строки ИНН, склеенной с этой строкой (требование «Строки ИНН рядом с контрагентом»); 3. конца текста названия: 10 или 12 цифр после запятой, скобки, «/», пробела или метки «ИНН» (`counterparty_inn_suffix`; «Полиграф, 3528315710», «ООО Альфа (ИНН 7701234567)»). -Контрольная сумма ИНН из колонки и из названия MUST NOT проверяться. Строки «Вал.», «Кол.», трёхбуквенного кода валюты -SHALL получать `group_type = OTHER`, `data_type` CURRENCY/QUANTITY, MUST NOT занимать позицию в `group_schema` и MUST NOT -наследовать `counterparty_name`/`counterparty_inn` (`account_code_raw` наследуется от ветки, R-19); их суммы остаются в -шести полях. Остальные строки получают `data_type` шапки. Все строки, включая TOTAL, SHALL присутствовать в `rows` +Контрольная сумма ИНН из колонки и из названия MUST NOT проверяться. Строки-показатели (требование «Строки-показатели +и колонка «Показатели»») SHALL получать `group_type = OTHER`, `data_type` по метке, MUST NOT занимать позицию в +`group_schema` и MUST NOT наследовать `counterparty_name`/`counterparty_inn` (`account_code_raw` наследуется от ветки +родителя, R-19); их суммы остаются в шести полях. Строка с меткой «БУ» в колонке «Показатели» получает `data_type = BU`. +Остальные строки получают `data_type` шапки, а если шапка вид данных не называет — `BU` и одно предупреждение `OSV_HEADER` +на лист «вид данных в шапке не указан — строки без метки приняты как БУ» (`header.data_type` остаётся `null`). Все строки, включая TOTAL, SHALL присутствовать в `rows` (`ASSUMPTION(OQ-01)`: хранить ли «Итого», решает ядро); склеенные строки ИНН в `rows` MUST NOT попадать. #### Scenario: Подразделение, контрагент с ИНН, физлицо @@ -176,6 +178,15 @@ SHALL получать `group_type = OTHER`, `data_type` CURRENCY/QUANTITY, MUST - **THEN** `group_type = OTHER`, `data_type = CURRENCY` и `QUANTITY`, `counterparty_name`/`counterparty_inn` равны `null`, `account_code_raw` совпадает с родителем, строки исключены из проверки «сумма детей = родитель», статус `done` +#### Scenario: Шапка без вида данных +- **WHEN** разбирается синтетическая ОСВ `s36` (шапка без «Выводимые данные», колонки «Показатели» нет) +- **THEN** `header.data_type = null`, у всех строк данных и «Итого» `data_type = BU`, в `warnings` одно `OSV_HEADER` «вид + данных в шапке не указан — строки без метки приняты как БУ», статус `done` + +#### Scenario: «Валюта <код>» — обычная строка +- **WHEN** в синтетической ОСВ `s35` под контрагентом строка «Валюта USD» с рублёвыми суммами +- **THEN** `group_type = OTHER`, `data_type` шапки, строка участвует в сверке «сумма детей = родитель» + ### Requirement: Числа — Decimal, пусто — null Суммы SHALL приводиться к `Decimal` с двумя знаками: числовые ячейки — через строковое представление; текстовые — после удаления пробелов (включая неразрывные и узкие), замены запятой на точку, `(x)` → `-x`; «-», «—», «–», пустая ячейка → @@ -191,8 +202,9 @@ SHALL получать `group_type = OTHER`, `data_type` CURRENCY/QUANTITY, MUST turnover_credit = closing_debit − closing_credit` (±0.01, `null` = 0); по каждому родителю суммы = Σ детей с тем же `data_type` (±0.01), причём **обороты** сверяются по колонкам, а **сальдо** (начало, конец) — по колонкам либо, если у родителя сальдо свёрнуто (не больше одной ненулевой стороны), по нетто «дебет − кредит» (R-21: 1С показывает счёт нетто, -а субсчета и контрагентов — развёрнуто; остаточные риски перечислены ниже); строки CURRENCY/QUANTITY в суммирование не входят и сами -родителями не проверяются; строка TOTAL = корневая строка ACCOUNT (первая строка уровня 0). Если корня нет (пустая ОСВ, +а субсчета и контрагентов — развёрнуто; остаточные риски перечислены ниже); строки-показатели (требование «Строки-показатели и колонка +«Показатели»») в суммирование не входят и сами родителями не проверяются; строка TOTAL = корневая строка ACCOUNT +(первая строка уровня 0); итоговая строка-показатель («Итого» с меткой «НУ», «Кол.») в эту сверку не входит. Если корня нет (пустая ОСВ, R-13), «Итого» SHALL быть пустой или нулевой. Если строка «Итого» не найдена, `total_row_matches_root = false` и в `warnings` — «строка «Итого» не найдена» (R-20). Результат — `checks{total_row_matches_root, balance_identity_violations, parent_sum_violations}`. Результат проверки SHALL записываться в документ листа (контракт v2.0): `status` листа — `done`, когда контрольные суммы @@ -203,9 +215,9 @@ balance_identity_violations, parent_sum_violations}`. Результат про `OSV_XLSB_NO_OUTLINE`); строк вида `sheet=<имя> <текст>` в `metrics.warnings` больше нет. Парсер MUST NOT подгонять структуру под сходимость. -Исключение — **счета без сальдо по аналитике** (решение владельца 07.10.2026, OQ-132): у 91 и 99 строки аналитики несут +Исключение — **счета без сальдо по аналитике** (решение владельца 07.10.2026, OQ-132): у 90, 91 и 99 строки аналитики несут только обороты, сальдо закрыто на субсчёт закрытия (91.09). Список счетов — данные `rules/osv_checks.yaml` -(`accounts_without_analytic_balance`, начальный состав `91`, `99`; 90 не входит). Строка относится к такому счёту, если +(`accounts_without_analytic_balance`, состав `90`, `91`, `99`; счёт 90 добавлен решением владельца 19.10.2026). Строка относится к такому счёту, если код ближайшего счёта её ветки (`account_code_raw`) совпадает с записью списка либо является её субсчётом (`91`, `91.01`, но не `910`). Для таких строк тождество строки SHALL NOT проверяться; сверка «сумма детей = родитель» сохраняется: обороты — всегда по колонкам, сальдо — только у родителя с дочерними субсчетами (корень → субсчета), а у @@ -463,3 +475,51 @@ design #14). #### Scenario: Несколько детей у строки ИНН - **WHEN** у строки ИНН в дереве два ребёнка-наименования - **THEN** строка ИНН без пары, `group_type = OTHER`, статус `needs_check` + +### Requirement: Строки-показатели и колонка «Показатели» +Строка-показатель — строка, которая несёт вид сумм предыдущей строки данных, а не уровень аналитики. Парсер SHALL считать +строку показателем, если: +1. в таблице есть колонка «Показатели» (заголовок блока по словарю `osv_headers.yaml` — `service_columns.indicator`, + «Показатели», «Показа-тели»), ячейка строки в ней непуста и метка не «БУ»: «НУ» → `data_type = NU`, «Кол.» → + QUANTITY, «Вал.» → CURRENCY (словарь `data_types.yaml` — `indicator_column`); «ПР», «ВР» (`indicator_column_untyped`) + → `data_type = null`; метка не из словарей → `data_type = null` и предупреждение `OSV_ROWS` «строка N: метка «X» в + колонке «Показатели» не распознана — строка не участвует в проверках»; +2. иначе — текст строки матчит `data_types.yaml` — `row` («Вал.», «Кол.», «Кол-во», «В валюте» → CURRENCY/QUANTITY) или + равен коду валюты из `currency_codes`. + +Строка «Валюта <код>» («Валюта USD») MUST NOT считаться показателем: это строка аналитики с рублёвыми суммами; код валюты +не хранится. Колонка «Показатели» MUST NOT быть колонкой текста строки (как колонка ИНН) и SHALL оставаться в `extra` +строки под своим заголовком. `row_value` строки с меткой колонки — сама метка. + +Строки-показатели MUST NOT передаваться в каскад иерархии. Родитель строки-показателя — ближайшая строка выше, которая +сама не показатель; уровень — на один глубже родителя; показатель без строки данных выше — уровень 0 без родителя. +Строки-показатели MUST NOT входить в сверку «сумма детей = родитель» (ни как дети, ни как родители) и в сверку «Итого»; +тождество строки (начало + обороты = конец) проверяется у них, как у всех строк. Строки NU хранятся как пришли +(`ASSUMPTION(OQ-45)`); собственных проверок по NU нет (AURORA-1669). + +Итоговые строки, следующие сразу за основной «Итого» и помеченные в колонке «Показатели» меткой показателя, SHALL +оставаться в таблице как TOTAL (`data_type` по метке) и MUST NOT уходить в подвал или давать предупреждение «ниже +таблицы есть числа»; сверка «Итого = корень» берёт первую итоговую строку, которая не показатель. + +#### Scenario: Колонка «Показатели» БУ/НУ +- **WHEN** разбирается синтетическая ОСВ `s33` (счёт 02, шапка без «Выводимые данные», колонка «Показа-тели», на каждую + строку — «БУ» и «НУ», название объединено на две строки, «Итого» БУ и НУ) +- **THEN** строки «БУ» — `data_type = BU`, строки «НУ» — `data_type = NU`, `row_value = "НУ"`, `group_type = OTHER`, + родитель — строка «БУ» над ней; `parent_sum_violations = []`, `total_row_matches_root = true`, две строки TOTAL + (BU и NU), предупреждения «ниже таблицы» и «вид данных … приняты как БУ» нет, статус `done` + +#### Scenario: Количество, валюта и разницы в колонке «Показатели» +- **WHEN** разбирается синтетическая ОСВ `s34` (колонка «Показатели» с метками «Кол.», «Вал.», «ПР», «ВР» и одной + неизвестной меткой) +- **THEN** «Кол.» — QUANTITY, «Вал.» — CURRENCY, «ПР»/«ВР»/неизвестная — `data_type = null`, все — показатели вне + сверки родителя; одно предупреждение `OSV_ROWS` о нераспознанной метке; статус `done` + +#### Scenario: «В валюте» под «Валюта <код>» +- **WHEN** разбирается синтетическая ОСВ `s35` (под контрагентом пары «Валюта USD» / «В валюте», «Валюта EUR» / + «В валюте») +- **THEN** «В валюте» — CURRENCY, родитель — «Валюта …» над ней; контрагент = Σ строк «Валюта …» по рублям; + статус `done` + +#### Scenario: Строки «Вал.»/«Кол.» в колонке текста не меняются +- **WHEN** разбираются s04, s30 и все реальные фикстуры `../fixtures/osv/**` +- **THEN** golden-снимки совпадают с прежними (родитель показателя — строка над ним, как и было)