Andrey Epifancev d564d4998d План: номера синтетики s33–s36 вместо s40–s43 (R-1, #58)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 11:29:53 +04:00

108 lines
12 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.

# Design: колонка «Показатели» и валютные строки ОСВ
Правило — `05-domain-rules.md` §1.3 (абзацы «строки-показатели», «Колонка «Показатели»»), §1.4 (сверка родителя),
ветка docs `feat/58-osv-indicators`.
## Как выглядит файл (реальный образец контура, в git не кладётся)
`result_dir.zip`, `files/3da66219-….xlsx` — ОСВ по счёту 02, шапка без «Выводимые данные» («Параметры: Валюта БУ, НУ:
Руб»):
```
r7 Счет | Показа-\nтели | Сальдо на начало | Обороты за период | Сальдо на конец
r8 Основные средства | | Дебет | Кредит | Дебет | Кредит | Дебет | Кредит
r10 02 | БУ | | 480896,82 | 45754,41 | 46336,70 | | 481479,11 outline 0
r11 | НУ | | 480896,82 | 45754,41 | 46336,71 | | 481479,12 outline 0
r12 Интерактивная … | БУ | … outline 1
r13 | НУ | … outline 1
r16 Машина … (A16:D17 объединены) | БУ | … outline 1
r17 (продолжение объединения) | НУ | … outline 1
r30 Итого (A30:D31 объединены) | БУ | … outline 0
r31 (продолжение) | НУ | … outline 0
```
`files/270b41da-….xlsx` (плоская форма, трек B) — пары строк «Валюта CNY» (рубли) / «В валюте» (сумма в валюте) под
субсчётом 76.55.
Сейчас: колонка «Показа-тели» попадает в `extra_cols` и в `_label_cols` (r11, r13 — пустой текст → текст «НУ» из
колонки E, отступ +1000 → ребёнок строки БУ); r17 — текст объединённой ячейки (повтор названия), `data_type` всех строк
`null` (шапка молчит); r31 — не «Итого развернутое», `_trailing_totals` обрывается, строка уходит в подвал с
предупреждением «ниже таблицы есть числа».
## Решения
### Признак строки-показателя — поле строки, не значение `data_type`
Сейчас «показатель» = `data_type ∈ {CURRENCY, QUANTITY}` (`checks._INDICATOR_DATA_TYPES`). NU в этот набор добавить
нельзя: документ с «Выводимые данные: НУ» (s12) целиком состоит из строк NU, и все его проверки пропали бы. Поэтому
вводится признак `indicator: bool` у `BodyRow` (вычисляется при сборе строк) и у `ClassifiedRow`; `checks._is_indicator`
читает признак. Строка-показатель — если:
1. в листе есть колонка «Показатели», ячейка строки в ней непуста и метка ≠ «БУ» (словарь
`data_types.indicator_column`); `data_type` — из словаря; «ПР», «ВР» — `null` (словарь `indicator_column_untyped`);
метка не из обоих словарей — `null` + предупреждение `OSV_ROWS` «строка N: метка «X» в колонке «Показатели» не
распознана — строка не участвует в проверках»;
2. иначе — текст строки матчит `data_types.row` («Вал.», «Кол.», «Кол-во», **«В валюте»**) или равен коду валюты
(как сейчас, `row_data_type`).
Метка «БУ» в колонке даёт строке `data_type = BU` явно (даже если шапка молчит или называет НУ — колонка точнее шапки).
### Текст строки с меткой колонки — метка
У строки-показателя из колонки текст в колонке текста либо пуст, либо повторяет объединённую ячейку строки БУ (r17).
`BodyRow.text` = метка («НУ»), `is_account = False`. Так `row_value` не дублирует название объекта, а ИНН-логика и
классификатор не принимают строку за счёт или контрагента. Колонка «Показатели» исключается из `_label_cols` (как колонка
ИНН) и остаётся в `extra` под своим заголовком.
### Иерархия: показатели вне каскада, родитель — предыдущая строка данных
Новый модуль `src/parser/indicators.py` (чтобы не пересекаться с треком B в `hierarchy.py`):
`attach_indicators(rows, levels, total_row) -> Levels`. В `OsvParser.parse_sheet` каскад `resolve_levels` получает
строки без показателей; затем каждому показателю (до «Итого») назначается родитель — ближайшая строка выше, которая не
показатель, — и уровень `level(родителя) + 1`; показатель в начале таблицы без строки данных выше — уровень 0 без
родителя. Итоговые строки-показатели — уровень 0 без родителя (как «Итого»). Стратегия иерархии (`Levels.strategy`) —
стратегия каскада.
Для строк «Вал.»/«Кол.» под контрагентом (s04, s30, реальные файлы) результат совпадает с прежним: 1С печатает
показатель сразу под строкой, к которой он относится. Golden-проверка это подтверждает; любое расхождение golden на
реальных файлах — стоп и вопрос владельцу (не перегенерировать молча).
### Итоговые строки-показатели
`_trailing_totals` продолжает серию итоговых строк и через строки с меткой показателя в колонке «Показатели»
(r31 после r30): они остаются в таблице, классифицируются TOTAL с `data_type` метки и `indicator = True`;
`checks._total` берёт первую итоговую строку **не показатель**. Трек B меняет `_trailing_totals`/`_total` под
«Итого развернутое» перед «Итого» — при слиянии второй трек добавляет своё условие к версии первого.
### Вид данных по умолчанию
Если шапка не называет вид данных (`doc.data_type is None`), строки без собственного вида (не показатели и без метки
«БУ») получают `BU`; один раз на лист — предупреждение `OSV_HEADER` «вид данных в шапке не указан — строки без метки
приняты как БУ». Если все строки данных размечены колонкой «Показатели», предупреждения нет (умолчание не
применялось). `header.data_type` остаётся `null`; существующее предупреждение шапки «тип выводимых данных … не найден»
сохраняется.
### Что не меняется
- `balance_identity` проверяет все строки, включая показатели (как сейчас у «Вал.»/«Кол.»): у НУ/количества тождество
«начало + обороты = конец» тоже выполняется.
- «Валюта <код>» — обычная строка OTHER (рубли): `row_data_type("Валюта USD")` = `None` уже сейчас; закрепляется тестом.
- Контракт, DBML, arm-core.
## Decisions made without discussion
| Дата | Решение | Обоснование | Что стоит ошибка |
|---|---|---|---|
| 19.10.2026 | «ПР», «ВР» и метка не из словаря — `data_type = null`, строка-показатель | В контракте нет значения для разниц; `null` ядро не берёт в свод, проверки строку не видят | Разницы не видны как отдельный вид данных до AURORA-1669; переразметка — правка словаря |
| 19.10.2026 | Признак показателя — поле `indicator`, а не набор значений `data_type` | Документ «Выводимые данные: НУ» не должен терять проверки | Лишнее поле в двух dataclass; контракт не меняется |
| 19.10.2026 | `row_value` строки с меткой колонки — метка, а не текст колонки текста | Текст там пуст или повтор объединённой ячейки строки БУ | Если 1С когда-то печатает в строке НУ своё название — оно теряется (не встречалось в 31 файле контура) |
| 19.10.2026 | Колонка «Показатели» остаётся в `extra` | Первичка не теряется, ядро `extra` хранит как есть | Дублирование метки в `extra` и `data_type` |
| 19.10.2026 | Родитель показателя — предыдущая строка данных для всех показателей, включая «Вал.»/«Кол.» в колонке текста | Один механизм для колонки, «В валюте» и старых меток; каскад не видит строк, которые ломают дерево | Если показатель стоит не сразу под своей строкой, родитель будет неверным; ловит golden |
| 19.10.2026 | Умолчание BU — только строкам без собственного вида; `header.data_type` остаётся `null` | Шапка действительно молчит; ядру нужен вид строки, не шапки | Предупреждение на листах без «Выводимые данные» (были без него) |
| 19.10.2026 | Синтетика s33–s36 (R-1: s40–s44 заняты треком B #59, s37–s39 резерв) | Рулинг владельца R-1: параллельные треки не конфликтуют по именам файлов набора | Пропуск номеров в наборе |
| 19.10.2026 | Новый модуль `indicators.py` вместо правки `hierarchy.resolve_levels` | Трек B меняет каскад иерархии параллельно | Ещё один модуль конвейера |
Решения владельца 19.10.2026 (чат): п. 1 колонка «Показатели» как метки §1.3, НУ без своих проверок; п. 2 «В валюте» →
CURRENCY, «Валюта <код>» — строка OTHER в рублях, код валюты не хранится; п. 3 BU по умолчанию с предупреждением — по
рекомендации агента, владелец принял без возражений («ошибки давай исправлять сейчас»).