"""Geld, an das man nicht herankommt. Eine Saeule 3a ist gesperrt bis zur Rente, zur Selbstaendigkeit oder zur Auswanderung. Sie in dieselbe Summe zu werfen wie das Girokonto beantwortet eine andere Frage, als der Nutzer stellt. Der Unterschied, um den es geht: VERMOEGEN bleibt es – VERFUEGBAR ist es nicht. """ import json from datetime import date def _konto(admin, name, **kw): body = {"name": name, "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_gebunden_wird_gespeichert_und_laesst_sich_loesen(admin): konto = _konto(admin, "Saeule 3a", type="depot", is_locked=True, opening_balance_cents=200461) assert konto["is_locked"] is True r = admin.patch(f"/api/accounts/{konto['id']}", json={"is_locked": False}) assert r.json()["is_locked"] is False, "ausgewandert – jetzt kommt man dran" r = admin.patch(f"/api/accounts/{konto['id']}", json={"name": "Saeule 3a ZKB"}) assert r.json()["is_locked"] is False, "ein Namenswechsel aendert nichts daran" def test_neue_konten_sind_nicht_gebunden(admin): assert _konto(admin, "Ganz normal")["is_locked"] is False def test_gebundenes_geld_faellt_aus_der_verfuegbaren_summe(admin): """Der Punkt der ganzen Sache.""" vorher = admin.get("/api/dashboard/balances").json() _konto(admin, "Giro Verfuegbar", opening_balance_cents=300000) _konto(admin, "Saeule 3a Gesperrt", type="depot", is_locked=True, opening_balance_cents=200461) jetzt = admin.get("/api/dashboard/balances").json() assert jetzt["total"] == vorher["total"] + 300000, "nur das Freie zaehlt" assert jetzt["gebunden"] == vorher.get("gebunden", 0) + 200461 gesperrt = [a for a in jetzt["accounts"] if a["name"] == "Saeule 3a Gesperrt"][0] assert gesperrt["locked"] is True assert gesperrt["balance_base_cents"] == 200461, "der Saldo bleibt, was er ist" def test_gebundenes_geld_bleibt_vermoegen(admin): """Der Unterschied, auf den es ankommt. Es nicht ausgeben zu koennen heisst nicht, es nicht zu besitzen. Der Vermoegensverlauf und das Nettovermoegen rechnen es weiter mit – nur die Summe, die „wie viel habe ich zur Verfuegung" beantwortet, laesst es weg. """ from app.database import SessionLocal from app.models import Account, User from app.services import balances def vermoegen() -> int: db = SessionLocal() try: user = db.query(User).filter(User.username == "admin").one() konten = db.query(Account).filter(Account.owner_id == user.id).all() return balances.net_worth_cents(db, konten, "EUR", date.today()) finally: db.close() vorher = vermoegen() _konto(admin, "Saeule 3a Vermoegen", type="depot", is_locked=True, opening_balance_cents=200461) assert vermoegen() == vorher + 200461 def test_archiviertes_gebundenes_konto_zaehlt_nirgends(admin): konto = _konto(admin, "Alte Saeule", type="depot", is_locked=True, opening_balance_cents=50000) vorher = admin.get("/api/dashboard/balances").json() admin.patch(f"/api/accounts/{konto['id']}", json={"is_archived": True}) jetzt = admin.get("/api/dashboard/balances").json() assert jetzt["total"] == vorher["total"] assert jetzt["gebunden"] == vorher["gebunden"] - 50000 def test_gebunden_ueberlebt_das_backup(admin): konto = _konto(admin, "Saeule 3a Backup", type="depot", is_locked=True, opening_balance_cents=123456) daten = json.loads(admin.get("/api/export/backup.json").content) gesichert = [a for a in daten["data"]["accounts"] if a["name"] == "Saeule 3a Backup"] assert gesichert and gesichert[0]["is_locked"] in (True, 1) admin.delete(f"/api/accounts/{konto['id']}") r = admin.post( "/api/backup/restore", files={"file": ("backup.json", json.dumps(daten).encode("utf-8"), "application/json")}, data={"mode": "replace"}, ) assert r.status_code == 200, r.text zurueck = [a for a in admin.get("/api/accounts").json() if a["name"] == "Saeule 3a Backup"] assert zurueck and zurueck[0]["is_locked"] is True