""" Letters Models - Pydantic models and enums for Elternbrief-Verwaltung. """ from datetime import datetime from typing import Optional, List from enum import Enum from pydantic import BaseModel, Field # ============================================================================= # Enums # ============================================================================= class LetterType(str, Enum): """Typen von Elternbriefen.""" GENERAL = "general" HALBJAHR = "halbjahr" FEHLZEITEN = "fehlzeiten" ELTERNABEND = "elternabend" LOB = "lob" CUSTOM = "custom" class LetterTone(str, Enum): """Tonalitaet der Briefe.""" FORMAL = "formal" PROFESSIONAL = "professional" WARM = "warm" CONCERNED = "concerned" APPRECIATIVE = "appreciative" class LetterStatus(str, Enum): """Status eines Briefes.""" DRAFT = "draft" SENT = "sent" ARCHIVED = "archived" # ============================================================================= # Pydantic Models # ============================================================================= class SchoolInfoModel(BaseModel): """Schulinformationen fuer Briefkopf.""" name: str address: str phone: str email: str website: Optional[str] = None principal: Optional[str] = None logo_path: Optional[str] = None class LegalReferenceModel(BaseModel): """Rechtliche Referenz.""" law: str paragraph: str title: str summary: Optional[str] = None relevance: Optional[str] = None class LetterCreateRequest(BaseModel): """Request zum Erstellen eines neuen Briefes.""" recipient_name: str = Field(..., description="Name des Empfaengers") recipient_address: str = Field(..., description="Adresse des Empfaengers") student_name: str = Field(..., description="Name des Schuelers") student_class: str = Field(..., description="Klasse des Schuelers") subject: str = Field(..., description="Betreff des Briefes") content: str = Field(..., description="Inhalt des Briefes") letter_type: LetterType = Field(LetterType.GENERAL, description="Art des Briefes") tone: LetterTone = Field(LetterTone.PROFESSIONAL, description="Tonalitaet des Briefes") teacher_name: str = Field(..., description="Name des Lehrers") teacher_title: Optional[str] = Field(None, description="Titel des Lehrers") school_info: Optional[SchoolInfoModel] = Field(None, description="Schulinformationen") legal_references: Optional[List[LegalReferenceModel]] = Field(None, description="Rechtliche Referenzen") gfk_principles_applied: Optional[List[str]] = Field(None, description="Angewandte GFK-Prinzipien") class LetterUpdateRequest(BaseModel): """Request zum Aktualisieren eines Briefes.""" recipient_name: Optional[str] = None recipient_address: Optional[str] = None student_name: Optional[str] = None student_class: Optional[str] = None subject: Optional[str] = None content: Optional[str] = None letter_type: Optional[LetterType] = None tone: Optional[LetterTone] = None teacher_name: Optional[str] = None teacher_title: Optional[str] = None school_info: Optional[SchoolInfoModel] = None legal_references: Optional[List[LegalReferenceModel]] = None gfk_principles_applied: Optional[List[str]] = None status: Optional[LetterStatus] = None class LetterResponse(BaseModel): """Response mit Briefdaten.""" id: str recipient_name: str recipient_address: str student_name: str student_class: str subject: str content: str letter_type: LetterType tone: LetterTone teacher_name: str teacher_title: Optional[str] school_info: Optional[SchoolInfoModel] legal_references: Optional[List[LegalReferenceModel]] gfk_principles_applied: Optional[List[str]] gfk_score: Optional[float] status: LetterStatus pdf_path: Optional[str] dsms_cid: Optional[str] sent_at: Optional[datetime] created_at: datetime updated_at: datetime class LetterListResponse(BaseModel): """Response mit Liste von Briefen.""" letters: List[LetterResponse] total: int page: int page_size: int class ExportPDFRequest(BaseModel): """Request zum PDF-Export.""" letter_id: Optional[str] = Field(None, description="ID eines gespeicherten Briefes") letter_data: Optional[LetterCreateRequest] = Field(None, description="Oder direkte Briefdaten") class ImproveRequest(BaseModel): """Request zur GFK-Verbesserung.""" content: str = Field(..., description="Text zur Verbesserung") communication_type: Optional[str] = Field("general_info", description="Art der Kommunikation") tone: Optional[str] = Field("professional", description="Gewuenschte Tonalitaet") class ImproveResponse(BaseModel): """Response mit verbessertem Text.""" improved_content: str changes: List[str] gfk_score: float gfk_principles_applied: List[str] class SendEmailRequest(BaseModel): """Request zum Email-Versand.""" letter_id: str recipient_email: str cc_emails: Optional[List[str]] = None include_pdf: bool = True class SendEmailResponse(BaseModel): """Response nach Email-Versand.""" success: bool message: str sent_at: Optional[datetime] # ============================================================================= # Helper Functions # ============================================================================= def get_type_label(letter_type: LetterType) -> str: """Gibt menschenlesbare Labels fuer Brieftypen zurueck.""" labels = { LetterType.GENERAL: "Allgemeine Information", LetterType.HALBJAHR: "Halbjahresinformation", LetterType.FEHLZEITEN: "Fehlzeiten-Mitteilung", LetterType.ELTERNABEND: "Einladung Elternabend", LetterType.LOB: "Positives Feedback", LetterType.CUSTOM: "Benutzerdefiniert", } return labels.get(letter_type, letter_type.value) def get_tone_label(tone: LetterTone) -> str: """Gibt menschenlesbare Labels fuer Tonalitaeten zurueck.""" labels = { LetterTone.FORMAL: "Sehr foermlich", LetterTone.PROFESSIONAL: "Professionell-freundlich", LetterTone.WARM: "Warmherzig", LetterTone.CONCERNED: "Besorgt", LetterTone.APPRECIATIVE: "Wertschaetzend", } return labels.get(tone, tone.value)