Add Vorlagen editor, upload portal, onboarding, and participant import command
- Dokument-Vorlagen-Editor: create/edit/reset document templates (admin) - Upload-Portal: public portal for Nachweis uploads via token - Onboarding: invite Destinatäre via email with multi-step wizard - Bestätigungsschreiben: preview and send confirmation letters - Email settings: SMTP configuration UI - Management command: import_veranstaltung_teilnehmer for bulk participant import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
160
app/stiftung/migrations/0061_dokument_vorlage.py
Normal file
160
app/stiftung/migrations/0061_dokument_vorlage.py
Normal file
@@ -0,0 +1,160 @@
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def seed_vorlagen(apps, schema_editor):
|
||||
"""Seed initial DokumentVorlage records from file templates."""
|
||||
import os
|
||||
|
||||
from django.template.loader import get_template
|
||||
from django.template import TemplateDoesNotExist
|
||||
|
||||
DokumentVorlage = apps.get_model("stiftung", "DokumentVorlage")
|
||||
|
||||
# Map: (schluessel, bezeichnung, kategorie, variablen)
|
||||
vorlagen_def = [
|
||||
(
|
||||
"pdf/bestaetigung.html",
|
||||
"Bestätigung PDF",
|
||||
"pdf",
|
||||
{
|
||||
"destinataer.vorname": "Vorname",
|
||||
"destinataer.nachname": "Nachname",
|
||||
"destinataer.anrede": "Anrede (Herr/Frau)",
|
||||
"destinataer.strasse": "Straße",
|
||||
"destinataer.plz": "PLZ",
|
||||
"destinataer.ort": "Ort",
|
||||
"betrag_quartal": "Betrag pro Quartal",
|
||||
"betrag_jaehrlich": "Jährlicher Betrag",
|
||||
"zeitraum": "Förderzeitraum",
|
||||
"zweck": "Förderzweck",
|
||||
"unterstuetzungen": "Liste der Unterstützungen",
|
||||
"gesamtbetrag": "Gesamtbetrag",
|
||||
"datum": "Datum der Erstellung",
|
||||
},
|
||||
),
|
||||
(
|
||||
"email/bestaetigung.html",
|
||||
"Bestätigung E-Mail (HTML)",
|
||||
"email",
|
||||
{
|
||||
"destinataer.vorname": "Vorname",
|
||||
"destinataer.nachname": "Nachname",
|
||||
"destinataer.anrede": "Anrede",
|
||||
"zeitraum": "Förderzeitraum",
|
||||
"gesamtbetrag": "Gesamtbetrag",
|
||||
"datum": "Datum",
|
||||
},
|
||||
),
|
||||
(
|
||||
"email/nachweis_aufforderung.html",
|
||||
"Nachweis-Aufforderung E-Mail (HTML)",
|
||||
"email",
|
||||
{
|
||||
"destinataer.vorname": "Vorname",
|
||||
"destinataer.nachname": "Nachname",
|
||||
"halbjahr_label": "Halbjahr-Bezeichnung",
|
||||
"upload_url": "Upload-URL",
|
||||
"gueltig_bis": "Gültig bis",
|
||||
"qr_code_base64": "QR-Code (base64)",
|
||||
"ist_erinnerung": "True wenn Erinnerung",
|
||||
},
|
||||
),
|
||||
(
|
||||
"email/nachweis_aufforderung.txt",
|
||||
"Nachweis-Aufforderung E-Mail (Text)",
|
||||
"email",
|
||||
{
|
||||
"destinataer.vorname": "Vorname",
|
||||
"destinataer.nachname": "Nachname",
|
||||
"halbjahr_label": "Halbjahr-Bezeichnung",
|
||||
"upload_url": "Upload-URL",
|
||||
"gueltig_bis": "Gültig bis",
|
||||
"ist_erinnerung": "True wenn Erinnerung",
|
||||
},
|
||||
),
|
||||
(
|
||||
"email/onboarding_einladung.html",
|
||||
"Onboarding-Einladung E-Mail (HTML)",
|
||||
"email",
|
||||
{
|
||||
"einladung.vorname": "Vorname",
|
||||
"einladung.nachname": "Nachname",
|
||||
"onboarding_url": "Onboarding-URL",
|
||||
"gueltig_bis": "Gültig bis",
|
||||
},
|
||||
),
|
||||
(
|
||||
"email/onboarding_einladung.txt",
|
||||
"Onboarding-Einladung E-Mail (Text)",
|
||||
"email",
|
||||
{
|
||||
"einladung.vorname": "Vorname",
|
||||
"einladung.nachname": "Nachname",
|
||||
"onboarding_url": "Onboarding-URL",
|
||||
"gueltig_bis": "Gültig bis",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
templates_dir = os.path.join(settings.BASE_DIR, "templates")
|
||||
|
||||
for schluessel, bezeichnung, kategorie, variablen in vorlagen_def:
|
||||
template_path = os.path.join(templates_dir, schluessel)
|
||||
if os.path.exists(template_path):
|
||||
with open(template_path, "r", encoding="utf-8") as f:
|
||||
html_inhalt = f.read()
|
||||
DokumentVorlage.objects.get_or_create(
|
||||
schluessel=schluessel,
|
||||
defaults={
|
||||
"bezeichnung": bezeichnung,
|
||||
"kategorie": kategorie,
|
||||
"html_inhalt": html_inhalt,
|
||||
"verfuegbare_variablen": variablen,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("stiftung", "0060_portal_upload_token_onboarding"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="DokumentVorlage",
|
||||
fields=[
|
||||
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
("schluessel", models.CharField(help_text="Interner Template-Pfad, z.B. pdf/bestaetigung.html", max_length=200, unique=True, verbose_name="Schlüssel")),
|
||||
("bezeichnung", models.CharField(max_length=200, verbose_name="Bezeichnung")),
|
||||
("kategorie", models.CharField(
|
||||
choices=[("pdf", "PDF-Dokument"), ("email", "E-Mail"), ("bericht", "Bericht"), ("serienbrief", "Serienbrief")],
|
||||
max_length=30,
|
||||
verbose_name="Kategorie",
|
||||
)),
|
||||
("html_inhalt", models.TextField(verbose_name="HTML-Inhalt")),
|
||||
("verfuegbare_variablen", models.JSONField(blank=True, default=dict, help_text="JSON-Dokumentation der verfügbaren Template-Variablen", verbose_name="Verfügbare Variablen")),
|
||||
("zuletzt_bearbeitet_am", models.DateTimeField(auto_now=True, verbose_name="Zuletzt bearbeitet")),
|
||||
("erstellt_am", models.DateTimeField(auto_now_add=True, verbose_name="Erstellt am")),
|
||||
("zuletzt_bearbeitet_von", models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="bearbeitete_vorlagen",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Zuletzt bearbeitet von",
|
||||
)),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Dokument-Vorlage",
|
||||
"verbose_name_plural": "Dokument-Vorlagen",
|
||||
"ordering": ["kategorie", "bezeichnung"],
|
||||
},
|
||||
),
|
||||
migrations.RunPython(seed_vorlagen, migrations.RunPython.noop),
|
||||
]
|
||||
Reference in New Issue
Block a user