from django import forms from django.contrib import admin from django.utils.html import format_html from ..models import BriefVorlage, Veranstaltung, Veranstaltungsteilnehmer class VeranstaltungsteilnehmerInline(admin.TabularInline): model = Veranstaltungsteilnehmer extra = 1 fields = [ "anrede", "vorname", "nachname", "strasse", "plz", "ort", "email", "rsvp_status", "bemerkungen", ] class BriefVorlageWidget(forms.Textarea): """Erweitertes Textarea-Widget für HTML-Briefvorlagen mit Editor-Panel und Platzhalter-Hilfe.""" class Media: js = ["stiftung/js/briefvorlage_editor.js"] def __init__(self, attrs=None): default_attrs = {"rows": 18, "cols": 80, "class": "briefvorlage-textarea", "style": "font-family: monospace; font-size: 13px;"} if attrs: default_attrs.update(attrs) super().__init__(attrs=default_attrs) class VeranstaltungAdminForm(forms.ModelForm): class Meta: model = Veranstaltung fields = "__all__" widgets = { "briefvorlage": BriefVorlageWidget(), } @admin.register(Veranstaltung) class VeranstaltungAdmin(admin.ModelAdmin): form = VeranstaltungAdminForm list_display = [ "titel", "datum", "uhrzeit", "ort", "status", "get_teilnehmer_count", "get_zugesagte_count", "budget_pro_person", ] list_filter = ["status", "datum"] search_fields = ["titel", "ort", "beschreibung"] ordering = ["-datum"] readonly_fields = ["id", "erstellt_am", "aktualisiert_am", "serienbrief_aktionen", "platzhalter_dokumentation"] inlines = [VeranstaltungsteilnehmerInline] fieldsets = ( ("Grunddaten", {"fields": ("titel", "datum", "uhrzeit", "status")}), ("Veranstaltungsort", {"fields": ("ort", "adresse")}), ("Details", {"fields": ("beschreibung", "budget_pro_person")}), ( "Serienbrief – Vorlage", { "fields": ( "platzhalter_dokumentation", "betreff", "briefvorlage", ), }, ), ( "Serienbrief – Unterschriften & Aktionen", { "fields": ( "unterschrift_1_name", "unterschrift_1_titel", "unterschrift_2_name", "unterschrift_2_titel", "serienbrief_aktionen", ), }, ), ("System", {"fields": ("id", "erstellt_am", "aktualisiert_am"), "classes": ("collapse",)}), ) def get_teilnehmer_count(self, obj): return obj.get_teilnehmer_count() get_teilnehmer_count.short_description = "Teilnehmer gesamt" def get_zugesagte_count(self, obj): return obj.get_zugesagte_count() get_zugesagte_count.short_description = "Zugesagt" def platzhalter_dokumentation(self, obj): return format_html( """
Verfügbare Platzhalter im Brieftext:
{{{{ anrede }}}}Anredetitel (Herr / Frau)
{{{{ vorname }}}}Vorname des Empfängers
{{{{ nachname }}}}Nachname des Empfängers
{{{{ strasse }}}}Straße und Hausnummer
{{{{ plz }}}}Postleitzahl
{{{{ ort }}}}Wohnort des Empfängers
{{{{ datum }}}}Datum der Veranstaltung (z.B. Freitag, 17. April 2026)
{{{{ uhrzeit }}}}Uhrzeit der Veranstaltung (z.B. 19:00 Uhr)
{{{{ veranstaltungsort }}}}Name des Veranstaltungsorts / Gasthaus
{{{{ gasthaus_adresse }}}}Adresse des Gasthauses
Platzhalter werden beim PDF-Export automatisch mit den Empfänger- und Veranstaltungsdaten befüllt. Tipp: Vorlagen unter Verwaltung → Briefvorlagen speichern und wiederverwenden.
""" ) platzhalter_dokumentation.short_description = "Platzhalter-Dokumentation" platzhalter_dokumentation.allow_tags = True def serienbrief_aktionen(self, obj): if obj.pk: from django.urls import reverse as url_reverse pdf_url = url_reverse("stiftung:veranstaltung_serienbrief_pdf", args=[obj.pk]) vorschau_url = url_reverse("stiftung:veranstaltung_serienbrief_vorschau", args=[obj.pk]) return format_html( 'Serienbrief-PDF generieren' 'Vorschau im Browser', pdf_url, vorschau_url, ) return "–" serienbrief_aktionen.short_description = "Aktionen" actions = ["generate_serienbrief"] def generate_serienbrief(self, request, queryset): if queryset.count() != 1: self.message_user( request, "Bitte genau eine Veranstaltung auswählen.", level="error", ) return from django.urls import reverse as url_reverse from django.shortcuts import redirect veranstaltung = queryset.first() url = url_reverse("stiftung:veranstaltung_serienbrief_pdf", args=[veranstaltung.pk]) return redirect(url) generate_serienbrief.short_description = "Serienbrief-PDF generieren" @admin.register(BriefVorlage) class BriefVorlageAdmin(admin.ModelAdmin): list_display = ["name", "beschreibung_kurz", "erstellt_am", "aktualisiert_am"] search_fields = ["name", "beschreibung"] ordering = ["name"] readonly_fields = ["erstellt_am", "aktualisiert_am"] fieldsets = ( (None, {"fields": ("name", "beschreibung")}), ( "Briefinhalt", { "fields": ("betreff", "briefvorlage"), "description": ( "Verfügbare Platzhalter: {{ anrede }}, {{ vorname }}, {{ nachname }}, " "{{ strasse }}, {{ plz }}, {{ ort }}, {{ datum }}, {{ uhrzeit }}, " "{{ veranstaltungsort }}, {{ gasthaus_adresse }}" ), }, ), ("System", {"fields": ("erstellt_am", "aktualisiert_am"), "classes": ("collapse",)}), ) def beschreibung_kurz(self, obj): return obj.beschreibung[:80] + "…" if len(obj.beschreibung) > 80 else obj.beschreibung beschreibung_kurz.short_description = "Beschreibung" @admin.register(Veranstaltungsteilnehmer) class VeranstaltungsteilnehmerAdmin(admin.ModelAdmin): list_display = [ "nachname", "vorname", "anrede", "veranstaltung", "rsvp_status", "ort", ] list_filter = ["rsvp_status", "veranstaltung", "anrede"] search_fields = ["vorname", "nachname", "ort", "email"] ordering = ["veranstaltung", "nachname", "vorname"] readonly_fields = ["id", "erstellt_am"] fieldsets = ( ("Zuordnung", {"fields": ("veranstaltung", "paechter", "destinataer")}), ( "Persönliche Daten", {"fields": ("anrede", "vorname", "nachname", "email")}, ), ("Adresse", {"fields": ("strasse", "plz", "ort")}), ("RSVP", {"fields": ("rsvp_status", "bemerkungen")}), ("System", {"fields": ("id", "erstellt_am"), "classes": ("collapse",)}), )