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",)}),
)