- Anmeldung über Argon2id und JWT in httpOnly-Cookies, Refresh mit echter Rotation über die neue Tabelle refresh_token - AuthProvider-Protokoll als Vorbereitung für OIDC, Administrator-Anlage beim Erststart mit erzwungenem Passwortwechsel - CRUD für Konten, Kategorien (zweistufiger Baum), Firmen, Recurrences, Preisversionen, Buchungen, Budgets, Vorlagen und Sparziele - Fälligkeiten mit Overlay-Logik: abrufen, bestätigen, auslassen, zurücksetzen - Kontosalden zum Stichtag, Monatsübersicht mit Plan-Ist-Vergleich - SECRET_KEY jetzt mindestens 32 Zeichen; Platzhalter in Produktion abgelehnt - 61 neue Integrationstests, insgesamt 148 grün Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014e7t8UpmoVNMtWivY5LiSH
70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
"""Schemata für Konten."""
|
||
|
||
from datetime import date, datetime
|
||
from decimal import Decimal
|
||
|
||
from pydantic import Field
|
||
|
||
from app.models.enums import AccountType
|
||
from app.schemas.common import ApiModel, HexColor, InputModel, Money
|
||
|
||
|
||
class AccountBase(InputModel):
|
||
name: str = Field(min_length=1, max_length=120, examples=["Girokonto"])
|
||
type: AccountType = AccountType.CHECKING
|
||
iban_last4: str | None = Field(
|
||
default=None, pattern=r"^\d{4}$", description="Letzte vier Stellen der IBAN."
|
||
)
|
||
opening_balance: Money = Field(
|
||
default=Decimal("0.00"), description="Saldo zum Stichtag `opening_balance_date`."
|
||
)
|
||
opening_balance_date: date
|
||
color: HexColor = "#3b82f6"
|
||
icon: str = Field(default="wallet", max_length=64, description="Name eines lucide-Icons.")
|
||
is_active: bool = True
|
||
sort_order: int = 0
|
||
|
||
|
||
class AccountCreate(AccountBase):
|
||
pass
|
||
|
||
|
||
class AccountUpdate(InputModel):
|
||
"""Alle Felder optional – gesetzt wird nur, was mitgeschickt wurde."""
|
||
|
||
name: str | None = Field(default=None, min_length=1, max_length=120)
|
||
type: AccountType | None = None
|
||
iban_last4: str | None = Field(default=None, pattern=r"^\d{4}$")
|
||
opening_balance: Money | None = None
|
||
opening_balance_date: date | None = None
|
||
color: HexColor | None = None
|
||
icon: str | None = Field(default=None, max_length=64)
|
||
is_active: bool | None = None
|
||
sort_order: int | None = None
|
||
|
||
|
||
class AccountOut(ApiModel):
|
||
id: int
|
||
name: str
|
||
type: AccountType
|
||
iban_last4: str | None
|
||
opening_balance: Money
|
||
opening_balance_date: date
|
||
color: str
|
||
icon: str
|
||
is_active: bool
|
||
sort_order: int
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
|
||
|
||
class AccountBalanceOut(ApiModel):
|
||
"""Fortgeschriebener Saldo zu einem Stichtag."""
|
||
|
||
account_id: int
|
||
as_of: date
|
||
opening_balance: Money
|
||
booked_transactions: Money = Field(description="Summe der einmaligen Buchungen.")
|
||
booked_occurrences: Money = Field(description="Summe der bestätigten Fälligkeiten.")
|
||
balance: Money = Field(description="Eröffnungssaldo zuzüglich aller Bewegungen.")
|