from datetime import date import pytest from arm_statements.dates import expected_dates, parse_date, parse_period_label, resolve_relative from arm_statements.loader import Rules from arm_statements.model import Cell, PeriodKind from arm_statements.text import fix_lookalikes # Обязательные строки scan-gateway test_dates.py::test_parses_real_forms (спека «Шаг 2 — подпись и дата колонки») REAL_FORMS = [ ("на 30 сентября 2025 г.", date(2025, 9, 30)), ("На 30 июня\n2025 г", date(2025, 6, 30)), ("31 декабря 2024 года", date(2024, 12, 31)), ("30 сентября 2025 r.", date(2025, 9, 30)), ("с 01.01.2025 по 30.09.2025", date(2025, 9, 30)), ("I квартал 2026", date(2026, 3, 31)), ("1-й кв. 2026", date(2026, 3, 31)), ("первый квартал 2025 г.", date(2025, 3, 31)), ("1 полугодие 2026", date(2026, 6, 30)), ("1 п/г 2026", date(2026, 6, 30)), ("9 месяцев 2025", date(2025, 9, 30)), ("9 мес. 2025", date(2025, 9, 30)), ("За январь - июнь\n2025 г.", date(2025, 6, 30)), ("январь – сентябрь 2025", date(2025, 9, 30)), ("за 2025 г.", date(2025, 12, 31)), ("2024 год", date(2024, 12, 31)), ("30.09.2025", date(2025, 9, 30)), ("2025 03 31", date(2025, 3, 31)), ("30/09/25", date(2025, 9, 30)), ("2 0 2 4", date(2024, 12, 31)), ("30 09 2 0 2 5", date(2025, 9, 30)), ("30092025", date(2025, 9, 30)), ("20250930", date(2025, 9, 30)), ("30 09 25", date(2025, 9, 30)), ("30.09.2025 0:00:00", date(2025, 9, 30)), ("2|0|2|4|", date(2024, 12, 31)), ("3l.12.2О24", date(2024, 12, 31)), ] @pytest.mark.parametrize(("raw", "expected"), REAL_FORMS) def test_parses_real_forms(rules: Rules, raw: str, expected: date) -> None: assert parse_date(fix_lookalikes(raw, rules.lookalikes), rules) == expected label = parse_period_label(Cell(raw, None, 100.0, "row:0"), rules) assert (label.kind, label.date) == (PeriodKind.ABSOLUTE, expected) @pytest.mark.parametrize("raw", ["Общество с ограниченной ответственностью", "", "+", "тыс. руб.", "1999999999999"]) def test_not_a_date(rules: Rules, raw: str) -> None: assert parse_date(raw, rules) is None def test_long_text_not_parsed(rules: Rules) -> None: assert parse_date("на 30 сентября 2025 г." + "x" * 200, rules) is None @pytest.mark.parametrize( ("raw", "kind"), [ ("На отчетную дату", PeriodKind.CURRENT), ("За отчётный период", PeriodKind.CURRENT), ("На 31 декабря предыдущего года", PeriodKind.PREV_YEAR_END), ("На 31 декабря года, предшествующего предыдущему", PeriodKind.PREV_PREV_YEAR_END), ("За аналогичный период предыдущего года", PeriodKind.PREV_PERIOD), ], ) def test_relative_labels(rules: Rules, raw: str, kind: PeriodKind) -> None: assert parse_period_label(Cell(raw, None, 100.0, "row:0"), rules).kind is kind def test_exclusion_and_excel_date_value(rules: Rules) -> None: assert parse_period_label(Cell("Изменение, %", None, 100.0, "A!F1"), rules).excluded label = parse_period_label(Cell("30.09.2025", date(2025, 9, 30), 100.0, "A!D1"), rules) assert (label.kind, label.date) == (PeriodKind.ABSOLUTE, date(2025, 9, 30)) assert parse_period_label(Cell("2024", None, 100.0, "A!E1"), rules).bare_year def test_empty_label(rules: Rules) -> None: assert parse_period_label(None, rules).kind is PeriodKind.NONE label = parse_period_label(Cell(" ", None, 100.0, "A!G1"), rules) assert (label.kind, label.date, label.excluded, label.bare_year) == (PeriodKind.NONE, None, False, False) def test_resolve_relative_and_expected() -> None: eff = date(2025, 9, 30) assert resolve_relative(PeriodKind.PREV_YEAR_END, eff) == date(2024, 12, 31) assert resolve_relative(PeriodKind.PREV_PREV_YEAR_END, eff) == date(2023, 12, 31) assert resolve_relative(PeriodKind.PREV_PERIOD, date(2024, 2, 29)) == date(2023, 2, 28) assert resolve_relative(PeriodKind.CURRENT, None) is None assert resolve_relative(PeriodKind.ABSOLUTE, eff) is None and resolve_relative(PeriodKind.NONE, eff) is None assert expected_dates(eff) == frozenset( {eff, date(2024, 9, 30), date(2023, 9, 30), date(2024, 12, 31), date(2023, 12, 31)} )