Files
certain/backend/tests/test_neutral_category.py
T
GuidoandClaude Opus 4.8 5c8b53a995 feat: Kategorien aus Auswertungen ausnehmen (z. B. „Kontoübertrag")
Umbuchungen zwischen eigenen Konten sind keine Ausgabe – das Geld ist nicht weg,
es liegt woanders. Bisher blieb nur die Wahl zwischen einer echten Transfer-
Buchung (bildet die Wirklichkeit ab, braucht aber auf beiden Seiten passende
Regeln und schätzt bei Fremdwährung den Gegenwert) oder einer gewöhnlichen
Ausgabe, die Budget und Statistik verfälscht.

Kategorien haben jetzt den Schalter „Nicht in Auswertungen einrechnen": Die
Buchung wirkt weiter auf den Kontostand, bleibt aber aus Budget, Dashboard und
Auswertungen heraus. Gefiltert wird zentral in actual_expense_by_category und
income_by_category – damit greift es zugleich für Budget-Donut, Budget-
Fortschritt, Einnahmen/Ausgaben, Ausgaben-Anteile und die Budget-Seite.

Das ersetzt die Transfer-Paarung nicht, es ist der einfachere Weg: kein
Gegenkonto, keine Kursschätzung, dafür ohne Verbindung zwischen den beiden Seiten.

Migration 0013, Schalter im Kategorie-Dialog, Kennzeichnung in der Liste, Test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-21 10:17:20 +02:00

55 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Kategorien, die nicht in Auswertungen zählen (z. B. „Kontoübertrag").
Eine Umbuchung zwischen eigenen Konten ist keine Ausgabe – das Geld liegt nur
woanders. Der Kontostand muss sie trotzdem abbilden."""
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):
out = []
for g in admin.get("/api/categories").json():
if g["kind"] == "expense":
out += g["categories"]
return out[:n]
def test_neutral_category_out_of_stats_but_in_balance(admin):
acc = _account(admin, name="Giro Neutral")
normal, uebertrag = _expense_cats(admin, 2)
# „Kontoübertrag" aus den Auswertungen nehmen.
r = admin.patch(f"/api/categories/{uebertrag['id']}", json={"excluded_from_stats": True})
assert r.status_code == 200, r.text
assert r.json()["excluded_from_stats"] is True
heute = datetime.date.today().isoformat()
for cat, cents in ((normal, 5000), (uebertrag, 30000)):
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
# Auswertungen kennen nur die echte Ausgabe.
ie = admin.get("/api/dashboard/income-expense").json()
assert ie["expense"] == 5000, ie
anteile = admin.get("/api/dashboard/expense-share?group_by=category").json()
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})
assert admin.get("/api/dashboard/income-expense").json()["expense"] == 35000