Andrey Epifancev 56c0f01d86 chore(arm_statements): копия пакета arm-statements@6bce80b (#44)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:38:33 +04:00

100 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
from dataclasses import replace
from decimal import Decimal as D
import pytest
from arm_statements import (
DocStatus,
DocumentType,
document_status,
make_warning,
normalize_candidate,
status_input,
status_input_from_contract,
to_contract,
warning_to_contract,
)
from arm_statements.loader import Rules
from arm_statements.model import FailedRelation, StatementChecks, StatementDocument
from arm_statements.tests.builders import hdr, ocr
HEAD = ["Наименование показателя", "Код", "На 30.09.2025"]
FULL_HEADER = hdr(
organization_name="ООО «Пример»", inn=("7700000000", 80.0), report_date="30.09.2025", units="тыс. руб."
)
HEADER_KEYS = {"form_name", "needs_review_fields"} | {
f"{name}{suffix}"
for name in ("organization_name", "inn", "report_date", "units", "okud", "okpo", "okopf", "okfs", "okei", "address")
for suffix in ("", "_text", "_confidence")
}
def balance(rules: Rules, *rows: list[str]) -> StatementDocument:
cand = ocr([HEAD, *rows], header=FULL_HEADER, type_hint=DocumentType.BALANCE, title="Бухгалтерский баланс")
doc = normalize_candidate(cand, rules).document
assert doc is not None
return doc
def test_document_in_contract_form(rules: Rules) -> None:
doc = balance(rules, ["Запасы", "1210", "60"], ["Итого II", "1200", "60"], ["НИ", "", "7"])
data = json.loads(json.dumps(to_contract(doc), ensure_ascii=False))
assert set(data["header"]) == HEADER_KEYS
assert (data["header"]["form_name"], data["header"]["inn"], data["header"]["inn_confidence"]) == (
"Бухгалтерский баланс",
"7700000000",
80.0,
)
assert data["header"]["report_date"] == "2025-09-30" and data["header"]["okei"] is None
assert data["lines"][0]["values"][0]["amount"] == "60.00"
assert {ln["line_status"] for ln in data["lines"]} >= {"ok"}
assert "column_key" not in json.dumps(data) and "row:" not in json.dumps(data["header"])
assert "locator" not in json.dumps(data["warnings"])
assert set(data["checks"]) == {"relations_failed", "soft_relations_failed"}
def test_empty_target_is_null_in_contract(rules: Rules) -> None:
doc = balance(rules, ["Запасы", "1210", "60"], ["Итого II", "1200", "60"], ["Итого I", "1100", "40"])
failed = to_contract(doc)["checks"]["relations_failed"]
target = next(f for f in failed if f["relation"] == "1600 = 1100 + 1200")
assert (target["expected"], target["actual"], target["column_index"]) == (None, "100.00", 2)
def test_no_lines_no_checks_key(rules: Rules) -> None:
doc = normalize_candidate(
ocr([["Итого", "15 000"]], type_hint=DocumentType.BALANCE, header=FULL_HEADER), rules
).document
assert doc is not None and "checks" not in to_contract(doc) and to_contract(doc)["lines"] == []
def test_relation_without_column_index_is_error(rules: Rules) -> None:
doc = balance(rules, ["Запасы", "1210", "60"], ["Итого II", "1200", "60"])
bad = FailedRelation(None, "c1", "1600 = 1700", ("1600", "1700"), D("1"), None)
with pytest.raises(ValueError, match="column_index"):
to_contract(replace(doc, checks=StatementChecks((bad,), ())))
def test_warning_keys(rules: Rules) -> None:
w = make_warning("ROW_SPLIT", "разлеплено", rules, line_refs=("row:3#1", "row:3#2"), locator="file:a.json")
assert warning_to_contract(w) == {
"code": "ROW_SPLIT",
"severity": "info",
"message": "разлеплено",
"line_refs": ["row:3#1", "row:3#2"],
}
lost = make_warning("TABLE_LOST", "таблица", rules, locator="file:a.json;table:1")
assert warning_to_contract(lost, file_level=True) == {
"code": "TABLE_LOST",
"severity": "error",
"message": "таблица",
"locator": "file:a.json;table:1",
}
def test_status_input_roundtrip(rules: Rules) -> None:
doc = balance(rules, ["Запасы", "1210", "60"], ["Итого II", "1200", "60"], ["НИ", "", "7"])
data = status_input_from_contract(json.loads(json.dumps(to_contract(doc), ensure_ascii=False)))
assert data == status_input(doc)
assert document_status(data) is doc.status is DocStatus.NEEDS_CHECK