56 lines
3.3 KiB
Python
56 lines
3.3 KiB
Python
"""Строки-показатели ОСВ (§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"
|