"""Блоки форм, вид листа и столбцы на словарях `arm_statements` (план 4, задача 4).""" import pytest from gridbuilder import at, sheet_from_rows from arm_statements import DocumentType, continuation_type, default_rules from src.parser.statements.forms import ( StatementRules, caption_matches, classify_statement_sheet, codes_of, continuation_marker, find_blocks, is_weak_continuation, matches, sheet_amount_columns, sheet_code_column, ) CODE_COL = 3 @pytest.fixture(scope="module") def rules() -> StatementRules: return default_rules() def test_title_and_okud_without_codes_between_form_one_block(rules: StatementRules) -> None: sheet = sheet_from_rows( [ ["Бухгалтерская отчетность"], [], [None, "Бухгалтерский баланс"], [], [*at({3: "Форма по ОКУД", 5: "0710001"})], [*at({1: "Актив", 3: "Код", 4: "На 30.09.2025"})], [*at({1: "Основные средства", 3: "1150", 4: 10})], ] ) [block] = find_blocks(sheet, rules) assert (block.type_hint, block.title, block.okud, block.first_row, block.last_row) == ( DocumentType.BALANCE, (3, 2), (5, 5), 1, 7, ) def test_second_title_after_codes_opens_new_block(rules: StatementRules) -> None: balance = [at({1: name, 3: code, 4: 10}) for name, code in (("а", 1110), ("б", 1150), ("в", 1170), ("г", 1600))] income = [at({1: name, 3: code, 4: 10}) for name, code in (("д", 2110), ("е", 2120), ("ж", 2400))] sheet = sheet_from_rows( [["Бухгалтерский баланс"], *balance, ["Отчет о финансовых результатах"], *income], ) blocks = find_blocks(sheet, rules) assert [(b.type_hint, b.first_row, b.last_row) for b in blocks] == [ (DocumentType.BALANCE, 1, 5), (DocumentType.INCOME, 6, 9), ] def test_okud_wins_over_title(rules: StatementRules) -> None: blocks = find_blocks(sheet_from_rows([["Бухгалтерский баланс"], ["по ОКУД", "0710002"]]), rules) assert [block.type_hint for block in blocks] == [DocumentType.INCOME] def test_report_title_alone_is_not_a_form(rules: StatementRules) -> None: assert find_blocks(sheet_from_rows([["Бухгалтерская отчетность"]]), rules) == [] def test_continuation_marker_is_not_a_block(rules: StatementRules) -> None: sheet = sheet_from_rows([["Форма 0710001 с.2"], ["Пассив", "Код", "На 30.09.2025"], ["Капитал", "1310", 10]]) assert find_blocks(sheet, rules) == [] assert classify_statement_sheet(sheet, rules) == "continuation" def test_code_column_ignores_title_codes_block(rules: StatementRules) -> None: titles = ["Коды", "0710001", 30, "09", 2025, 12345678, 7700000000, 12267, 16, 384] codes = [1110, 1150, 1170, 1100, 1210, 1230] rows = [at({6: value}) for value in titles] rows += [at({3: code, 4: 10}) for code in codes] sheet = sheet_from_rows(rows) assert sheet_code_column(sheet, rules, 1, sheet.n_rows) == CODE_COL assert codes_of(sheet, rules, CODE_COL, 1, sheet.n_rows) == [str(code) for code in codes] def test_amount_columns_counts_numeric_columns_right_of_code(rules: StatementRules) -> None: rows = [at({1: "Актив", 3: "Код", 4: "На 30.09.2025", 7: "Изменение"})] rows += [at({1: "Статья", 3: code, 4: 1, 5: 2, 6: 3, 7: "рост"}) for code in (1110, 1150, 1170, 1100)] sheet = sheet_from_rows(rows) assert sheet_amount_columns(sheet, rules, CODE_COL, 1, sheet.n_rows) == CODE_COL def test_weak_and_other_sheets(rules: StatementRules) -> None: weak = sheet_from_rows([["Чистая прибыль", "2400", 10, 8]]) assert classify_statement_sheet(weak, rules) == "other" assert is_weak_continuation(weak, rules, DocumentType.INCOME) assert not is_weak_continuation(weak, rules, DocumentType.BALANCE) notes = sheet_from_rows([["Примечания"], ["Текст пояснения к отчетности"]]) assert classify_statement_sheet(notes, rules) == "other" assert not is_weak_continuation(notes, rules, DocumentType.INCOME) def test_marker_with_unknown_okud_is_continuation(rules: StatementRules) -> None: rows = [["Форма 0710000 с.2"]] + [at({1: "Статья", 3: code, 4: 10}) for code in (1110, 1150, 1170)] sheet = sheet_from_rows(rows) assert find_blocks(sheet, rules) == [] assert classify_statement_sheet(sheet, rules) == "continuation" marker = continuation_marker(sheet, rules) assert marker is not None assert marker.text == "Форма 0710000 с.2" assert continuation_type(marker.text, rules) is None def test_labels_with_punctuation_match(rules: StatementRules) -> None: assert matches(rules.headers.labels["address"], "Местонахождение (адрес)") assert matches(rules.headers.labels["okopf_okfs"], "по ОКОПФ / ОКФС") assert matches(rules.headers.legal_form, "АО «Пример»") assert caption_matches([rules.headers.code_caption], "Код")