feat: Budget – mehrere Monate nebeneinander + Kopieren Monat<->Vorlage

- Umschalter 1·2·3: Monate nebeneinander (responsives Raster, auf schmalem
  Schirm gestapelt); prev/next verschiebt das ganze Fenster
- Je Monat: „Als Standard festlegen" (Monat -> Vorlage) und „Standard
  übernehmen" (Vorlage -> Monat, überschreibt), plus Zurücksetzen
- Backend: copy_month_to_template / copy_template_to_month + Endpunkte
  POST /budget/template/from-month/{label} und /budget/{label}/from-template
- Test fürs Kopieren; globale .grow-Utility ergänzt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-20 17:07:49 +02:00
co-authored by Claude Opus 4.8
parent 8d0fbdfe2b
commit 49b927e2eb
8 changed files with 262 additions and 81 deletions
+24
View File
@@ -83,6 +83,30 @@ def test_budget_soll_ist_and_override(admin):
assert v["customized"] is False
def test_budget_copy_month_and_template(admin):
admin.put("/api/settings/budget_start_day", params={"value": "1"})
today = date.today()
label = f"{today.year:04d}-{today.month:02d}"
leb = _lebensmittel(admin)
admin.put(f"/api/budget/template/category/{leb}", params={"planned_cents": 50000})
# Monat individuell auf 700.
admin.put(f"/api/budget/{label}/category/{leb}", params={"planned_cents": 70000})
# Monat -> Vorlage: Vorlage übernimmt den 700er Wert.
r = admin.post(f"/api/budget/template/from-month/{label}")
assert r.status_code == 200, r.text
tpl = r.json()
assert next(l for l in tpl["lines"] if l["category_id"] == leb)["planned_cents"] == 70000
# Vorlage auf 900 ändern, dann Vorlage -> Monat (überschreibt den angepassten Monat).
admin.put(f"/api/budget/template/category/{leb}", params={"planned_cents": 90000})
v = admin.post(f"/api/budget/{label}/from-template").json()
row = next(c for g in v["groups"] for c in g["categories"] if c["category_id"] == leb)
assert row["planned_cents"] == 90000
assert v["customized"] is True
def test_planned_income(admin):
admin.put("/api/settings/budget_start_day", params={"value": "1"})
today = date.today()