feat: Kontostand aufschluesseln – und der Angleich-Knopf bleibt
Zwei Sachen aus derselben Wurzel: Wenn ein Saldo nicht stimmt, sieht man nicht, warum, und kann auch nichts dagegen tun. Ein Klick auf den Kontostand zeigt jetzt die Rechnung: Anfangsbestand, Einnahmen, Ausgaben, Uebertraege raus und rein – jeweils mit der Anzahl der Buchungen – und was daraus wird. Darunter der Saldo der Bank und, einzeln aufgefuehrt, alle Uebertraege des Kontos. Genau die sind die haeufigste Ursache und in einer langen Buchungsliste am schwersten zu ueberblicken. Rechnung und Kontenliste kommen aus EINER Quelle: ``account_balance_cents`` liest jetzt aus der Aufschluesselung. Sonst koennte die Anzeige etwas anderes behaupten als der Saldo, und man suchte den Fehler im Falschen. Ausserdem war der Knopf "Saldo der Bank uebernehmen" verschwunden, sobald die Bank nur einen verfuegbaren Saldo meldet. Das war zu weit gedacht: Nicht vergleichbar heisst nicht, dass man nicht angleichen duerfte. Der Knopf ist zurueck, und die Nachfrage sagt in dem Fall, worauf man sich einlaesst – der verfuegbare Saldo enthaelt Vorgemerktes, das spaeter noch als Buchung kommt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -241,6 +241,54 @@ def _entkoppele_uebertraege(db: Session, acc: Account) -> None:
|
||||
db.flush()
|
||||
|
||||
|
||||
@router.get("/{account_id}/aufschluesselung")
|
||||
def balance_breakdown(account_id: int, db: Session = Depends(get_db),
|
||||
user: User = Depends(get_current_user)) -> dict:
|
||||
"""Woraus sich der Saldo zusammensetzt – samt aller Übertrags-Beine.
|
||||
|
||||
Stimmt ein Kontostand nicht, liegt es fast immer an einer dieser Zahlen
|
||||
oder an einem Übertrag, der zu viel oder zu wenig verschiebt. Ohne diese
|
||||
Ansicht sucht man in einer langen Buchungsliste; mit ihr sieht man sofort,
|
||||
welcher Teil nicht passt.
|
||||
"""
|
||||
konto = get_owned(db, Account, account_id, user)
|
||||
teile = balances.aufschluesselung(db, konto)
|
||||
namen = {a.id: a.name for a in db.query(Account).filter(Account.owner_id == user.id)}
|
||||
|
||||
# Die Übertrags-Beine einzeln: Sie sind der Teil, den man in der Liste am
|
||||
# schwersten überblickt, und die haeufigste Ursache.
|
||||
beine = [
|
||||
{"id": t.id, "datum": t.date.isoformat(),
|
||||
"von": namen.get(t.account_id, "?"), "nach": namen.get(t.to_account_id, "?"),
|
||||
"raus": t.account_id == konto.id,
|
||||
"cents": (t.amount_cents if t.account_id == konto.id
|
||||
else (t.to_amount_cents or t.amount_cents)),
|
||||
"text": t.payee or t.description}
|
||||
for t in db.query(Transaction).filter(
|
||||
Transaction.owner_id == user.id,
|
||||
Transaction.type == TxnType.transfer,
|
||||
(Transaction.account_id == konto.id) | (Transaction.to_account_id == konto.id),
|
||||
).order_by(Transaction.date.desc(), Transaction.id.desc()).limit(50)
|
||||
]
|
||||
verknuepfung = (
|
||||
db.query(BankAccountLink)
|
||||
.filter(BankAccountLink.owner_id == user.id,
|
||||
BankAccountLink.account_id == konto.id)
|
||||
.first()
|
||||
)
|
||||
return {
|
||||
"waehrung": konto.currency,
|
||||
"teile": teile,
|
||||
"uebertraege": beine,
|
||||
"bank": {
|
||||
"cents": verknuepfung.balance_cents if verknuepfung else None,
|
||||
"art": verknuepfung.balance_type if verknuepfung else None,
|
||||
"vergleichbar": (bank_sync.saldo_vergleichbar(verknuepfung.balance_type)
|
||||
if verknuepfung else False),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@router.post("/{account_id}/saldo-uebernehmen", response_model=AccountOut)
|
||||
def adopt_bank_balance(account_id: int, db: Session = Depends(get_db),
|
||||
user: User = Depends(get_current_user)):
|
||||
|
||||
Reference in New Issue
Block a user