Files
bin/finance/tests/test_loans.py
T
rdmsandClaude Haiku 4.5 80b8b369c7 refactor: Tilgungsplan-Helfer schedule_for, Kredit-Laufzeit 1–1200 Monate (A14-T5)
- Neuer schedule_for() in app/engine/loans.py: vereinheitlicht Tilgungsplan-Erstellung
- Laufzeit-Validierung in LoanIn und LoanPatch: 1–1200 Monate
- Aufrufstellen aktualisiert (routers/planning.py, services/breakdown.py,
  services/projection_service.py, services/planning_chart.py)
- Keine direkten loan_schedule(Decimal(...)) Aufrufe außerhalb engine/loans.py mehr
- Tests für schedule_for und Laufzeit-Grenzen (1, 1200, sowie 0/-5/1201 Ablehnung)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-30 13:10:55 +02:00

48 lines
1.8 KiB
Python

from datetime import date
from decimal import Decimal
from app.engine.loans import add_months, annuity_payment, loan_schedule
def test_add_months_clamps_month_end():
assert add_months(date(2026, 1, 31), 1) == date(2026, 2, 28)
def test_annuity_payment():
# 10.000 EUR, 6 % p.a., 48 Monate -> 234,85 EUR Monatsrate
assert annuity_payment(Decimal("10000"), Decimal("6"), 48) == Decimal("234.85")
def test_annuity_schedule_amortizes_fully():
plan = loan_schedule(Decimal("10000"), Decimal("6"), 48, date(2026, 8, 1), "annuity")
assert len(plan) == 48
assert plan[-1].remaining == Decimal("0.00")
assert plan[0].due == date(2026, 9, 1)
assert plan[0].interest == Decimal("50.00") # 10000 * 0,5 %
assert plan[0].payment < 0
def test_bullet_loan():
plan = loan_schedule(Decimal("10000"), Decimal("6"), 12, date(2026, 8, 1), "bullet")
assert all(i.principal == 0 for i in plan[:-1])
assert plan[-1].principal == Decimal("10000")
assert plan[-1].remaining == Decimal("0.00")
def test_schedule_for_entspricht_loan_schedule():
from types import SimpleNamespace
from app.engine.loans import schedule_for
kredit = SimpleNamespace(principal="1200.00", annual_rate_pct="3.00", term_months=12,
payout_date=date(2030, 1, 31), repayment_type="annuity")
assert schedule_for(kredit) == loan_schedule(Decimal("1200.00"), Decimal("3.00"), 12,
date(2030, 1, 31), "annuity")
def test_keine_manuelle_tilgungsplan_konvertierung_mehr():
from pathlib import Path
app_dir = Path(__file__).resolve().parent.parent / "app"
engine_loans = app_dir / "engine" / "loans.py"
treffer = [str(p.relative_to(app_dir)) for p in app_dir.rglob("*.py")
if p != engine_loans and "loan_schedule(Decimal(" in p.read_text()]
assert treffer == []