Files
stiftung-management-system/app/templates/stiftung/destinataer_timeline.html
SysAdmin Agent ee2c827d85 Phase 2: Destinatär-Timeline, Nachweis-Board, Zahlungs-Pipeline & Pächter-Workflow
2a. Destinatär-Timeline (/destinataere/<pk>/timeline/)
    - Chronologische Ansicht aller Events (Zahlungen, Nachweise, E-Mails, Notizen)
    - Filter nach Typ via GET-Parameter

2b. Nachweis-Board (/nachweis-board/)
    - Quartals-Übersicht aller aktiver Destinatäre (Q1–Q4) in einer Tabellenansicht
    - Batch-Erinnerung: erzeugt Audit-Log-Einträge für säumige Destinatäre
    - Semester-Logik erhalten (15.03 / 15.09 Fristen)

2c. Zahlungs-Pipeline (/zahlungs-pipeline/)
    - 5-Stufen-Kanban: Offen → Nachweis eingereicht → Freigegeben → Überwiesen → Abgeschlossen
    - Vier-Augen-Prinzip: can_be_freigegeben() prüft anderen Nutzer als Ersteller
    - SEPA pain.001 XML-Export (/sepa-export/) für freigegebene Zahlungen
    - Neue Status-Werte: nachweis_eingereicht, freigegeben, abgeschlossen
    - Neue Felder: freigegeben_von, freigegeben_am, erstellt_von

2d. Pächter-Workflow (/paechter/workflow/)
    - Pipeline nach Restlaufzeit: abgelaufen / <6M / 6–24M / >24M / unbefristet
    - Ausstehende Jahresabrechnungen (Vorjahr ohne Abrechnung)
    - Pachtanpassungen fällig (Verträge > 5 Jahre laufend)
    - Top-Pächter nach Gesamtfläche

Sidebar-Navigation um Pipeline, Nachweis-Board und Pacht-Workflow erweitert.
Migration 0047 erzeugt und angewendet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 10:40:43 +00:00

152 lines
7.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'base.html' %}
{% load static %}
{% block title %}Timeline {{ destinataer.get_full_name }} Stiftungsverwaltung{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3">
<i class="fas fa-stream text-primary me-2"></i>
Timeline: {{ destinataer.get_full_name }}
</h1>
<div>
<a href="{% url 'stiftung:destinataer_detail' pk=destinataer.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>Zum Destinatär
</a>
</div>
</div>
<!-- Filter Bar -->
<div class="card shadow mb-4">
<div class="card-body py-2">
<div class="d-flex gap-2 flex-wrap align-items-center">
<span class="text-muted small fw-bold me-2">Filter:</span>
<a href="?typ=" class="btn btn-sm {% if not typ_filter %}btn-primary{% else %}btn-outline-primary{% endif %}">
<i class="fas fa-list me-1"></i>Alle
</a>
<a href="?typ=zahlung" class="btn btn-sm {% if typ_filter == 'zahlung' %}btn-success{% else %}btn-outline-success{% endif %}">
<i class="fas fa-money-bill-wave me-1"></i>Zahlungen
</a>
<a href="?typ=nachweis" class="btn btn-sm {% if typ_filter == 'nachweis' %}btn-warning{% else %}btn-outline-warning{% endif %}">
<i class="fas fa-file-alt me-1"></i>Nachweise
</a>
<a href="?typ=email" class="btn btn-sm {% if typ_filter == 'email' %}btn-info{% else %}btn-outline-info{% endif %}">
<i class="fas fa-envelope me-1"></i>E-Mails
</a>
<a href="?typ=notiz" class="btn btn-sm {% if typ_filter == 'notiz' %}btn-secondary{% else %}btn-outline-secondary{% endif %}">
<i class="fas fa-sticky-note me-1"></i>Notizen
</a>
<span class="ms-auto text-muted small">{{ events|length }} Einträge</span>
</div>
</div>
</div>
<!-- Timeline -->
{% if events %}
<div class="timeline-wrapper">
{% for event in events %}
<div class="timeline-item mb-3">
<div class="card shadow-sm border-start border-4 border-{{ event.farbe }}">
<div class="card-body py-2 px-3">
<div class="d-flex align-items-start gap-3">
<!-- Icon -->
<div class="timeline-icon text-{{ event.farbe }} pt-1">
<i class="fas {{ event.icon }} fa-lg"></i>
</div>
<!-- Content -->
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-start">
<div>
<span class="fw-semibold">{{ event.titel }}</span>
{% if event.beschreibung %}
<span class="text-muted ms-2 small">{{ event.beschreibung }}</span>
{% endif %}
</div>
<div class="text-end ms-3 text-nowrap">
<div class="small text-muted">{{ event.datum|date:"d.m.Y" }}</div>
{% if event.status %}
<span class="badge bg-{{ event.farbe }} text-white small">{{ event.status }}</span>
{% endif %}
</div>
</div>
<!-- Extra info per type -->
{% if event.typ == 'zahlung' %}
<div class="small mt-1">
{% with u=event.objekt %}
Konto: {{ u.konto.kontoname }}
{% if u.empfaenger_iban %} · IBAN: {{ u.empfaenger_iban|slice:":4" }}…{% endif %}
{% if u.ausgezahlt_von %} · Ausgezahlt von: {{ u.ausgezahlt_von.get_full_name|default:u.ausgezahlt_von.username }}{% endif %}
{% if u.freigegeben_von %} · Freigegeben: {{ u.freigegeben_von.get_full_name|default:u.freigegeben_von.username }} ({{ u.freigegeben_am|date:"d.m.Y" }}){% endif %}
{% endwith %}
</div>
{% elif event.typ == 'nachweis' %}
<div class="small mt-1">
{% with n=event.objekt %}
Fortschritt: {{ n.get_completion_percentage }}%
{% if n.geprueft_von %} · Geprüft von: {{ n.geprueft_von.get_full_name|default:n.geprueft_von.username }}{% endif %}
{% endwith %}
</div>
{% elif event.typ == 'email' %}
<div class="small mt-1">
{% with e=event.objekt %}
Von: {{ e.absender_name|default:e.absender_email }}
{% if e.quartalsnachweis %} · Zugeordnet: Q{{ e.quartalsnachweis.quartal }}/{{ e.quartalsnachweis.jahr }}{% endif %}
{% endwith %}
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
Keine Timeline-Einträge vorhanden{% if typ_filter %} für den gewählten Filter{% endif %}.
</div>
{% endif %}
</div>
</div>
<style>
.timeline-wrapper {
position: relative;
}
.timeline-wrapper::before {
content: '';
position: absolute;
left: 20px;
top: 0;
bottom: 0;
width: 2px;
background: #dee2e6;
z-index: 0;
}
.timeline-item {
position: relative;
padding-left: 48px;
}
.timeline-icon {
position: absolute;
left: -28px;
top: 50%;
transform: translateY(-50%);
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: white;
border-radius: 50%;
border: 2px solid #dee2e6;
z-index: 1;
}
</style>
{% endblock %}