From c3c675502773a46b9d149f939876edd489022b9e Mon Sep 17 00:00:00 2001 From: SysAdmin Agent Date: Wed, 11 Mar 2026 20:55:21 +0000 Subject: [PATCH] Modernize Destinataer detail page: tabbed UI with integrated timeline Replaces the old multi-card layout (1368 lines) with a compact, modern tabbed interface (Stammdaten | Nachweise | Zahlungen | Timeline | Dokumente | Notizen). All information is now accessible from one page without excessive clicking. - Add timeline events to destinataer_detail view (merged from timeline view logic) - Compact profile header with avatar initials, status badges, key contact info - Inline editing preserved with table-based layout for cleaner data display - Tab state persisted in URL hash for bookmarkable deep links - Dropdown menu for less-used actions (export, archive, delete) Co-Authored-By: Claude Opus 4.6 --- app/stiftung/views/destinataere.py | 47 + .../stiftung/destinataer_detail.html | 2050 ++++++----------- 2 files changed, 811 insertions(+), 1286 deletions(-) diff --git a/app/stiftung/views/destinataere.py b/app/stiftung/views/destinataere.py index 250328e..ba393bc 100644 --- a/app/stiftung/views/destinataere.py +++ b/app/stiftung/views/destinataere.py @@ -316,6 +316,52 @@ def destinataer_detail(request, pk): # Alle verfügbaren StiftungsKonten für das Select-Feld laden stiftungskonten = StiftungsKonto.objects.all().order_by("kontoname") + # Timeline events (merged from destinataer_timeline view) + timeline_events = [] + for u in destinataer.unterstuetzungen.select_related("konto", "ausgezahlt_von", "freigegeben_von").order_by("-faellig_am"): + timeline_events.append({ + "datum": u.faellig_am, + "typ": "zahlung", + "icon": "fa-money-bill-wave", + "farbe": "success" if u.status == "ausgezahlt" else ("danger" if u.is_overdue() else "primary"), + "titel": f"Zahlung \u20ac{u.betrag}", + "beschreibung": u.beschreibung or u.get_status_display(), + "status": u.get_status_display(), + }) + for n in destinataer.quartalseinreichungen.order_by("-jahr", "-quartal"): + datum = n.zahlung_faelligkeitsdatum or n.faelligkeitsdatum + if datum: + timeline_events.append({ + "datum": datum, + "typ": "nachweis", + "icon": "fa-file-alt", + "farbe": "success" if n.status in ("geprueft", "auto_geprueft") else ("danger" if n.is_overdue() else "warning"), + "titel": f"Nachweis {n.jahr} Q{n.quartal}", + "beschreibung": n.get_status_display(), + "status": n.get_status_display(), + }) + for e in destinataer.email_eingaenge.order_by("-eingangsdatum"): + timeline_events.append({ + "datum": e.eingangsdatum.date() if hasattr(e.eingangsdatum, "date") else e.eingangsdatum, + "typ": "email", + "icon": "fa-envelope", + "farbe": "info", + "titel": e.betreff or "(kein Betreff)", + "beschreibung": e.absender_email, + "status": e.get_status_display(), + }) + for n in destinataer.notizen_eintraege.order_by("-erstellt_am"): + timeline_events.append({ + "datum": n.erstellt_am.date() if hasattr(n.erstellt_am, "date") else n.erstellt_am, + "typ": "notiz", + "icon": "fa-sticky-note", + "farbe": "secondary", + "titel": n.titel or "Notiz", + "beschreibung": (n.text[:100] + "\u2026") if n.text and len(n.text) > 100 else n.text, + "status": f"von {n.erstellt_von.get_full_name() or n.erstellt_von.username}" if n.erstellt_von else "", + }) + timeline_events.sort(key=lambda e: e["datum"] if e["datum"] else date.min, reverse=True) + context = { "destinataer": destinataer, "verknuepfte_dokumente": verknuepfte_dokumente, @@ -326,6 +372,7 @@ def destinataer_detail(request, pk): "quarterly_confirmations": quarterly_confirmations, "available_years": available_years, "current_year": current_year, + "timeline_events": timeline_events, } return render(request, "stiftung/destinataer_detail.html", context) diff --git a/app/templates/stiftung/destinataer_detail.html b/app/templates/stiftung/destinataer_detail.html index 7cb10f1..d013a44 100644 --- a/app/templates/stiftung/destinataer_detail.html +++ b/app/templates/stiftung/destinataer_detail.html @@ -1,1216 +1,798 @@ {% extends 'base.html' %} {% load static %} -{% block title %}{{ destinataer.get_full_name }} - Destinatär - Stiftungsverwaltung{% endblock %} +{% block title %}{{ destinataer.get_full_name }} - Destinataer{% endblock %} {% block content %} +
-
-
- -
-

