from decimal import Decimal as D from arm_statements.header import parse_header from arm_statements.issues import make_warning from arm_statements.lines import build_lines, units_warnings from arm_statements.loader import Rules from arm_statements.model import FormCandidate, Severity, StatementLine, StatementWarning from arm_statements.rows import collect_raw_lines from arm_statements.segments import find_layout from arm_statements.tests.builders import excel, hdr, ocr HEAD = ["Наименование показателя", "Код", "На 30.09.2025"] CODE_CONFIDENCE = 99.0 NAME_CONFIDENCE = 71.0 def statement_lines(cand: FormCandidate, rules: Rules) -> tuple[list[StatementLine], list[StatementWarning]]: layout = find_layout(cand, parse_header(hdr(), rules), rules) raw, _ = collect_raw_lines(cand, layout, rules) return build_lines(raw, cand.source, rules) def test_ocr_name_and_code_confidence(rules: Rules) -> None: cand = ocr([HEAD, [("Дебиторская задолжен-ность", 71.0), "1230", "5"], ["Итого", "I1О0", "5"]]) lines, _ = statement_lines(cand, rules) assert (lines[0].line_name, lines[0].line_name_confidence) == ("Дебиторская задолжен-ность", NAME_CONFIDENCE) assert (lines[1].line_code, lines[1].line_code_text, lines[1].line_code_confidence) == ( "1100", "I1О0", CODE_CONFIDENCE, ) assert [v.column_index for v in lines[0].values] == [2] def test_value_out_of_range_warning(rules: Rules) -> None: cand = excel([("Баланс", [["Наименование", "Код", "На 30.09.2025"], ["Запасы", "1210", D("123456789012345678")]])]) lines, warnings = statement_lines(cand, rules) assert lines[0].values[0].amount is None assert [(w.code, w.severity, w.line_refs, w.column_index) for w in warnings] == [ ("VALUE_OUT_OF_RANGE", Severity.INFO, ("Баланс!B2",), 2) ] def test_excel_code_ref_and_clean_confidence(rules: Rules) -> None: cand = excel([("Баланс", [["Наименование", "Код", "На 30.09.2025"], ["Запасы", "1210", D("5")]])]) lines, warnings = statement_lines(cand, rules) assert (lines[0].ref, lines[0].line_code, lines[0].line_code_text) == ("Баланс!B2", "1210", "1210") assert (lines[0].line_code_confidence, lines[0].needs_review, warnings) == (100.0, False, []) def test_fractional_in_thousands(rules: Rules) -> None: pairs = [("1210", "1.5"), ("1220", "2.25"), ("1230", "3"), ("1240", "4"), ("1200", "10.75")] title: list[str | D | None] = ["Наименование", "Код", "На 30.09.2025"] body: list[list[str | D | None]] = [[f"Строка {i}", c, D(v)] for i, (c, v) in enumerate(pairs)] rows = [title, *body] cand = excel([("Баланс", rows)]) lines, _ = statement_lines(cand, rules) head = parse_header(hdr(units="тыс. руб."), rules) assert [w.code for w in units_warnings(lines, head, (), rules)] == ["FRACTIONAL_IN_THOUSANDS"] xlsb = make_warning("XLSB_NO_FORMATS", "формат чисел xlsb не читается", rules) (scale,) = units_warnings(lines, head, (xlsb,), rules) assert (scale.code, scale.severity) == ("XLSB_SCALE_SUSPECT", Severity.ERROR) assert units_warnings(lines, parse_header(hdr(units="руб."), rules), (), rules) == []