SPB Git

spb/air Public MIT

AIR — The Language of Accounting.

Python 100%
5.1 KB · 131 lines python
Raw Blame History
1# =============================================================================2# Projet : AIR — Accounting Intermediate Representation3# Auteur : Simon-Pierre Boucher4# Contact : contact@spboucher.ai5# Fichier : test_optimize.py6# Description : Tests — optimization passes: fusion, netting, duplicate detection.7# =============================================================================8"""Optimization pass tests (Phase 6).910The invariant is verified after every optimization pass by the pass manager;11these tests check the transformations themselves and their provenance."""12from __future__ import annotations1314from datetime import date15from decimal import Decimal16from pathlib import Path1718from aic.compiler import compile_document19from alsl.loader import load_policy_set20from core.events import AirDocument2122ROOT = Path(__file__).resolve().parents[1]23POLICIES = load_policy_set(ROOT / "alsl" / "policies" / "ca-qc-2026.yaml")242526def _doc(*events: dict) -> AirDocument:27    return AirDocument.model_validate({"events": list(events)})282930def _payment(i: int, amount: str = "125.00") -> dict:31    return {32        "id": f"evt_pay_{i:03d}", "type": "PaymentReceived",33        "date": date(2026, 3, 15), "description": f"payout {i}",34        "amount": {"amount": amount, "currency": "CAD"},35    }363738# --- fusion --------------------------------------------------------------------39def test_fusion_batches_identical_payments() -> None:40    document = _doc(*[_payment(i) for i in range(50)])41    journal, diags = compile_document(document, POLICIES, optimize=True)4243    (batch,) = journal.entries44    assert batch.id.startswith("je_batch_")45    assert batch.description == "Batch: 50 x PaymentReceived"46    debit = next(l for l in batch.lines if l.side.value == "debit")47    assert debit.amount.amount == Decimal("125.00") * 50   # 6250.004849    # traceability survives fusion: the batch line derives from all 50 originals50    assert debit.provenance_id is not None51    node = journal.provenance.get(debit.provenance_id)52    assert node.kind == "fusion" and len(node.inputs) == 505354    assert any(d.code == "AIR-N800" for d in diags)555657def test_fusion_keeps_different_days_apart() -> None:58    events = [_payment(1), {**_payment(2), "date": date(2026, 3, 16)}]59    journal, _ = compile_document(_doc(*events), POLICIES, optimize=True)60    assert len(journal.entries) == 2       # nothing to fuse across dates616263def test_default_pipeline_never_fuses() -> None:64    document = _doc(*[_payment(i) for i in range(5)])65    journal, _ = compile_document(document, POLICIES)      # optimize off66    assert len(journal.entries) == 5676869# --- netting --------------------------------------------------------------------70SALE = {71    "id": "evt_net_sale", "type": "Sale", "date": date(2026, 3, 1),72    "amount": {"amount": "1000.00", "currency": "CAD"},73    "tax": {"jurisdiction": "CA-QC"},74}757677def _refund(amount: str) -> dict:78    return {79        "id": "evt_net_refund", "type": "Refund", "date": date(2026, 3, 5),80        "related_event": "evt_net_sale",81        "amount": {"amount": amount, "currency": "CAD"},82        "tax": {"jurisdiction": "CA-QC"},83    }848586def test_partial_refund_nets_into_one_entry() -> None:87    journal, diags = compile_document(88        _doc(SALE, _refund("250.00")), POLICIES, optimize=True)8990    (entry,) = journal.entries91    assert entry.id == "je_net_evt_net_sale"92    amounts = {(l.account.code, l.side.value): str(l.amount.amount)93               for l in entry.lines}94    assert amounts[("4000", "credit")] == "750.00"    # 1000 - 25095    assert amounts[("2310", "credit")] == "37.50"     # 50.00 - 12.5096    assert amounts[("2320", "credit")] == "74.81"     # 99.75 - 24.9497    assert amounts[("1100", "debit")] == "862.31"     # balances98    assert any(d.code == "AIR-N801" for d in diags)99100101def test_full_refund_nets_to_nothing() -> None:102    journal, diags = compile_document(103        _doc(SALE, _refund("1000.00")), POLICIES, optimize=True)104    assert journal.entries == []105    note = next(d for d in diags if d.code == "AIR-N801")106    assert "fully offset" in note.message107108109def test_refund_exceeding_sale_is_left_alone() -> None:110    journal, _ = compile_document(111        _doc(SALE, _refund("1500.00")), POLICIES, optimize=True)112    assert len(journal.entries) == 2       # not nettable; both entries stay113114115# --- duplicate detection -------------------------------------------------------------116def test_identical_content_different_ids_warns() -> None:117    twin_a = {**SALE, "id": "evt_dup_a"}118    twin_b = {**SALE, "id": "evt_dup_b"}119    journal, diags = compile_document(_doc(twin_a, twin_b), POLICIES,120                                      optimize=True)121    warning = next(d for d in diags if d.code == "AIR-W800")122    assert "evt_dup_a" in warning.message and "evt_dup_b" in warning.message123    assert len(journal.entries) == 2       # nothing dropped — a human decides124125126def test_distinct_descriptions_are_not_duplicates() -> None:127    a = {**SALE, "id": "evt_a", "description": "invoice 1"}128    b = {**SALE, "id": "evt_b", "description": "invoice 2"}129    _, diags = compile_document(_doc(a, b), POLICIES, optimize=True)130    assert not any(d.code == "AIR-W800" for d in diags)131