Files
certain/backend/app/seed.py
T
GuidoandClaude Opus 4.8 1b7107b9bd feat: Phase 1 – Konten, Kategorien, Transaktionen, EZB-Währungsumrechnung
Backend:
- Modelle + Migration 0002: accounts, account_identifiers, category_groups,
  categories, transactions, exchange_rates (alle owner-gescoped).
- EZB-Kursdienst (90-Tage/Historie) + Backfill-Skript; Umrechnung EUR<->CHF zum
  Buchungsdatum mit lokalem Cache und manueller Übersteuerung; EUR-Pivot
  (amount_eur_cents) eingefroren.
- Kontostände + Netto-Vermögen (Umrechnung in Hauptwährung).
- Router: accounts (inkl. IBAN-Identifikatoren), categories (Gruppen+Kategorien),
  transactions (Ausgabe/Einnahme/Transfer, cross-currency), rates.
- Gruppierte Standard-Kategorien je Nutzer beim Anlegen.
- pytest-Suite: Währung, Salden, Cross-Currency-Transfer, Nutzer-Isolation.

Frontend:
- Seiten Konten, Kategorien, Buchungen; Icon-Chip, Geldbetrag mit Umrechnung,
  Icon-/Farbwähler, Modal; erweitertes SVG-Icon-Set (Konto-/Kategorie-Icons).
- Währungs-/Datumsformatierung (EUR de-DE, CHF de-CH), i18n DE/EN erweitert.
- Live-Umrechnungs-Vorschau im Transfer-Formular.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-19 18:59:24 +02:00

88 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Startup-Seeds. Phase 0: nur der erste Admin-Benutzer.
Fachliche Startdaten (Standard-Kategorien usw.) folgen in späteren Phasen.
"""
from sqlalchemy.orm import Session
from .config import get_settings
from .models import Category, CategoryGroup, CategoryKind, Role, User
from .security import hash_password
# Vorgefertigte, gruppierte Startkategorien je Benutzer. Alles frei änderbar;
# wer eine Gruppe/Kategorie löscht, bekommt sie nicht automatisch zurück.
# (Gruppe, Art, Gruppen-Icon, Gruppen-Farbe, [(Kategoriename, Icon), ...])
STARTER_CATEGORIES: list[tuple[str, CategoryKind, str, str, list[tuple[str, str]]]] = [
("Fixkosten", CategoryKind.expense, "landmark", "#3f51b5", [
("Wohnen", "home"),
("Versicherungen", "shield"),
("Telefon & Internet", "wifi"),
("Abos & Streaming", "refresh-ccw"),
]),
("Lebenshaltung", CategoryKind.expense, "shopping-cart", "#2e7d55", [
("Lebensmittel", "shopping-cart"),
("Restaurant", "utensils"),
("Mobilität", "car"),
("Gesundheit", "heart-pulse"),
("Kleidung", "shirt"),
]),
("Freizeit & Persönliches", CategoryKind.expense, "film", "#b06f14", [
("Freizeit", "film"),
("Reisen", "plane"),
("Sport & Fitness", "dumbbell"),
("Bildung", "graduation-cap"),
("Haustiere", "paw-print"),
("Geschenke & Spenden", "gift"),
]),
("Finanzen", CategoryKind.expense, "piggy-bank", "#2a78d6", [
("Sparen & Investments", "piggy-bank"),
("Steuern & Gebühren", "percent"),
]),
("Sonstiges", CategoryKind.expense, "more-horizontal", "#6b7480", [
("Sonstiges", "more-horizontal"),
]),
("Einnahmen", CategoryKind.income, "coins", "#2e7d55", [
("Gehalt", "banknote"),
("Nebeneinkünfte", "coins"),
("Erstattungen", "receipt"),
]),
]
def ensure_starter_categories(db: Session, user: User) -> None:
"""Legt die Startkategorien für einen Benutzer an – nur, wenn er noch keine hat."""
exists = db.query(CategoryGroup).filter(CategoryGroup.owner_id == user.id).first()
if exists is not None:
return
for gpos, (gname, kind, gicon, gcolor, cats) in enumerate(STARTER_CATEGORIES):
group = CategoryGroup(
owner_id=user.id, name=gname, kind=kind, icon=gicon, color=gcolor,
position=gpos, is_builtin=True,
)
db.add(group)
db.flush()
for cpos, (cname, cicon) in enumerate(cats):
db.add(Category(
owner_id=user.id, group_id=group.id, name=cname, type=kind,
icon=cicon, color=gcolor, position=cpos, is_builtin=True,
))
db.commit()
def ensure_first_admin(db: Session) -> None:
"""Legt einen Admin an, solange noch gar kein Benutzer existiert."""
if db.query(User).first() is not None:
return
settings = get_settings()
admin = User(
username=settings.admin_username,
password_hash=hash_password(settings.admin_password),
role=Role.admin,
is_active=True,
must_change_password=False,
)
db.add(admin)
db.commit()
db.refresh(admin)
ensure_starter_categories(db, admin)