- - Destinatär: {{ destinataer.get_full_name }} -

-
- - Neue Unterstützung - - - - - - - -
- {% csrf_token %} + {# ── Profile Header ── #} +
+
+
+
+
+ {{ destinataer.vorname|first }}{{ destinataer.nachname|first }} +
+
+
+

+ {{ destinataer.get_full_name }} {% if destinataer.aktiv %} - + Aktiv {% else %} - + Inaktiv {% endif %} - - - Zurück zur Liste + {% if destinataer.finanzielle_notlage %} + Notlage + {% endif %} +

+
+ {% if destinataer.familienzweig %}{{ destinataer.get_familienzweig_display }}{% endif %} + {% if destinataer.email %}{{ destinataer.email }}{% endif %} + {% if destinataer.telefon %}{{ destinataer.telefon }}{% endif %} + {% if destinataer.iban %}{{ destinataer.iban }}{% endif %} +
+
+
+ {% if destinataer.vierteljaehrlicher_betrag %} +
+
Quartalsbetrag
+
€{{ destinataer.vierteljaehrlicher_betrag|floatformat:2 }}
+
+ {% endif %} +
+
+
+ + + +
+ + Zahlung -
-
- -
- -
- -
- {% csrf_token %} - - -
-
-
- Persönliche Informationen -
-
-
-
-
- -

- Vorname: - {{ destinataer.vorname }} - -

- - -

- Nachname: - {{ destinataer.nachname }} - -

- - -

- Geburtsdatum: - - {% if destinataer.geburtsdatum %} - {{ destinataer.geburtsdatum|date:"d.m.Y" }} - {% else %} - Nicht angegeben - {% endif %} - - -

- - -

- Familienzweig: - - {{ destinataer.get_familienzweig_display }} - - -

-
-
- -

- Status: - - {% if destinataer.aktiv %} - Aktiv - {% else %} - Inaktiv - {% endif %} - -

-

- - -

- Berufsgruppe: - - {{ destinataer.get_berufsgruppe_display }} - - -

-
-
-
-
- - -
-
-
- Kontaktinformationen -
-
-
-
-
- -

- E-Mail: - - {% if destinataer.email %} - {{ destinataer.email }} - {% else %} - Nicht angegeben - {% endif %} - - -

- - -

- Telefon: - - {% if destinataer.telefon %} - {{ destinataer.telefon }} - {% else %} - Nicht angegeben - {% endif %} - - -

-
-
- -

- IBAN: - - {% if destinataer.iban %} - {{ destinataer.iban }} - {% else %} - Nicht angegeben - {% endif %} - - -

-
-
- - -
-
-

- Adresse: - - {% if destinataer.adresse %} -
{{ destinataer.adresse|linebreaks }} - {% else %} - Nicht angegeben - {% endif %} -
-

-

-
-
-
-
- - -
-
-
- Berufliche Informationen -
-
-
-
-
- -

- Ausbildungsstand: - - {% if destinataer.ausbildungsstand %} - {{ destinataer.ausbildungsstand }} - {% else %} - Nicht angegeben - {% endif %} - - -

- - -

- Institution/Organisation: - - {% if destinataer.institution %} - {{ destinataer.institution }} - {% else %} - Nicht angegeben - {% endif %} - - -

-
-
- -

- Projektbeschreibung: - - {% if destinataer.projekt_beschreibung %} -
{{ destinataer.projekt_beschreibung|linebreaks }} - {% else %} - Nicht angegeben - {% endif %} -
- -

-
-
-
-
- - -
-
-
- Finanzielle Informationen -
-
-
-
-
- -

- Jährliches Einkommen: - - {% if destinataer.jaehrliches_einkommen %} - €{{ destinataer.jaehrliches_einkommen|floatformat:2 }} - {% else %} - Nicht angegeben - {% endif %} - - -

- - -

- Vermögen: - - {% if destinataer.vermoegen %} - €{{ destinataer.vermoegen|floatformat:2 }} - {% else %} - Nicht angegeben - {% endif %} - - -

- - -

- Haushaltsgröße: - - {% if destinataer.haushaltsgroesse %} - {{ destinataer.haushaltsgroesse }} - {% else %} - Nicht angegeben - {% endif %} - - -

-
-
- -

- Finanzielle Notlage: - - {% if destinataer.finanzielle_notlage %} - - Ja - - {% else %} - - Nein - - {% endif %} - -

-

- - -

- Vierteljährlicher Betrag: - - {% if destinataer.vierteljaehrlicher_betrag %} - €{{ destinataer.vierteljaehrlicher_betrag|floatformat:2 }} - {% else %} - Nicht angegeben - {% endif %} - - -

- - -

- Unterstützung bestätigt: - - {% if destinataer.unterstuetzung_bestaetigt %} - Ja - {% else %} - Nein - {% endif %} - -

-

- - -

- Standardkonto: - - {% if destinataer.standard_konto %} - {{ destinataer.standard_konto }} - {% else %} - Nicht angegeben - {% endif %} - - -

-
-
-
-
- - -
-
-
- Studiennachweis & Voraussetzungen -
-
-
-
-
- -

- Abkömmling gem. Satzung: - - {% if destinataer.ist_abkoemmling %} - Ja - {% else %} - Nein - {% endif %} - -

-

- - -

- Studiennachweis erforderlich: - - {% if destinataer.studiennachweis_erforderlich %} - Ja - {% else %} - Nein - {% endif %} - -

-

-
-
- -

- Letzter Nachweis: - - {% if destinataer.letzter_studiennachweis %} - {{ destinataer.letzter_studiennachweis|date:"d.m.Y" }} - {% else %} - Nicht angegeben - {% endif %} - - -

-
-
-
-
- - -
-
-
-
- Vierteljährliche Nachweise -
-
- Studiennachweis: 15. März / 15. September | Zahlung: vierteljährlich im Voraus - -
-
-
-
- {% if quarterly_confirmations %} - -
- - - - - - - - - - - - - - - {% for nachweis in quarterly_confirmations %} - - - - - - - - - - - {% endfor %} - -
ZeitraumStatusFortschrittFristenAktionen
- {{ nachweis.jahr }} Q{{ nachweis.quartal }} - {% if nachweis.is_overdue %} -
- {% endif %} -
- {% if nachweis.status == 'offen' %} - Offen - {% elif nachweis.status == 'teilweise' %} - Teilweise - {% elif nachweis.status == 'eingereicht' %} - Eingereicht - {% elif nachweis.status == 'geprueft' %} - Freigegeben - {% elif nachweis.status == 'auto_geprueft' %} - - Auto - - {% elif nachweis.status == 'nachbesserung' %} - Nachbesserung - {% elif nachweis.status == 'abgelehnt' %} - Abgelehnt - {% endif %} - - {% with completion=nachweis.get_completion_percentage %} -
-
- {{ completion }}% -
-
- {% endwith %} -
-
- {% if nachweis.studiennachweis_faelligkeitsdatum %} -
- - - {{ nachweis.studiennachweis_faelligkeitsdatum|date:"d.m.Y" }} - - {% if nachweis.is_study_proof_overdue %} - - {% endif %} -
- {% endif %} - {% if nachweis.zahlung_faelligkeitsdatum %} -
- - - {{ nachweis.zahlung_faelligkeitsdatum|date:"d.m.Y" }} - - {% if nachweis.is_payment_overdue %} - - {% endif %} -
- {% endif %} -
-
- {% if nachweis.studiennachweis_eingereicht %} - {% if nachweis.studiennachweis_datei %} - - - - {% elif nachweis.studiennachweis_bemerkung %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - - {% if nachweis.einkommenssituation_bestaetigt %} - {% if nachweis.einkommenssituation_datei %} - - - - {% elif nachweis.einkommenssituation_text %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - - {% if nachweis.vermogenssituation_bestaetigt %} - {% if nachweis.vermogenssituation_datei %} - - - - {% elif nachweis.vermogenssituation_text %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - -
- - - - {% if user.is_staff %} - {% if nachweis.status == 'eingereicht' %} - - {% elif nachweis.status == 'geprueft' %} - - - {% endif %} - {% endif %} -
-
-
- - - - {% else %} -
- -
Keine vierteljährlichen Nachweise vorhanden
-

Klicken Sie auf "Quartal hinzufügen", um einen neuen Nachweis zu erstellen.

-
- {% endif %} -
-
- - -
-
-
- Notizen -
-
-
-

- - {% if destinataer.notizen %} - {{ destinataer.notizen|linebreaks }} - {% else %} - Keine Notizen vorhanden - {% endif %} - - -

-
-
-
- - - - - -
- -
-
-
- Statistiken -
-
-
-
-
-
-
-

{{ foerderungen.count }}

- Förderungen -
-
-
-

- {% if foerderungen %} - {% with total_betrag=foerderungen|length %} - €{{ total_betrag|floatformat:0 }} - {% endwith %} - {% else %} - €0 - {% endif %} -

- Gesamtbetrag -
-
-
-
-
- - -
-
-
- Aktionen -
-
- -
- - -
-
-
- Informationen -
-
-
-

ID: {{ destinataer.id }}

-

Erstellt: {{ destinataer.id|slice:":8" }}

- {% if destinataer.aktiv %} -

Status: Aktiv

- {% else %} -

Status: Inaktiv

- {% endif %} -
+ +
  • +
  • Loeschen
  • +
    + + +
    + {# ── Tab Navigation ── #} + + + {# ── Tab Content ── #} +
    + + {# ════════ TAB: Stammdaten ════════ #} +
    +
    + {% csrf_token %} +
    + {# Left column – Personal + Contact #} +
    +
    +
    Persoenliche Daten
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    Vorname + {{ destinataer.vorname }} + +
    Nachname + {{ destinataer.nachname }} + +
    Geburtsdatum + {% if destinataer.geburtsdatum %}{{ destinataer.geburtsdatum|date:"d.m.Y" }}{% else %}-{% endif %} + +
    Familienzweig + {{ destinataer.get_familienzweig_display|default:"-" }} + +
    Berufsgruppe + {{ destinataer.get_berufsgruppe_display|default:"-" }} + +
    +
    +
    + +
    +
    Kontakt & Adresse
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    E-Mail + {% if destinataer.email %}{{ destinataer.email }}{% else %}-{% endif %} + +
    Telefon + {{ destinataer.telefon|default:"-" }} + +
    IBAN + {{ destinataer.iban|default:"-" }} + +
    Strasse + {{ destinataer.strasse|default:"-" }} + +
    PLZ / Ort + {% if destinataer.plz or destinataer.ort %}{{ destinataer.plz }} {{ destinataer.ort }}{% else %}-{% endif %} + +
    +
    +
    +
    + + {# Right column – Financial + Study #} +
    +
    +
    Finanzen & Foerderung
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Quartalsbetrag + {% if destinataer.vierteljaehrlicher_betrag %}€{{ destinataer.vierteljaehrlicher_betrag|floatformat:2 }}{% else %}-{% endif %} + +
    Monatliche Bezuege + {% if destinataer.monatliche_bezuege %}€{{ destinataer.monatliche_bezuege|floatformat:2 }}{% else %}-{% endif %} + +
    Jaehrliches Einkommen + {% if destinataer.jaehrliches_einkommen %}€{{ destinataer.jaehrliches_einkommen|floatformat:2 }}{% else %}-{% endif %} + +
    Vermoegen + {% if destinataer.vermoegen %}€{{ destinataer.vermoegen|floatformat:2 }}{% else %}-{% endif %} + +
    Haushaltsgroesse + {{ destinataer.haushaltsgroesse|default:"-" }} + +
    Standardkonto + {{ destinataer.standard_konto|default:"-" }} + +
    Finanzielle Notlage + + {% if destinataer.finanzielle_notlage %}Ja{% else %}Nein{% endif %} + + +
    Unterstuetzung bestaetigt + + {% if destinataer.unterstuetzung_bestaetigt %}Ja{% else %}Nein{% endif %} + + +
    +
    +
    + +
    +
    Studium & Voraussetzungen
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    Abkoemmling gem. Satzung + {% if destinataer.ist_abkoemmling %}Ja{% else %}Nein{% endif %} + +
    Ausbildungsstand + {{ destinataer.ausbildungsstand|default:"-" }} + +
    Institution + {{ destinataer.institution|default:"-" }} + +
    Studiennachweis erf. + {% if destinataer.studiennachweis_erforderlich %}Ja{% else %}Nein{% endif %} + +
    Letzter Nachweis + {% if destinataer.letzter_studiennachweis %}{{ destinataer.letzter_studiennachweis|date:"d.m.Y" }}{% else %}-{% endif %} + +
    +
    +
    + + {# Projektbeschreibung + Notizen #} +
    +
    Beschreibung & Notizen
    +
    +
    + Projektbeschreibung +
    {% if destinataer.projekt_beschreibung %}{{ destinataer.projekt_beschreibung|linebreaks }}{% else %}-{% endif %}
    + +
    +
    + Notizen +
    {% if destinataer.notizen %}{{ destinataer.notizen|linebreaks }}{% else %}-{% endif %}
    + +
    +
    +
    + + {# Hidden fields for edit form #} + +
    +
    +
    +
    + + {# ════════ TAB: Nachweise ════════ #} +
    +
    +
    + Studiennachweis: 15. Maerz / 15. September | Zahlung: vierteljaehrlich im Voraus +
    + +
    + {% if quarterly_confirmations %} +
    + + + + + + + + + + + + + + + {% for nachweis in quarterly_confirmations %} + + + + + + + + + + + {% endfor %} + +
    ZeitraumStatusFortschrittFristenAktionen
    + {{ nachweis.jahr }} Q{{ nachweis.quartal }} + {% if nachweis.is_overdue %}
    {% endif %} +
    + {% if nachweis.status == 'offen' %}Offen + {% elif nachweis.status == 'teilweise' %}Teilweise + {% elif nachweis.status == 'eingereicht' %}Eingereicht + {% elif nachweis.status == 'geprueft' %}Freigegeben + {% elif nachweis.status == 'auto_geprueft' %} Auto + {% elif nachweis.status == 'nachbesserung' %}Nachbesserung + {% elif nachweis.status == 'abgelehnt' %}Abgelehnt + {% endif %} + + {% with completion=nachweis.get_completion_percentage %} +
    +
    {{ completion }}%
    +
    + {% endwith %} +
    +
    + {% if nachweis.studiennachweis_faelligkeitsdatum %} +
    + {{ nachweis.studiennachweis_faelligkeitsdatum|date:"d.m.Y" }} + {% if nachweis.is_study_proof_overdue %}{% endif %} +
    + {% endif %} + {% if nachweis.zahlung_faelligkeitsdatum %} +
    + {{ nachweis.zahlung_faelligkeitsdatum|date:"d.m.Y" }} + {% if nachweis.is_payment_overdue %}{% endif %} +
    + {% endif %} +
    +
    + {% if nachweis.studiennachweis_eingereicht %} + {% if nachweis.studiennachweis_datei %} + {% elif nachweis.studiennachweis_bemerkung %} + {% else %}{% endif %} + {% else %}{% endif %} + + {% if nachweis.einkommenssituation_bestaetigt %} + {% if nachweis.einkommenssituation_datei %} + {% elif nachweis.einkommenssituation_text %} + {% else %}{% endif %} + {% else %}{% endif %} + + {% if nachweis.vermogenssituation_bestaetigt %} + {% if nachweis.vermogenssituation_datei %} + {% elif nachweis.vermogenssituation_text %} + {% else %}{% endif %} + {% else %}{% endif %} + +
    + + {% if user.is_staff %} + {% if nachweis.status == 'eingereicht' %} + + {% elif nachweis.status == 'geprueft' %} + + + {% endif %} + {% endif %} +
    +
    +
    + {% else %} +
    + +

    Keine Nachweise vorhanden.

    +
    + {% endif %} +
    + + {# ════════ TAB: Zahlungen ════════ #} +
    + + {% if unterstuetzungen %} +
    + + + + + + + + + + + + {% for u in unterstuetzungen %} + + + + + + + + {% endfor %} + +
    Faellig amBetragStatusBeschreibung
    {{ u.faellig_am|date:"d.m.Y" }}€{{ u.betrag|floatformat:2 }} + {% if u.status == 'ausgezahlt' %}Ausgezahlt + {% elif u.status == 'in_bearbeitung' %}In Bearbeitung + {% elif u.status == 'geplant' %}Geplant + {% else %}{{ u.get_status_display }}{% endif %} + {{ u.beschreibung|truncatechars:50 }}
    +
    + {% else %} +
    + +

    Keine Zahlungen vorhanden.

    +
    + {% endif %} + + {% if foerderungen %} +
    Foerderungen ({{ foerderungen.count }})
    +
    + + + + + + {% for f in foerderungen %} + + + + + + + + + {% endfor %} + +
    JahrBetragKategorieStatusNachweis
    {{ f.jahr }}€{{ f.betrag|floatformat:2 }}{{ f.get_kategorie_display }} + {% if f.status == 'bewilligt' %}Bewilligt + {% elif f.status == 'abgelehnt' %}Abgelehnt + {% elif f.status == 'in_bearbeitung' %}In Bearbeitung + {% else %}{{ f.get_status_display }}{% endif %} + {% if f.verwendungsnachweis %}{% else %}{% endif %}
    +
    + {% endif %} +
    + + {# ════════ TAB: Timeline ════════ #} +
    + {% if timeline_events %} +
    + {% for event in timeline_events %} +
    +
    +
    + +
    +
    +
    +
    + {{ event.titel }} + {{ event.datum|date:"d.m.Y" }} +
    + {% if event.beschreibung %}
    {{ event.beschreibung }}
    {% endif %} + {% if event.status %}{{ event.status }}{% endif %} +
    +
    + {% endfor %} +
    + {% else %} +
    + +

    Keine Ereignisse vorhanden.

    +
    + {% endif %} +
    + + {# ════════ TAB: Dokumente ════════ #} +
    + + {% if verknuepfte_dokumente %} +
    + + + + + + {% for d in verknuepfte_dokumente %} + + + + + + + {% endfor %} + +
    DokumentKontextBeschreibung
    {{ d.titel }}
    ID: {{ d.paperless_document_id }}
    {{ d.get_kontext_display }}{{ d.beschreibung|default:"-"|truncatewords:10 }} +
    + + + +
    +
    +
    + {% else %} +
    + +

    Keine Dokumente verknuepft.

    +
    + {% endif %} +
    + + {# ════════ TAB: Notizen ════════ #} +
    + + {% if notizen_eintraege %} +
    + {% for n in notizen_eintraege %} +
    +
    +
    + {{ n.erstellt_am|date:"d.m.Y H:i" }} + {% if n.erstellt_von %}- {{ n.erstellt_von.username }}{% endif %} +
    + {% if n.datei %}{% endif %} +
    + {% if n.titel %}
    {{ n.titel }}
    {% endif %} + {% if n.text %}
    {{ n.text|linebreaks }}
    {% endif %} +
    + {% endfor %} +
    + {% else %} +
    + +

    Keine Notizen vorhanden.

    +
    + {% endif %} +
    + +
    {# /tab-content #} +
    + +{# ── Add Quarter Modal ── #} + + {% endblock %} {% block javascript %} - -{% endblock %} +{% endblock %}