fix: Anfangssaldo gilt ab dem Stichtag
Der Stichtag eines Kontos wurde gespeichert und angezeigt, von der Saldo-Berechnung aber ignoriert: sie addierte jede Buchung des Kontos, auch die aus der Zeit vor dem Stichtag. Damit lief jeder Saldo um die gesamte Vorgeschichte daneben. Der Anfangssaldo beschreibt jetzt den Stand am ENDE des Stichtags – so steht er auf dem Auszug. Buchungen bis einschliesslich dieses Tages zaehlen nicht mehr zum Kontostand, bleiben aber in Liste und Auswertungen. Beim Uebertrag wird jede Seite an ihrem eigenen Stichtag gemessen; der Vermoegensverlauf folgt derselben Regel. Ohne Stichtag zaehlt weiterhin alles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Kontostände (in Kontowährung) und Umrechnung in die Hauptwährung.
|
||||
|
||||
Saldo = Anfangssaldo + Einnahmen - Ausgaben - Transfers-raus + Transfers-rein.
|
||||
Saldo = Anfangssaldo + Einnahmen - Ausgaben - Transfers-raus + Transfers-rein,
|
||||
gezählt ab dem Stichtag des Kontos (siehe ``counts_after_opening``).
|
||||
Transfers werden in der jeweiligen Kontowährung verrechnet (bei währungsüber-
|
||||
greifenden Transfers am Zielkonto der gutgeschriebene Betrag ``to_amount_cents``).
|
||||
"""
|
||||
@@ -18,28 +19,44 @@ def _sum(query) -> int:
|
||||
return int(query.scalar() or 0)
|
||||
|
||||
|
||||
def counts_after_opening(account: Account):
|
||||
"""Bedingung, die Buchungen bis zum Stichtag ausschliesst.
|
||||
|
||||
Der Anfangssaldo beschreibt den Stand *am Ende* des Stichtags – so steht er
|
||||
auf jedem Auszug und im E-Banking. Buchungen bis einschliesslich dieses Tages
|
||||
stecken also schon darin und dürfen nicht noch einmal zählen. Sie bleiben in
|
||||
der Liste und in den Auswertungen, nur der Kontostand lässt sie aus.
|
||||
Ohne Stichtag zählt alles – dann ist der Anfangssaldo der Stand von Beginn an.
|
||||
"""
|
||||
if account.opening_date is None:
|
||||
return None
|
||||
return Transaction.date > account.opening_date
|
||||
|
||||
|
||||
def account_balance_cents(db: Session, account: Account) -> int:
|
||||
income = _sum(
|
||||
db.query(func.sum(Transaction.amount_cents)).filter(
|
||||
Transaction.account_id == account.id, Transaction.type == TxnType.income
|
||||
)
|
||||
ab = counts_after_opening(account)
|
||||
|
||||
def summe(spalte, *bedingungen) -> int:
|
||||
query = db.query(func.sum(spalte)).filter(*bedingungen)
|
||||
if ab is not None:
|
||||
query = query.filter(ab)
|
||||
return _sum(query)
|
||||
|
||||
income = summe(
|
||||
Transaction.amount_cents,
|
||||
Transaction.account_id == account.id, Transaction.type == TxnType.income,
|
||||
)
|
||||
expense = _sum(
|
||||
db.query(func.sum(Transaction.amount_cents)).filter(
|
||||
Transaction.account_id == account.id, Transaction.type == TxnType.expense
|
||||
)
|
||||
expense = summe(
|
||||
Transaction.amount_cents,
|
||||
Transaction.account_id == account.id, Transaction.type == TxnType.expense,
|
||||
)
|
||||
transfer_out = _sum(
|
||||
db.query(func.sum(Transaction.amount_cents)).filter(
|
||||
Transaction.account_id == account.id, Transaction.type == TxnType.transfer
|
||||
)
|
||||
transfer_out = summe(
|
||||
Transaction.amount_cents,
|
||||
Transaction.account_id == account.id, Transaction.type == TxnType.transfer,
|
||||
)
|
||||
transfer_in = _sum(
|
||||
db.query(
|
||||
func.sum(func.coalesce(Transaction.to_amount_cents, Transaction.amount_cents))
|
||||
).filter(
|
||||
Transaction.to_account_id == account.id, Transaction.type == TxnType.transfer
|
||||
)
|
||||
transfer_in = summe(
|
||||
func.coalesce(Transaction.to_amount_cents, Transaction.amount_cents),
|
||||
Transaction.to_account_id == account.id, Transaction.type == TxnType.transfer,
|
||||
)
|
||||
return account.opening_balance_cents + income - expense - transfer_out + transfer_in
|
||||
|
||||
|
||||
Reference in New Issue
Block a user