feat: Ringdiagramm faerbt Legende und Mitte nach Budget
Eingefaerbt war bisher nur die Listen-Darstellung der Ausgaben-Anteile. In der Kreis-Darstellung blieben die Betraege der Legende grau, und die Summe in der Mitte sagte gar nichts ueber den Stand. Jetzt tragen beide die Aussage: gruen im geplanten Rahmen, rot darueber. Faehrt man ein Segment an, zeigt die Mitte dessen Betrag – dann gilt dort das Budget dieser Kategorie, sonst das des Ganzen. Fuer die Mitte liefert der Server jetzt auch das Geplante ueber ALLE Ausgaben-Einheiten, nicht nur ueber die mit Ausgaben: Der Monatsplan umfasst auch, wofuer noch nichts ausgegeben wurde. Ohne Plan bleibt alles, wie es war. Der Donut faerbt nur, wenn ein Segment die Angabe mitbringt – die Budget-Karte, die dieselbe Komponente benutzt, bleibt also unberuehrt. Der Test hat dabei gleich einen Fehler gefunden: ``_units`` ist ein Generator, und ich lief zweimal darueber – beim zweiten Mal war er leer und das Geplante immer 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -164,8 +164,11 @@ def expense_share(
|
||||
planned = budget.effective_planned(db, user, label)
|
||||
by_category = group_by != "group"
|
||||
|
||||
# Als Liste: ``_units`` ist ein Generator, und er wird hier zweimal
|
||||
# gebraucht – beim zweiten Mal waere er leer und das Geplante 0.
|
||||
einheiten = list(_units(_expense_groups(db, user), by_category))
|
||||
rows = []
|
||||
for name, color, ids in _units(_expense_groups(db, user), by_category):
|
||||
for name, color, ids in einheiten:
|
||||
val = sum(actual.get(i, 0) for i in ids)
|
||||
if val > 0:
|
||||
geplant = sum(planned.get(i, 0) for i in ids)
|
||||
@@ -173,9 +176,16 @@ def expense_share(
|
||||
"planned": geplant,
|
||||
"over": geplant > 0 and val > geplant})
|
||||
rows.sort(key=lambda r: r["amount"], reverse=True)
|
||||
|
||||
# Das Geplante ueber ALLE Ausgaben-Einheiten, nicht nur die mit Ausgaben:
|
||||
# Der Monatsplan umfasst auch, wofuer noch nichts ausgegeben wurde.
|
||||
gesamt = sum(r["amount"] for r in rows)
|
||||
gesamt_geplant = sum(planned.get(i, 0) for _, _, ids in einheiten for i in ids)
|
||||
return {
|
||||
"rows": rows,
|
||||
"total": sum(r["amount"] for r in rows),
|
||||
"total": gesamt,
|
||||
"total_planned": gesamt_geplant,
|
||||
"total_over": gesamt_geplant > 0 and gesamt > gesamt_geplant,
|
||||
"currency": base,
|
||||
"label": label,
|
||||
"group_by": "category" if by_category else "group",
|
||||
|
||||
@@ -209,3 +209,9 @@ def test_ausgabenanteile_nennen_das_geplante(admin):
|
||||
|
||||
plane(max(1, ist - 10000))
|
||||
assert zeile()["over"] is True, "ueberschritten"
|
||||
|
||||
# Und die Mitte des Ringdiagramms bekommt dieselbe Grundlage fuer das
|
||||
# Ganze – sonst faerbte sich die Legende, die Summe aber nicht.
|
||||
ganz = admin.get("/api/dashboard/expense-share").json()
|
||||
assert ganz["total_planned"] > 0
|
||||
assert ganz["total_over"] == (ganz["total"] > ganz["total_planned"])
|
||||
|
||||
Reference in New Issue
Block a user