arm-core/api/tests/test_domain_statement_aggregate.py

84 lines
2.9 KiB
Python

"""Агрегат формы по коду (спека `arm-core` v5.19; Review Focus 2)."""
import uuid
from dataclasses import dataclass
from decimal import Decimal
from src.domain.statement_aggregate import AggLine, aggregate_by_code, checks_input
from src.models.enums import StatementLineStatus
C1 = uuid.UUID(int=1)
C2 = uuid.UUID(int=2)
L1, L5 = uuid.UUID(int=101), uuid.UUID(int=105)
def line( # noqa: PLR0913 - поля строки теста
status: str,
code: str | None,
*,
r: int | None,
c1: str | None = None,
c2: str | None = None,
id_: uuid.UUID | None = None,
) -> AggLine:
amounts = {C1: Decimal(c1) if c1 is not None else None, C2: Decimal(c2) if c2 is not None else None}
return AggLine(id_ or uuid.uuid4(), r, StatementLineStatus(status), code, amounts)
def ok(code: str, *, r: int | None, c1: str | None = None, c2: str | None = None, id_: uuid.UUID | None = None):
return line("ok", code, r=r, c1=c1, c2=c2, id_=id_)
def test_repeated_code_sums() -> None:
agg = aggregate_by_code([ok("2410", r=1, c1="100", id_=L1), ok("2410", r=5, c1="649", id_=L5)])
assert agg["2410"].amounts[C1] == Decimal("749") and agg["2410"].line_ids == (L1, L5)
def test_empty_amounts_stay_null() -> None:
assert aggregate_by_code([ok("1110", r=0), ok("1110", r=3)])["1110"].amounts[C1] is None
assert aggregate_by_code([ok("1110", r=0), ok("1110", r=3, c1="5")])["1110"].amounts[C1] == Decimal("5")
def test_non_ok_lines_excluded() -> None:
agg = aggregate_by_code(
[
line("detail", None, r=2, c1="7"),
line("unreadable", None, r=3, c1="9"),
line("missing", None, r=4, c1="1"),
ok("1250", r=5, c1="3"),
]
)
assert list(agg) == ["1250"]
def test_template_line_counts_as_ok() -> None:
agg = aggregate_by_code([ok("1250", r=None, c1="10")])
assert agg["1250"].amounts[C1] == Decimal("10") and agg["1250"].has_source_line is False
def test_codes_ascending_and_template_line_ids_last() -> None:
agg = aggregate_by_code([ok("2400", r=None, id_=L5), ok("1600", r=2), ok("2400", r=7, id_=L1)])
assert list(agg) == ["1600", "2400"] and agg["2400"].line_ids == (L1, L5)
assert agg["2400"].has_source_line is True
def test_reference_name_from_callback() -> None:
agg = aggregate_by_code([ok("1250", r=1)], reference_name=lambda code: f"имя {code}")
assert agg["1250"].reference_name == "имя 1250"
@dataclass
class Col:
id: uuid.UUID
column_index: int
def test_checks_input_skips_empty_template_codes() -> None:
agg = aggregate_by_code(
[ok("1250", r=None), ok("1260", r=None, c1="4"), ok("1270", r=3), ok("1280", r=4, c1="1"), ok("1280", r=None)]
)
indexes, lines = checks_input([Col(C2, 1), Col(C1, 0)], agg)
assert indexes == [0, 1]
assert [code for code, _ in lines] == ["1260", "1270", "1280"]
assert dict(lines)["1260"] == {0: Decimal("4"), 1: None}