import uuid from django.db import models class BriefVorlage(models.Model): """Wiederverwendbare Briefvorlagen für Serienbriefe (Veranstaltungseinladungen u.ä.)""" name = models.CharField(max_length=100, verbose_name="Vorlagenname") beschreibung = models.TextField( blank=True, verbose_name="Beschreibung", help_text="Kurze Beschreibung des Verwendungszwecks dieser Vorlage.", ) briefvorlage = models.TextField( verbose_name="Brieftext (HTML)", help_text=( "HTML-Text des Briefs. Verfügbare Platzhalter: " "{{ anrede }}, {{ vorname }}, {{ nachname }}, {{ strasse }}, " "{{ plz }}, {{ ort }}, {{ datum }}, {{ uhrzeit }}, " "{{ veranstaltungsort }}, {{ gasthaus_adresse }}" ), ) betreff = models.CharField( max_length=300, blank=True, verbose_name="Standard-Betreff", help_text="Wird beim Laden der Vorlage in die Veranstaltung übernommen. Leer = unveränderter Betreff.", ) erstellt_am = models.DateTimeField(auto_now_add=True) aktualisiert_am = models.DateTimeField(auto_now=True) class Meta: verbose_name = "Briefvorlage" verbose_name_plural = "Briefvorlagen" ordering = ["name"] def __str__(self): return self.name class Veranstaltung(models.Model): """Veranstaltungen der Stiftung, z.B. Stiftungsessen mit Rechnungslegung""" STATUS_CHOICES = [ ("geplant", "Geplant"), ("einladungen_versendet", "Einladungen versendet"), ("abgeschlossen", "Abgeschlossen"), ("abgesagt", "Abgesagt"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) titel = models.CharField(max_length=200, verbose_name="Titel") datum = models.DateField(verbose_name="Datum") uhrzeit = models.TimeField(null=True, blank=True, verbose_name="Uhrzeit") ort = models.CharField(max_length=200, verbose_name="Ort / Gasthaus") adresse = models.TextField(blank=True, verbose_name="Adresse Gasthaus") beschreibung = models.TextField(blank=True, verbose_name="Beschreibung / Zweck") status = models.CharField( max_length=30, choices=STATUS_CHOICES, default="geplant", verbose_name="Status", ) budget_pro_person = models.DecimalField( max_digits=8, decimal_places=2, null=True, blank=True, verbose_name="Budget pro Person (€)", help_text="Geschätztes Budget je Teilnehmer in €", ) briefvorlage = models.TextField( blank=True, verbose_name="Briefvorlage", help_text=( "HTML/Text-Template für Serienbrief. Platzhalter: " "{{ anrede }}, {{ vorname }}, {{ nachname }}, {{ strasse }}, " "{{ plz }}, {{ ort }}, {{ datum }}, {{ uhrzeit }}, " "{{ veranstaltungsort }}, {{ gasthaus_adresse }}" ), ) betreff = models.CharField( max_length=300, blank=True, verbose_name="Betreff", help_text="Betreffzeile des Serienbriefs. Leer = Standardbetreff.", ) unterschrift_1_name = models.CharField( max_length=100, blank=True, default="Katrin Kleinpaß", verbose_name="Unterschrift 1 – Name", ) unterschrift_1_titel = models.CharField( max_length=100, blank=True, default="Rentmeisterin", verbose_name="Unterschrift 1 – Titel", ) unterschrift_2_name = models.CharField( max_length=100, blank=True, default="Jan Remmer Siebels", verbose_name="Unterschrift 2 – Name", ) unterschrift_2_titel = models.CharField( max_length=100, blank=True, default="Rentmeister", verbose_name="Unterschrift 2 – Titel", ) erstellt_am = models.DateTimeField(auto_now_add=True) aktualisiert_am = models.DateTimeField(auto_now=True) class Meta: verbose_name = "Veranstaltung" verbose_name_plural = "Veranstaltungen" ordering = ["-datum"] def __str__(self): return f"{self.titel} ({self.datum})" def get_teilnehmer_count(self): return self.teilnehmer.count() def get_zugesagte_count(self): return self.teilnehmer.filter(rsvp_status="zugesagt").count() def get_abgesagte_count(self): return self.teilnehmer.filter(rsvp_status="abgesagt").count() def get_keine_rueckmeldung_count(self): return self.teilnehmer.filter(rsvp_status="keine_rueckmeldung").count() class Veranstaltungsteilnehmer(models.Model): """Teilnehmer einer Veranstaltung – primär freie Eingabe für Familienmitglieder""" ANREDE_CHOICES = [ ("Herr", "Herr"), ("Frau", "Frau"), ("", "Keine Anrede"), ] RSVP_CHOICES = [ ("eingeladen", "Eingeladen"), ("zugesagt", "Zugesagt"), ("abgesagt", "Abgesagt"), ("keine_rueckmeldung", "Keine Rückmeldung"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) veranstaltung = models.ForeignKey( Veranstaltung, on_delete=models.CASCADE, related_name="teilnehmer", verbose_name="Veranstaltung", ) # Optionale Verknüpfung zu bestehenden Datensätzen paechter = models.ForeignKey( "stiftung.Paechter", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Pächter (optional)", ) destinataer = models.ForeignKey( "stiftung.Destinataer", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Destinatär (optional)", ) # Freie Felder (Pflichtfelder für Serienbrief) anrede = models.CharField( max_length=10, choices=ANREDE_CHOICES, blank=True, verbose_name="Anrede" ) vorname = models.CharField(max_length=100, verbose_name="Vorname") nachname = models.CharField(max_length=100, verbose_name="Nachname") strasse = models.CharField(max_length=200, blank=True, verbose_name="Straße") plz = models.CharField(max_length=10, blank=True, verbose_name="PLZ") ort = models.CharField(max_length=100, blank=True, verbose_name="Ort") email = models.EmailField( blank=True, verbose_name="E-Mail", help_text="Optional, für späteren E-Mail-Versand" ) rsvp_status = models.CharField( max_length=20, choices=RSVP_CHOICES, default="eingeladen", verbose_name="RSVP-Status", ) bemerkungen = models.TextField(blank=True, verbose_name="Bemerkungen") erstellt_am = models.DateTimeField(auto_now_add=True) class Meta: verbose_name = "Veranstaltungsteilnehmer" verbose_name_plural = "Veranstaltungsteilnehmer" ordering = ["nachname", "vorname"] def __str__(self): return f"{self.anrede} {self.vorname} {self.nachname}".strip() def get_full_name(self): return f"{self.vorname} {self.nachname}".strip() def get_full_address(self): parts = [self.strasse, f"{self.plz} {self.ort}".strip()] return ", ".join(p for p in parts if p)