from datetime import date, timedelta from decimal import Decimal def _seed_recent_rates(rate: str = "0.95") -> None: from app.database import SessionLocal from app.models import ExchangeRate db = SessionLocal() try: today = date.today() for delta in range(0, 7): day = today - timedelta(days=delta) if db.get(ExchangeRate, (day, "CHF")) is None: db.add(ExchangeRate(date=day, currency="CHF", rate_per_eur=Decimal(rate))) db.commit() finally: db.close() def _mk_account(admin, **kw): body = {"name": "A", "type": "girokonto", "currency": "EUR", "opening_balance_cents": 0} body.update(kw) r = admin.post("/api/accounts", json=body) assert r.status_code == 201, r.text return r.json() def test_starter_categories_present(admin): groups = admin.get("/api/categories").json() assert len(groups) >= 6 names = {c["name"] for g in groups for c in g["categories"]} assert {"Gehalt", "Lebensmittel", "Sparen & Investments"} <= names def test_currency_validation(admin): r = admin.post("/api/accounts", json={"name": "X", "currency": "USD"}) assert r.status_code == 422 def test_identifiers_stored_and_deduped(admin): acc = _mk_account( admin, name="Mit IBAN", identifiers=[ {"kind": "iban", "value": "DE12 3456"}, {"kind": "iban", "value": "de123456"}, # normiert identisch -> dedupliziert {"kind": "card_no", "value": "1234"}, ], ) kinds = sorted((i["kind"], i["value"]) for i in acc["identifiers"]) assert len(acc["identifiers"]) == 2 assert ("card_no", "1234") in kinds def test_balance_and_cross_currency_transfer(admin): _seed_recent_rates("0.95") d = date.today() eur = _mk_account(admin, name="Giro", currency="EUR", opening_balance_cents=100000) chf = _mk_account(admin, name="Spar", type="sparkonto", currency="CHF", opening_balance_cents=0) admin.post("/api/transactions", json={"type": "income", "date": str(d), "account_id": eur["id"], "amount_cents": 50000}) admin.post("/api/transactions", json={"type": "expense", "date": str(d), "account_id": eur["id"], "amount_cents": 20000}) assert admin.get(f"/api/accounts/{eur['id']}").json()["balance_cents"] == 130000 # Transfer 100 EUR -> CHF (0.95) = 95 CHF gutgeschrieben. r = admin.post("/api/transactions", json={ "type": "transfer", "date": str(d), "account_id": eur["id"], "to_account_id": chf["id"], "amount_cents": 10000, }) assert r.status_code == 201, r.text assert r.json()["to_amount_cents"] == 9500 assert admin.get(f"/api/accounts/{eur['id']}").json()["balance_cents"] == 120000 assert admin.get(f"/api/accounts/{chf['id']}").json()["balance_cents"] == 9500 def test_transfer_requires_other_account(admin): eur = _mk_account(admin, name="Solo", currency="EUR") d = date.today() r = admin.post("/api/transactions", json={ "type": "transfer", "date": str(d), "account_id": eur["id"], "to_account_id": eur["id"], "amount_cents": 100, }) assert r.status_code == 400