Адрес ячейки остаётся в message. Добавлен инвариант-тест по golden: line_refs предупреждений документа входят в ref строк, locator нет, column_index есть среди колонок. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
64 lines
3.3 KiB
Python
64 lines
3.3 KiB
Python
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) == []
|