feat: Konto-Saldo-Anker mit ankerbasierter Saldenrechnung
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
@@ -25,14 +26,23 @@ class AccountOut(AccountIn):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
id: int
|
||||
balance: Decimal = Decimal("0")
|
||||
anchor_date: date | None = None
|
||||
anchor_balance: Decimal | None = None
|
||||
|
||||
|
||||
class AccountPatch(BaseModel):
|
||||
name: str
|
||||
# Alle Felder optional; model_fields_set entscheidet, was tatsaechlich
|
||||
# geaendert wird (Muster wie TransactionPatch.category_id). anchor_date
|
||||
# und anchor_balance muessen gemeinsam gesetzt oder gemeinsam null sein.
|
||||
name: str | None = None
|
||||
anchor_date: date | None = None
|
||||
anchor_balance: Decimal | None = None
|
||||
|
||||
@field_validator("name")
|
||||
@classmethod
|
||||
def name_not_blank(cls, v: str) -> str:
|
||||
def name_not_blank(cls, v: str | None) -> str | None:
|
||||
if v is None:
|
||||
return v
|
||||
v = v.strip()
|
||||
if not v or len(v) > 100:
|
||||
raise ValueError("Name muss 1–100 Zeichen lang sein")
|
||||
@@ -75,7 +85,25 @@ def patch_account(account_id: int, data: AccountPatch, session: Session = Depend
|
||||
acc = session.get(Account, account_id)
|
||||
if acc is None:
|
||||
raise HTTPException(404, "Konto nicht gefunden")
|
||||
acc.name = data.name
|
||||
|
||||
# Validierung zuerst, VOR jeder Mutation - sonst haengt bei einem 422 auf
|
||||
# dem Anker eine bereits geschriebene name-Aenderung im Session-State.
|
||||
fields = data.model_fields_set
|
||||
if "name" in fields and data.name is None:
|
||||
raise HTTPException(422, "Name darf nicht leer sein")
|
||||
|
||||
anchor_fields = {"anchor_date", "anchor_balance"} & fields
|
||||
if anchor_fields and (
|
||||
anchor_fields != {"anchor_date", "anchor_balance"}
|
||||
or (data.anchor_date is None) != (data.anchor_balance is None)):
|
||||
raise HTTPException(422, "Anker braucht Datum und Betrag (oder beide leeren)")
|
||||
|
||||
if "name" in fields:
|
||||
acc.name = data.name
|
||||
if anchor_fields:
|
||||
acc.anchor_date = data.anchor_date
|
||||
acc.anchor_balance = data.anchor_balance
|
||||
|
||||
session.commit()
|
||||
session.refresh(acc)
|
||||
item = AccountOut.model_validate(acc)
|
||||
|
||||
Reference in New Issue
Block a user