fix: Eine berechnete Budget-Zeile ueberlebt jetzt das Kopieren

Beide Kopierwege uebernahmen nur planned_cents. Ein Eintrag der Betriebsart
"berechnet" fiel dabei still auf "fest" zurueck - mit der Zahl, die zufaellig
zuletzt in planned_cents stand. Der Bezug zu den Vertraegen war danach weg,
ohne dass irgendwo stand, dass er weg ist.

Vorlage -> Monat (copy_template_to_month) zieht jetzt nach, was
ensure_customized nebenan laengst richtig macht. Monat -> Vorlage
(copy_month_to_template) nimmt die Betriebsart mit, statt die gerade
herauskommende Zahl einzufrieren: Eine berechnete Zeile soll auch in der
Vorlage berechnet bleiben.

Dabei aufgefallen: Eine berechnete Zeile gehoert auch dann in die Vorlage,
wenn planned_cents null ist - ihre Zahl steht in den Vertraegen. Eine feste
Null bleibt dagegen draussen, sonst fuellte sich die Vorlage mit Nullzeilen
fuer jede je beruehrte Kategorie.

Das war Backend-Ergaenzung D und damit die letzte offene.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-10-21 21:04:46 +02:00
co-authored by Claude Opus 5
parent 37b29934ef
commit 4c61a02c53
2 changed files with 90 additions and 7 deletions
+27 -7
View File
@@ -217,13 +217,27 @@ def reset_month(db: Session, user: User, label: str) -> None:
def copy_month_to_template(db: Session, user: User, label: str) -> None:
"""Setzt die Standard-Vorlage auf die wirksamen Soll-Werte dieses Monats
(„diesen Monat als Standard festlegen"). Einnahmen bleiben unberührt."""
planned = effective_planned(db, user, label) # {category_id: cents}
"""Setzt die Standard-Vorlage auf die Soll-Werte dieses Monats
(„diesen Monat als Standard festlegen"). Einnahmen bleiben unberührt.
Übernommen wird die **Betriebsart**, nicht die gerade herauskommende Zahl:
Eine berechnete Zeile soll auch in der Vorlage berechnet bleiben. Vorher
fror dieser Weg den Monatswert als festen Betrag ein – der Bezug zu den
Verträgen war danach still weg, und niemand sah, wo er geblieben war.
"""
zeilen = list(_zeilen(db, user, label))
db.query(BudgetTemplateLine).filter(BudgetTemplateLine.owner_id == user.id).delete()
for category_id, cents in planned.items():
if cents > 0:
db.add(BudgetTemplateLine(owner_id=user.id, category_id=category_id, planned_cents=cents))
for zeile in zeilen:
# Eine feste Null ist nichts Geplantes und gehört nicht in die Vorlage.
# Eine berechnete Zeile dagegen schon: Ihre Zahl steht in den
# Verträgen, nicht in planned_cents.
if zeile.modus != "berechnet" and zeile.planned_cents <= 0:
continue
db.add(BudgetTemplateLine(
owner_id=user.id, category_id=zeile.category_id,
planned_cents=zeile.planned_cents, modus=zeile.modus,
zuschlag_cents=zeile.zuschlag_cents,
))
db.commit()
@@ -241,7 +255,13 @@ def copy_template_to_month(db: Session, user: User, label: str) -> BudgetPeriod:
db.flush()
period.customized = True
for tl in db.query(BudgetTemplateLine).filter(BudgetTemplateLine.owner_id == user.id):
period.lines.append(BudgetPeriodLine(category_id=tl.category_id, planned_cents=tl.planned_cents))
period.lines.append(BudgetPeriodLine(
category_id=tl.category_id, planned_cents=tl.planned_cents,
# Wie in ``ensure_customized``: Ohne diese beiden fiele eine
# berechnete Zeile auf „fest" zurueck, mit der Zahl, die zufaellig
# zuletzt in planned_cents stand.
modus=tl.modus, zuschlag_cents=tl.zuschlag_cents,
))
db.commit()
return period