"""Строки-показатели ОСВ (§1.3, AURORA-1613, AURORA-1661): метка вида суммы строки и привязка к строке данных.""" from dataclasses import dataclass from src.contract.common import DataType from src.parser.detect import TableHeader from src.parser.grid import Sheet from src.parser.rules import Rules, first_match, normalize_text __all__ = ["RowLabel", "column_label", "is_indicator_total", "read_label", "row_data_type"] @dataclass(frozen=True) class RowLabel: """Вид строки по метке: показатель ли она, `data_type` метки, текст строки взамен исходного, предупреждение.""" indicator: bool data_type: DataType | None text: str | None = None # для метки колонки «Показатели» — сама метка (`row_value`) warning: str | None = None def row_data_type(text: str, rules: Rules, currency_codes: frozenset[str]) -> DataType | None: """CURRENCY/QUANTITY по словарю строк («Вал.», «Кол.») или коду валюты ISO («USD», «usd»); иначе `None`.""" found = first_match(rules.data_types.row, text) if found is not None: return found return "CURRENCY" if normalize_text(text).upper() in currency_codes else None def column_label(sheet: Sheet, row: int, header: TableHeader) -> str: """Метка строки в колонке «Показатели» (пусто — колонки нет или ячейка пуста).""" return "" if header.indicator_col is None else sheet.text_at(row, header.indicator_col) def read_label(sheet: Sheet, row: int, text: str, header: TableHeader, rules: Rules) -> RowLabel: """Метка колонки «Показатели» важнее текста строки: «БУ» — строка данных BU, прочие — показатели; без метки — показатель по тексту («Вал.», «Кол.», «Кол-во», «В валюте», код валюты), иначе обычная строка без своего вида.""" label = column_label(sheet, row, header) if label: data_type = first_match(rules.data_types.indicator_column, label) if data_type == "BU": return RowLabel(indicator=False, data_type="BU") if data_type is not None or any(p.search(label) for p in rules.data_types.indicator_column_untyped): return RowLabel(indicator=True, data_type=data_type, text=label) warning = f"строка {row}: метка «{label}» в колонке «Показатели» не распознана — строка вне проверок" return RowLabel(indicator=True, data_type=None, text=label, warning=warning) data_type = row_data_type(text, rules, frozenset(rules.data_types.currency_codes)) return RowLabel(indicator=data_type is not None, data_type=data_type) def is_indicator_total(sheet: Sheet, row: int, header: TableHeader, rules: Rules) -> bool: """Итоговая строка-показатель за «Итого»: метка колонки «Показатели» не «БУ».""" label = column_label(sheet, row, header) return bool(label) and first_match(rules.data_types.indicator_column, label) != "BU"