Срез 3b: формы ББ/ОФР в ядре и API до сводной ОСВ #39

Merged
aep merged 36 commits from feat/36-slice-3b-statements-api into main 2026-10-07 14:20:49 +03:00
2 changed files with 17 additions and 12 deletions
Showing only changes of commit 4126a44e0e - Show all commits

View File

@ -188,11 +188,6 @@ def run_checks(
for rule in [*explicit, *sublines]:
if rule not in sublines and rule.target not in amounts:
continue
# Для явных правил (не подстроки): пропустить, если целевой есть, но ни одного члена нет
if rule not in sublines:
term_codes = {code for _, code in rule.terms}
if not any(code in amounts for code in term_codes):
continue
holds, expected, actual = _holds(amounts, rule, rules.tolerance)
if holds:
continue

View File

@ -73,14 +73,24 @@ def test_sublines_soft() -> None:
assert report.failed == ()
def test_per_column_and_null_as_zero() -> None:
report = run_checks(
"BALANCE",
_lines(("1100", {0: "300", 1: None}), ("1200", {0: "600", 1: "5"}), ("1600", {0: "900", 1: "5"})),
[0, 1],
RULES,
def test_target_present_no_terms_hard_failure() -> None:
# Спека: отсутствующий код = 0; если цель присутствует но членов нет, это нарушение
# Правило 1600 = 1100 + 1200, в колонке только 1600=1000 → 1600 ≠ 0, жёсткое нарушение
report = run_checks("BALANCE", _lines(("1600", {0: "1000"})), [0], RULES)
assert any(
item.relation == "1600 = 1100 + 1200" and item.expected == D("1000") and item.actual == D("0")
for item in report.failed
)
def test_target_without_self_sum_hard_failure() -> None:
# Спека: пропуск только если цель отсутствует; если цель есть, правило проверяется
# Правило 1600 = 1700, в колонке только 1600=1000 (нет 1300, 1400, 1500) → нарушение
report = run_checks("BALANCE", _lines(("1600", {0: "1000"})), [0], RULES)
assert any(
item.relation == "1600 = 1700" and item.expected == D("1000") and item.actual == D("0")
for item in report.failed
)
assert report.failed == ()
@pytest.mark.parametrize(