import io import json def _konto(admin, **kw): body = {"name": "Giro", "type": "girokonto", "currency": "EUR", "opening_balance_cents": 0} body.update(kw) return admin.post("/api/accounts", json=body).json() def _kategorie(admin): for g in admin.get("/api/categories").json(): for c in g["categories"]: if c["name"] == "Lebensmittel": return c["id"] raise AssertionError("Lebensmittel fehlt") def test_offene_buchungen_listet_nur_unkategorisierte(admin): """Zum Abarbeiten braucht man die Buchungen ohne Kategorie – und zwar nur die.""" konto = _konto(admin, name="Abarbeiten") kat = _kategorie(admin) admin.post("/api/transactions", json={"type": "expense", "date": "2026-04-01", "account_id": konto["id"], "amount_cents": 1000, "payee": "Ohne Kategorie"}) admin.post("/api/transactions", json={"type": "expense", "date": "2026-04-02", "account_id": konto["id"], "amount_cents": 2000, "payee": "Mit Kategorie", "category_id": kat}) admin.post("/api/transactions", json={"type": "income", "date": "2026-04-03", "account_id": konto["id"], "amount_cents": 3000, "payee": "Einnahme ohne Kategorie"}) offen = admin.get("/api/transactions", params={"uncategorized": "true", "account_id": konto["id"]}).json() namen = sorted(t["payee"] for t in offen) assert namen == ["Einnahme ohne Kategorie", "Ohne Kategorie"] def test_offene_buchungen_lassen_uebertraege_aus(admin): """Ein Übertrag ordnet kein Geld ein, er verschiebt es – er gehört nicht auf die Liste.""" a = _konto(admin, name="Von") b = _konto(admin, name="Nach") admin.post("/api/transactions", json={"type": "transfer", "date": "2026-04-04", "account_id": a["id"], "to_account_id": b["id"], "amount_cents": 5000}) offen = admin.get("/api/transactions", params={"uncategorized": "true", "account_id": a["id"]}).json() assert offen == [] def test_verknuepfte_buchungen_sind_nicht_mehr_offen(admin): """Sie gehoeren zu einem Uebertrag und zaehlen in keiner Auswertung. Nach einer Kategorie zu fragen, verlangt Arbeit, die nichts bewirkt.""" import secrets a = admin.post("/api/accounts", json={ "name": f"Offen-A {secrets.token_hex(3)}", "type": "girokonto", "currency": "CHF", "opening_balance_cents": 0}).json() b = admin.post("/api/accounts", json={ "name": f"Offen-B {secrets.token_hex(3)}", "type": "girokonto", "currency": "CHF", "opening_balance_cents": 0}).json() betrag = 20000 + secrets.randbelow(900) raus = admin.post("/api/transactions", json={ "type": "expense", "date": "2026-08-21", "account_id": a["id"], "amount_cents": betrag, "payee": "Umbuchung"}).json() rein = admin.post("/api/transactions", json={ "type": "income", "date": "2026-08-21", "account_id": b["id"], "amount_cents": betrag, "payee": "Umbuchung"}).json() offen = {t["id"] for t in admin.get("/api/transactions", params={"uncategorized": True}).json()} assert raus["id"] in offen and rein["id"] in offen, "vorher beide offen" assert admin.post("/api/uebertraege/verbinden", json={"a_id": raus["id"], "b_id": rein["id"]}).status_code == 200 danach = {t["id"] for t in admin.get("/api/transactions", params={"uncategorized": True}).json()} assert raus["id"] not in danach and rein["id"] not in danach, \ "verknuepfte Buchungen brauchen keine Kategorie mehr"