from decimal import Decimal H = {"Authorization": "Bearer test-key"} KREDIT = {"name": "Auto", "principal": "1200.00", "annual_rate_pct": "0", "term_months": 12, "payout_date": "2026-01-15", "repayment_type": "annuity"} POSTEN = {"name": "Rate Auto", "amount": "-100.00", "rhythm": "monthly", "due_day": 15} def _count(client, path): return len(client.get(path, headers=H).json()) def test_posten_zu_bestehendem_kredit_409(client): assert client.post("/api/loans", headers=H, json=KREDIT).status_code == 201 r = client.post("/api/recurring", headers=H, json=POSTEN) assert r.status_code == 409 d = r.json()["detail"] assert d["code"] == "doppelzaehlung_kredit" assert "doppelt" in d["meldung"] assert d["konflikte"] == [{"posten": "Rate Auto", "posten_betrag": "-100.00", "kredit": "Auto", "kredit_rate": "100.00"}] assert _count(client, "/api/recurring") == 0 def test_posten_mit_bestaetigung_gespeichert(client): client.post("/api/loans", headers=H, json=KREDIT) r = client.post("/api/recurring", headers=H, json={**POSTEN, "doppelzaehlung_bestaetigt": True}) assert r.status_code == 201 assert "doppelzaehlung_bestaetigt" not in r.json() assert _count(client, "/api/recurring") == 1 def test_kredit_zu_bestehendem_posten_409_und_bestaetigung(client): client.post("/api/recurring", headers=H, json=POSTEN) r = client.post("/api/loans", headers=H, json=KREDIT) assert r.status_code == 409 assert r.json()["detail"]["konflikte"][0]["posten"] == "Rate Auto" assert _count(client, "/api/loans") == 0 r = client.post("/api/loans", headers=H, json={**KREDIT, "doppelzaehlung_bestaetigt": True}) assert r.status_code == 201 assert "doppelzaehlung_bestaetigt" not in r.json() def test_ohne_konflikt_unveraendert(client): client.post("/api/loans", headers=H, json=KREDIT) r = client.post("/api/recurring", headers=H, json={**POSTEN, "amount": "-50.00"}) assert r.status_code == 201 def test_patch_posten_erzeugt_konflikt_409_ohne_aenderung(client): client.post("/api/loans", headers=H, json=KREDIT) item = client.post("/api/recurring", headers=H, json={**POSTEN, "amount": "-50.00"}).json() r = client.patch(f"/api/recurring/{item['id']}", headers=H, json={"amount": "-100.00"}) assert r.status_code == 409 stored = client.get("/api/recurring", headers=H).json()[0] assert Decimal(stored["amount"]) == Decimal("-50.00") r = client.patch(f"/api/recurring/{item['id']}", headers=H, json={"amount": "-100.00", "doppelzaehlung_bestaetigt": True}) assert r.status_code == 200 assert Decimal(r.json()["amount"]) == Decimal("-100.00") def test_patch_nur_name_bei_bestehendem_konflikt_ohne_flag(client): client.post("/api/loans", headers=H, json=KREDIT) item = client.post("/api/recurring", headers=H, json={**POSTEN, "doppelzaehlung_bestaetigt": True}).json() r = client.patch(f"/api/recurring/{item['id']}", headers=H, json={"name": "Rate Auto neu"}) assert r.status_code == 200 loan = client.get("/api/loans", headers=H).json()[0] r = client.patch(f"/api/loans/{loan['id']}", headers=H, json={"name": "Auto neu"}) assert r.status_code == 200 def test_patch_kredit_erzeugt_konflikt_409(client): client.post("/api/recurring", headers=H, json=POSTEN) loan = client.post("/api/loans", headers=H, json={**KREDIT, "principal": "2400.00"}).json() r = client.patch(f"/api/loans/{loan['id']}", headers=H, json={"principal": "1200.00"}) assert r.status_code == 409 assert Decimal(client.get("/api/loans", headers=H).json()[0]["principal"]) == Decimal("2400.00") r = client.patch(f"/api/loans/{loan['id']}", headers=H, json={"principal": "1200.00", "doppelzaehlung_bestaetigt": True}) assert r.status_code == 200 def test_vorschlag_uebernehmen_nutzt_denselben_endpunkt(client): # „Vorschlag übernehmen" sendet dieselben Felder (inkl. start_date/category_id=null). client.post("/api/loans", headers=H, json=KREDIT) r = client.post("/api/recurring", headers=H, json={ **POSTEN, "start_date": None, "category_id": None}) assert r.status_code == 409