fix: Test für neutrale Kategorien misst relativ statt absolut
Die Testdatenbank lebt über den ganzen Lauf; im laufenden Monat liegen also schon Buchungen anderer Tests. Absolute Erwartungswerte gingen allein durch, im Gesamtlauf nicht. Jetzt zählt die Differenz vorher/nachher. 93 grün. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,54 +1,69 @@
|
|||||||
"""Kategorien, die nicht in Auswertungen zählen (z. B. „Kontoübertrag").
|
"""Kategorien, die nicht in Auswertungen zählen (z. B. „Kontoübertrag").
|
||||||
|
|
||||||
Eine Umbuchung zwischen eigenen Konten ist keine Ausgabe – das Geld liegt nur
|
Eine Umbuchung zwischen eigenen Konten ist keine Ausgabe – das Geld liegt nur
|
||||||
woanders. Der Kontostand muss sie trotzdem abbilden."""
|
woanders. Der Kontostand muss sie trotzdem abbilden.
|
||||||
|
|
||||||
|
Gemessen wird als Differenz: Die Testdatenbank lebt über den ganzen Lauf, es
|
||||||
|
liegen also schon Buchungen anderer Tests im laufenden Monat."""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
def _account(admin, **kw):
|
|
||||||
body = {"name": "Giro N", "type": "girokonto", "currency": "EUR", "opening_balance_cents": 100000}
|
|
||||||
body.update(kw)
|
|
||||||
return admin.post("/api/accounts", json=body).json()
|
|
||||||
|
|
||||||
|
|
||||||
def _expense_cats(admin, n=2):
|
def _expense_cats(admin, n=2):
|
||||||
out = []
|
out = []
|
||||||
for g in admin.get("/api/categories").json():
|
for g in admin.get("/api/categories").json():
|
||||||
if g["kind"] == "expense":
|
if g["kind"] == "expense":
|
||||||
out += g["categories"]
|
out += g["categories"]
|
||||||
|
assert len(out) >= n
|
||||||
return out[:n]
|
return out[:n]
|
||||||
|
|
||||||
|
|
||||||
def test_neutral_category_out_of_stats_but_in_balance(admin):
|
def _ausgaben(admin):
|
||||||
acc = _account(admin, name="Giro Neutral")
|
return admin.get("/api/dashboard/income-expense").json()["expense"]
|
||||||
normal, uebertrag = _expense_cats(admin, 2)
|
|
||||||
|
|
||||||
# „Kontoübertrag" aus den Auswertungen nehmen.
|
|
||||||
|
def _anteile(admin):
|
||||||
|
d = admin.get("/api/dashboard/expense-share?group_by=category").json()
|
||||||
|
return {r["name"]: r["amount"] for r in d["rows"]}
|
||||||
|
|
||||||
|
|
||||||
|
def test_neutral_category_out_of_stats_but_in_balance(admin):
|
||||||
|
acc = admin.post("/api/accounts", json={
|
||||||
|
"name": "Giro Neutral", "type": "girokonto", "currency": "EUR",
|
||||||
|
"opening_balance_cents": 100000,
|
||||||
|
}).json()
|
||||||
|
normal, uebertrag = _expense_cats(admin, 2)
|
||||||
|
for c in (normal, uebertrag): # definierter Ausgangszustand
|
||||||
|
admin.patch(f"/api/categories/{c['id']}", json={"excluded_from_stats": False})
|
||||||
|
|
||||||
|
vorher_ausgaben = _ausgaben(admin)
|
||||||
|
vorher_anteile = _anteile(admin)
|
||||||
|
|
||||||
|
heute = datetime.date.today().isoformat()
|
||||||
|
for cat, cents in ((normal, 5000), (uebertrag, 30000)):
|
||||||
|
r = admin.post("/api/transactions", json={
|
||||||
|
"type": "expense", "date": heute, "account_id": acc["id"],
|
||||||
|
"amount_cents": cents, "category_id": cat["id"],
|
||||||
|
})
|
||||||
|
assert r.status_code == 201, r.text
|
||||||
|
|
||||||
|
# Beide Buchungen wirken auf den Saldo: 1000.00 - 50.00 - 300.00 = 650.00
|
||||||
|
assert admin.get(f"/api/accounts/{acc['id']}").json()["balance_cents"] == 65000
|
||||||
|
assert _ausgaben(admin) == vorher_ausgaben + 35000
|
||||||
|
|
||||||
|
# Jetzt „Kontoübertrag" aus den Auswertungen nehmen.
|
||||||
r = admin.patch(f"/api/categories/{uebertrag['id']}", json={"excluded_from_stats": True})
|
r = admin.patch(f"/api/categories/{uebertrag['id']}", json={"excluded_from_stats": True})
|
||||||
assert r.status_code == 200, r.text
|
assert r.status_code == 200, r.text
|
||||||
assert r.json()["excluded_from_stats"] is True
|
assert r.json()["excluded_from_stats"] is True
|
||||||
|
|
||||||
heute = datetime.date.today().isoformat()
|
# Nur noch die echte Ausgabe zählt – der Saldo bleibt unverändert.
|
||||||
for cat, cents in ((normal, 5000), (uebertrag, 30000)):
|
assert _ausgaben(admin) == vorher_ausgaben + 5000
|
||||||
admin.post("/api/transactions", json={
|
|
||||||
"type": "expense", "date": heute, "account_id": acc["id"],
|
|
||||||
"amount_cents": cents, "category_id": cat["id"],
|
|
||||||
})
|
|
||||||
|
|
||||||
# Saldo bildet BEIDE Buchungen ab: 1000.00 - 50.00 - 300.00 = 650.00
|
|
||||||
assert admin.get(f"/api/accounts/{acc['id']}").json()["balance_cents"] == 65000
|
assert admin.get(f"/api/accounts/{acc['id']}").json()["balance_cents"] == 65000
|
||||||
|
|
||||||
# Auswertungen kennen nur die echte Ausgabe.
|
jetzt = _anteile(admin)
|
||||||
ie = admin.get("/api/dashboard/income-expense").json()
|
assert jetzt.get(normal["name"], 0) == vorher_anteile.get(normal["name"], 0) + 5000
|
||||||
assert ie["expense"] == 5000, ie
|
assert jetzt.get(uebertrag["name"], 0) == 0, "neutrale Kategorie darf nicht auftauchen"
|
||||||
|
|
||||||
anteile = admin.get("/api/dashboard/expense-share?group_by=category").json()
|
# Häkchen entfernen -> zählt sofort wieder mit.
|
||||||
namen = [r["name"] for r in anteile["rows"]]
|
|
||||||
assert normal["name"] in namen
|
|
||||||
assert uebertrag["name"] not in namen
|
|
||||||
assert anteile["total"] == 5000
|
|
||||||
|
|
||||||
# Häkchen wieder entfernen -> zählt sofort wieder mit.
|
|
||||||
admin.patch(f"/api/categories/{uebertrag['id']}", json={"excluded_from_stats": False})
|
admin.patch(f"/api/categories/{uebertrag['id']}", json={"excluded_from_stats": False})
|
||||||
assert admin.get("/api/dashboard/income-expense").json()["expense"] == 35000
|
assert _ausgaben(admin) == vorher_ausgaben + 35000
|
||||||
|
|||||||
Reference in New Issue
Block a user