Implement modular report system with 6 report types and composer UI
Refactors the Berichte section from a single hardcoded Jahresbericht into a modular report-building system. Jahresbericht now uses PDFGenerator for corporate identity (logo, colors, headers/footers, cover page). 8 reusable section templates can be freely combined. 6 predefined report templates (Jahres-, Destinatär-, Grundstücks-, Finanz-, Förder-, Pachtbericht) with HTML preview and PDF export. New Bericht-Baukasten UI lets users compose custom reports from individual sections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,16 @@ urlpatterns = [
|
||||
views.jahresbericht_pdf,
|
||||
name="jahresbericht_pdf",
|
||||
),
|
||||
path(
|
||||
"berichte/zusammenstellen/",
|
||||
views.bericht_zusammenstellen,
|
||||
name="bericht_zusammenstellen",
|
||||
),
|
||||
path(
|
||||
"berichte/<str:vorlage_key>/",
|
||||
views.bericht_vorlage,
|
||||
name="bericht_vorlage",
|
||||
),
|
||||
# Geschäftsführung URLs
|
||||
path("geschaeftsfuehrung/", views.geschaeftsfuehrung, name="geschaeftsfuehrung"),
|
||||
path("geschaeftsfuehrung/konten/", views.konto_list, name="konto_list"),
|
||||
|
||||
@@ -29,6 +29,10 @@ from .finanzen import ( # noqa: F401
|
||||
jahresbericht_generate,
|
||||
jahresbericht_generate_redirect,
|
||||
jahresbericht_pdf,
|
||||
bericht_zusammenstellen,
|
||||
bericht_vorlage,
|
||||
BERICHT_SEKTIONEN,
|
||||
BERICHT_VORLAGEN,
|
||||
geschaeftsfuehrung,
|
||||
konto_list,
|
||||
verwaltungskosten_list,
|
||||
|
||||
@@ -59,7 +59,7 @@ from stiftung.forms import (
|
||||
|
||||
@login_required
|
||||
def bericht_list(request):
|
||||
"""List available reports"""
|
||||
"""List available reports with modular report builder"""
|
||||
# Get available years from data
|
||||
jahre = sorted(
|
||||
set(
|
||||
@@ -69,7 +69,7 @@ def bericht_list(request):
|
||||
reverse=True,
|
||||
)
|
||||
|
||||
# Statistics for overview tiles (removed legacy Person and Verpachtung)
|
||||
# Statistics for overview tiles
|
||||
total_destinataere = Destinataer.objects.count()
|
||||
total_laendereien = Land.objects.count()
|
||||
total_verpachtungen = LandVerpachtung.objects.count()
|
||||
@@ -82,10 +82,25 @@ def bericht_list(request):
|
||||
"total_laendereien": total_laendereien,
|
||||
"total_verpachtungen": total_verpachtungen,
|
||||
"total_foerderungen": total_foerderungen,
|
||||
"bericht_vorlagen": BERICHT_VORLAGEN,
|
||||
"bericht_sektionen": BERICHT_SEKTIONEN,
|
||||
}
|
||||
return render(request, "stiftung/bericht_list.html", context)
|
||||
|
||||
|
||||
def _get_corporate_context():
|
||||
"""Holt Corporate-Identity-Einstellungen und CSS für Berichte."""
|
||||
from stiftung.utils.pdf_generator import pdf_generator
|
||||
corporate_settings = pdf_generator.get_corporate_settings()
|
||||
logo_base64 = pdf_generator.get_logo_base64(corporate_settings.get("logo_path", ""))
|
||||
css_content = pdf_generator.get_base_css(corporate_settings)
|
||||
return {
|
||||
"corporate_settings": corporate_settings,
|
||||
"logo_base64": logo_base64,
|
||||
"css_content": css_content,
|
||||
}
|
||||
|
||||
|
||||
def _jahresbericht_context(jahr):
|
||||
"""Phase 4: Aggregiert alle Daten für den Jahresbericht."""
|
||||
from stiftung.models import (
|
||||
@@ -138,7 +153,7 @@ def _jahresbericht_context(jahr):
|
||||
total_ausgaben = total_ausgaben_foerderung + total_verwaltungskosten
|
||||
netto = total_einnahmen - total_ausgaben
|
||||
|
||||
return {
|
||||
context = {
|
||||
"jahr": jahr,
|
||||
"title": f"Jahresbericht {jahr}",
|
||||
"foerderungen": foerderungen,
|
||||
@@ -157,9 +172,14 @@ def _jahresbericht_context(jahr):
|
||||
"total_einnahmen": total_einnahmen,
|
||||
"total_ausgaben": total_ausgaben,
|
||||
"netto": netto,
|
||||
# Rückwärtskompatibilität
|
||||
"total_foerderungen": total_ausgaben_foerderung,
|
||||
"show_cover": True,
|
||||
"bericht_titel": f"Jahresbericht {jahr}",
|
||||
"bericht_untertitel": "Gesamtübersicht des Geschäftsjahres",
|
||||
"berichtszeitraum": str(jahr),
|
||||
}
|
||||
context.update(_get_corporate_context())
|
||||
return context
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -181,24 +201,276 @@ def jahresbericht_generate_redirect(request):
|
||||
|
||||
@login_required
|
||||
def jahresbericht_pdf(request, jahr):
|
||||
"""Phase 4: PDF-Export des Jahresberichts."""
|
||||
from django.http import HttpResponse
|
||||
"""Phase 4: PDF-Export des Jahresberichts via PDFGenerator."""
|
||||
from django.template.loader import render_to_string
|
||||
from weasyprint import HTML
|
||||
from stiftung.utils.pdf_generator import pdf_generator
|
||||
|
||||
context = _jahresbericht_context(jahr)
|
||||
|
||||
# Render HTML
|
||||
html_string = render_to_string("stiftung/jahresbericht.html", context)
|
||||
return pdf_generator.generate_pdf_response(
|
||||
html_string, f"jahresbericht_{jahr}.pdf", context.get("css_content")
|
||||
)
|
||||
|
||||
# Generate PDF
|
||||
pdf = HTML(string=html_string).write_pdf()
|
||||
|
||||
# Create response
|
||||
response = HttpResponse(pdf, content_type="application/pdf")
|
||||
response["Content-Disposition"] = f'attachment; filename="jahresbericht_{jahr}.pdf"'
|
||||
# =============================================================================
|
||||
# MODULARE BERICHTE – Berichts-Baukasten
|
||||
# =============================================================================
|
||||
|
||||
return response
|
||||
# Verfügbare Sektionen mit Metadaten
|
||||
BERICHT_SEKTIONEN = {
|
||||
"bilanz": {"label": "Jahresbilanz", "icon": "fa-balance-scale", "needs_jahr": True},
|
||||
"unterstuetzungen": {"label": "Unterstützungszahlungen", "icon": "fa-hand-holding-heart", "needs_jahr": True},
|
||||
"foerderungen": {"label": "Förderungen", "icon": "fa-gift", "needs_jahr": True},
|
||||
"grundstuecke": {"label": "Grundstücksverwaltung", "icon": "fa-map", "needs_jahr": True},
|
||||
"verwaltungskosten": {"label": "Verwaltungskosten", "icon": "fa-file-invoice-dollar", "needs_jahr": True},
|
||||
"destinataere_uebersicht": {"label": "Destinatär-Übersicht", "icon": "fa-users", "needs_jahr": False},
|
||||
"konten_uebersicht": {"label": "Kontenübersicht", "icon": "fa-university", "needs_jahr": False},
|
||||
"verpachtungen": {"label": "Pachtbericht", "icon": "fa-handshake", "needs_jahr": False},
|
||||
}
|
||||
|
||||
# Vordefinierte Berichtstypen
|
||||
BERICHT_VORLAGEN = {
|
||||
"jahresbericht": {
|
||||
"label": "Jahresbericht",
|
||||
"beschreibung": "Vollständige Übersicht eines Geschäftsjahres",
|
||||
"sektionen": ["bilanz", "unterstuetzungen", "foerderungen", "grundstuecke", "verwaltungskosten"],
|
||||
"needs_jahr": True,
|
||||
"icon": "fa-calendar-alt",
|
||||
},
|
||||
"destinataerbericht": {
|
||||
"label": "Destinatärbericht",
|
||||
"beschreibung": "Übersicht aller Destinatäre mit Förderstatus",
|
||||
"sektionen": ["destinataere_uebersicht", "unterstuetzungen", "foerderungen"],
|
||||
"needs_jahr": True,
|
||||
"icon": "fa-users",
|
||||
},
|
||||
"grundstuecksbericht": {
|
||||
"label": "Grundstücksbericht",
|
||||
"beschreibung": "Liegenschaftsübersicht mit Pachtverträgen",
|
||||
"sektionen": ["grundstuecke", "verpachtungen"],
|
||||
"needs_jahr": True,
|
||||
"icon": "fa-map",
|
||||
},
|
||||
"finanzbericht": {
|
||||
"label": "Finanzbericht",
|
||||
"beschreibung": "Einnahmen/Ausgaben und Kontenübersicht",
|
||||
"sektionen": ["bilanz", "konten_uebersicht", "verwaltungskosten"],
|
||||
"needs_jahr": True,
|
||||
"icon": "fa-euro-sign",
|
||||
},
|
||||
"foerderbericht": {
|
||||
"label": "Förderbericht",
|
||||
"beschreibung": "Detailansicht aller Förderungen",
|
||||
"sektionen": ["foerderungen", "unterstuetzungen"],
|
||||
"needs_jahr": True,
|
||||
"icon": "fa-gift",
|
||||
},
|
||||
"pachtbericht": {
|
||||
"label": "Pachtbericht",
|
||||
"beschreibung": "Pachtzinseinnahmen und Vertragsübersicht",
|
||||
"sektionen": ["verpachtungen", "grundstuecke"],
|
||||
"needs_jahr": True,
|
||||
"icon": "fa-handshake",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _build_section_context(sektionen, jahr=None):
|
||||
"""Baut den Context für die gewählten Sektionen zusammen."""
|
||||
from stiftung.models import (
|
||||
DestinataerUnterstuetzung, LandAbrechnung, Verwaltungskosten,
|
||||
)
|
||||
context = {}
|
||||
|
||||
if jahr:
|
||||
context["jahr"] = jahr
|
||||
|
||||
needs_jahresbericht = any(s in sektionen for s in [
|
||||
"bilanz", "unterstuetzungen", "foerderungen", "grundstuecke", "verwaltungskosten"
|
||||
])
|
||||
if needs_jahresbericht and jahr:
|
||||
jb = _jahresbericht_context(jahr)
|
||||
context.update(jb)
|
||||
|
||||
if "destinataere_uebersicht" in sektionen:
|
||||
from django.db.models import Count, Sum as DSum
|
||||
qs = Destinataer.objects.all()
|
||||
context["destinataere_aktiv"] = qs.filter(aktiv=True).count()
|
||||
context["destinataere_gesamt"] = qs.count()
|
||||
|
||||
# Annotate with support stats
|
||||
if jahr:
|
||||
dest_qs = qs.annotate(
|
||||
unterstuetzung_count=Count(
|
||||
"unterstuetzungen",
|
||||
filter=Q(unterstuetzungen__faellig_am__year=jahr),
|
||||
),
|
||||
unterstuetzung_summe=Coalesce(
|
||||
DSum(
|
||||
"unterstuetzungen__betrag",
|
||||
filter=Q(
|
||||
unterstuetzungen__faellig_am__year=jahr,
|
||||
unterstuetzungen__status__in=["ausgezahlt", "abgeschlossen"],
|
||||
),
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
)
|
||||
else:
|
||||
dest_qs = qs.annotate(
|
||||
unterstuetzung_count=Count("unterstuetzungen"),
|
||||
unterstuetzung_summe=Coalesce(
|
||||
DSum(
|
||||
"unterstuetzungen__betrag",
|
||||
filter=Q(unterstuetzungen__status__in=["ausgezahlt", "abgeschlossen"]),
|
||||
),
|
||||
Decimal("0"),
|
||||
),
|
||||
)
|
||||
context["destinataere_liste"] = dest_qs.order_by("nachname", "vorname")
|
||||
context["destinataere_total_unterstuetzung"] = (
|
||||
dest_qs.aggregate(total=DSum("unterstuetzung_summe"))["total"] or 0
|
||||
)
|
||||
|
||||
if "konten_uebersicht" in sektionen:
|
||||
konten = StiftungsKonto.objects.filter(aktiv=True).order_by("bank_name", "kontoname")
|
||||
context["konten_liste"] = konten
|
||||
context["konten_anzahl"] = konten.count()
|
||||
context["konten_gesamtsaldo"] = konten.aggregate(total=Sum("saldo"))["total"] or 0
|
||||
|
||||
if "verpachtungen" in sektionen:
|
||||
from datetime import timedelta
|
||||
heute = date.today()
|
||||
in_12_monaten = heute + timedelta(days=365)
|
||||
|
||||
aktive = LandVerpachtung.objects.filter(
|
||||
status="aktiv"
|
||||
).select_related("land", "paechter")
|
||||
|
||||
auslaufend = aktive.filter(
|
||||
pachtende__isnull=False,
|
||||
pachtende__lte=in_12_monaten,
|
||||
pachtende__gte=heute,
|
||||
).order_by("pachtende")
|
||||
|
||||
total_flaeche = aktive.aggregate(total=Sum("verpachtete_flaeche"))["total"] or 0
|
||||
total_pz = aktive.aggregate(total=Sum("pachtzins_pauschal"))["total"] or 0
|
||||
|
||||
context["pacht_statistik"] = {
|
||||
"aktive_vertraege": aktive.count(),
|
||||
"total_pachtzins": total_pz,
|
||||
"total_flaeche": total_flaeche,
|
||||
"auslaufend_12m": auslaufend.count(),
|
||||
}
|
||||
context["pacht_auslaufend"] = auslaufend
|
||||
# Also provide full list if not already from jahresbericht
|
||||
if "verpachtungen" not in context or not context.get("verpachtungen"):
|
||||
if jahr:
|
||||
context["verpachtungen"] = LandVerpachtung.objects.filter(
|
||||
pachtbeginn__year__lte=jahr
|
||||
).filter(
|
||||
Q(pachtende__isnull=True) | Q(pachtende__year__gte=jahr)
|
||||
).select_related("land", "paechter")
|
||||
else:
|
||||
context["verpachtungen"] = aktive
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@login_required
|
||||
def bericht_zusammenstellen(request):
|
||||
"""Modularer Bericht: Sektionen auswählen und zusammenstellen."""
|
||||
if request.method == "POST":
|
||||
sektionen = request.POST.getlist("sektionen")
|
||||
jahr_str = request.POST.get("jahr", "")
|
||||
show_cover = request.POST.get("show_cover") == "on"
|
||||
output_format = request.POST.get("format", "html")
|
||||
vorlage = request.POST.get("vorlage", "")
|
||||
|
||||
# Vorlage anwenden falls gewählt
|
||||
if vorlage and vorlage in BERICHT_VORLAGEN and not sektionen:
|
||||
sektionen = BERICHT_VORLAGEN[vorlage]["sektionen"]
|
||||
|
||||
if not sektionen:
|
||||
messages.error(request, "Bitte wählen Sie mindestens eine Sektion aus.")
|
||||
return redirect("stiftung:bericht_list")
|
||||
|
||||
jahr = int(jahr_str) if jahr_str and jahr_str.isdigit() else None
|
||||
|
||||
# Build context
|
||||
context = _build_section_context(sektionen, jahr)
|
||||
context["sektionen"] = sektionen
|
||||
context["show_cover"] = show_cover
|
||||
|
||||
# Set titles
|
||||
if vorlage and vorlage in BERICHT_VORLAGEN:
|
||||
titel = BERICHT_VORLAGEN[vorlage]["label"]
|
||||
else:
|
||||
titel = "Bericht"
|
||||
if jahr:
|
||||
context["bericht_titel"] = f"{titel} {jahr}"
|
||||
context["berichtszeitraum"] = str(jahr)
|
||||
else:
|
||||
context["bericht_titel"] = titel
|
||||
context["berichtszeitraum"] = "Aktuell"
|
||||
|
||||
context["bericht_untertitel"] = BERICHT_VORLAGEN.get(vorlage, {}).get("beschreibung", "")
|
||||
|
||||
# Add corporate context if not already present
|
||||
if "corporate_settings" not in context:
|
||||
context.update(_get_corporate_context())
|
||||
|
||||
if output_format == "pdf":
|
||||
from django.template.loader import render_to_string
|
||||
from stiftung.utils.pdf_generator import pdf_generator
|
||||
html_string = render_to_string("berichte/bericht_modular.html", context)
|
||||
filename = f"bericht_{vorlage or 'custom'}_{jahr or 'aktuell'}.pdf"
|
||||
return pdf_generator.generate_pdf_response(
|
||||
html_string, filename, context.get("css_content")
|
||||
)
|
||||
else:
|
||||
return render(request, "berichte/bericht_modular.html", context)
|
||||
|
||||
# GET: Redirect to bericht_list
|
||||
return redirect("stiftung:bericht_list")
|
||||
|
||||
|
||||
@login_required
|
||||
def bericht_vorlage(request, vorlage_key):
|
||||
"""Schnellzugriff: Vordefinierte Berichtsvorlage generieren."""
|
||||
if vorlage_key not in BERICHT_VORLAGEN:
|
||||
messages.error(request, f"Unbekannter Berichtstyp: {vorlage_key}")
|
||||
return redirect("stiftung:bericht_list")
|
||||
|
||||
vorlage = BERICHT_VORLAGEN[vorlage_key]
|
||||
jahr_str = request.GET.get("jahr", "")
|
||||
jahr = int(jahr_str) if jahr_str and jahr_str.isdigit() else None
|
||||
output_format = request.GET.get("format", "html")
|
||||
|
||||
if vorlage["needs_jahr"] and not jahr:
|
||||
messages.error(request, "Bitte wählen Sie ein Jahr für diesen Bericht.")
|
||||
return redirect("stiftung:bericht_list")
|
||||
|
||||
context = _build_section_context(vorlage["sektionen"], jahr)
|
||||
context["sektionen"] = vorlage["sektionen"]
|
||||
context["show_cover"] = True
|
||||
context["bericht_titel"] = f"{vorlage['label']}" + (f" {jahr}" if jahr else "")
|
||||
context["bericht_untertitel"] = vorlage["beschreibung"]
|
||||
context["berichtszeitraum"] = str(jahr) if jahr else "Aktuell"
|
||||
|
||||
if "corporate_settings" not in context:
|
||||
context.update(_get_corporate_context())
|
||||
|
||||
if output_format == "pdf":
|
||||
from django.template.loader import render_to_string
|
||||
from stiftung.utils.pdf_generator import pdf_generator
|
||||
html_string = render_to_string("berichte/bericht_modular.html", context)
|
||||
filename = f"{vorlage_key}_{jahr or 'aktuell'}.pdf"
|
||||
return pdf_generator.generate_pdf_response(
|
||||
html_string, filename, context.get("css_content")
|
||||
)
|
||||
else:
|
||||
return render(request, "berichte/bericht_modular.html", context)
|
||||
|
||||
|
||||
# API Views for AJAX
|
||||
|
||||
109
app/templates/berichte/bericht_modular.html
Normal file
109
app/templates/berichte/bericht_modular.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ bericht_titel }} – {{ corporate_settings.stiftung_name }}</title>
|
||||
<style>
|
||||
{{ css_content }}
|
||||
/* Cover page styles */
|
||||
.cover-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 85vh;
|
||||
text-align: center;
|
||||
}
|
||||
.cover-logo-img { max-height: 100px; max-width: 250px; margin-bottom: 30px; }
|
||||
.cover-title h1 {
|
||||
font-size: 24pt;
|
||||
color: {{ corporate_settings.primary_color|default:"#2c3e50" }};
|
||||
margin: 0 0 10px 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
.cover-title h2 {
|
||||
font-size: 18pt;
|
||||
color: {{ corporate_settings.secondary_color|default:"#3498db" }};
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
.cover-subtitle { font-size: 12pt; color: #666; }
|
||||
.cover-meta { margin-top: 40px; font-size: 11pt; color: #555; }
|
||||
.cover-meta p { margin: 5px 0; }
|
||||
.cover-footer { margin-top: 60px; font-size: 9pt; color: #999; }
|
||||
.cover-footer p { margin: 3px 0; }
|
||||
.cover-confidential {
|
||||
margin-top: 15px !important;
|
||||
font-weight: bold;
|
||||
color: {{ corporate_settings.primary_color|default:"#2c3e50" }} !important;
|
||||
font-size: 10pt;
|
||||
}
|
||||
/* Bilanz cards */
|
||||
.bilanz-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.bilanz-card { border-radius: 8px; padding: 16px; text-align: center; }
|
||||
.bilanz-card.einnahmen { background: #d4edda; border: 1px solid #c3e6cb; }
|
||||
.bilanz-card.ausgaben { background: #f8d7da; border: 1px solid #f5c6cb; }
|
||||
.bilanz-card.netto-positiv { background: #d1ecf1; border: 1px solid #bee5eb; }
|
||||
.bilanz-card.netto-negativ { background: #fff3cd; border: 1px solid #ffeeba; }
|
||||
.bilanz-card .value { font-size: 1.5em; font-weight: bold; }
|
||||
.bilanz-card .label { font-size: 0.85em; margin-top: 4px; color: #555; }
|
||||
/* Status badges extra */
|
||||
.status-aktiv { background-color: #d4edda; color: #155724; }
|
||||
.status-beendet { background-color: #e2e3e5; color: #383d41; }
|
||||
.status-gekuendigt { background-color: #f8d7da; color: #721c24; }
|
||||
.status-geplant, .status-faellig { background-color: #e2e3e5; color: #383d41; }
|
||||
.status-abgeschlossen { background-color: #d4edda; color: #155724; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% if show_cover %}
|
||||
{% include "berichte/cover_page.html" %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Kopfzeile (auf jeder Seite nach dem Deckblatt) -->
|
||||
<div class="header">
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
{% if logo_base64 %}
|
||||
<img src="{{ logo_base64 }}" alt="Logo" class="logo">
|
||||
{% endif %}
|
||||
<p class="stiftung-name">{{ corporate_settings.stiftung_name }}</p>
|
||||
<p class="document-title">{{ bericht_titel }}</p>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="contact-info">
|
||||
{% if corporate_settings.address_line1 %}<p>{{ corporate_settings.address_line1 }}</p>{% endif %}
|
||||
{% if corporate_settings.address_line2 %}<p>{{ corporate_settings.address_line2 }}</p>{% endif %}
|
||||
{% if corporate_settings.phone %}<p>{{ corporate_settings.phone }}</p>{% endif %}
|
||||
{% if corporate_settings.email %}<p>{{ corporate_settings.email }}</p>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-info">
|
||||
Erstellt am {% now "d.m.Y" %}{% if berichtszeitraum %} · Zeitraum: {{ berichtszeitraum }}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dynamische Sektionen -->
|
||||
{% for sektion in sektionen %}
|
||||
{% if sektion == "bilanz" %}{% include "berichte/sektionen/bilanz.html" %}
|
||||
{% elif sektion == "unterstuetzungen" %}{% include "berichte/sektionen/unterstuetzungen.html" %}
|
||||
{% elif sektion == "foerderungen" %}{% include "berichte/sektionen/foerderungen.html" %}
|
||||
{% elif sektion == "grundstuecke" %}{% include "berichte/sektionen/grundstuecke.html" %}
|
||||
{% elif sektion == "verwaltungskosten" %}{% include "berichte/sektionen/verwaltungskosten.html" %}
|
||||
{% elif sektion == "destinataere_uebersicht" %}{% include "berichte/sektionen/destinataere_uebersicht.html" %}
|
||||
{% elif sektion == "konten_uebersicht" %}{% include "berichte/sektionen/konten_uebersicht.html" %}
|
||||
{% elif sektion == "verpachtungen" %}{% include "berichte/sektionen/verpachtungen.html" %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<div class="footer">
|
||||
<p>{{ bericht_titel }} — automatisch generiert von der Stiftungsverwaltung</p>
|
||||
<p>{{ corporate_settings.stiftung_name }} · {{ corporate_settings.footer_text }}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
39
app/templates/berichte/cover_page.html
Normal file
39
app/templates/berichte/cover_page.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!-- Deckblatt / Cover Page für Berichte -->
|
||||
<div class="cover-page">
|
||||
<div class="cover-logo">
|
||||
{% if logo_base64 %}
|
||||
<img src="{{ logo_base64 }}" alt="Logo" class="cover-logo-img">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="cover-title">
|
||||
<h1>{{ corporate_settings.stiftung_name }}</h1>
|
||||
<h2>{{ bericht_titel }}</h2>
|
||||
{% if bericht_untertitel %}
|
||||
<p class="cover-subtitle">{{ bericht_untertitel }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="cover-meta">
|
||||
<p><strong>Berichtszeitraum:</strong> {{ berichtszeitraum }}</p>
|
||||
<p><strong>Erstellt am:</strong> {% now "d.m.Y" %}</p>
|
||||
{% if cover_freitext %}
|
||||
<p>{{ cover_freitext }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="cover-footer">
|
||||
{% if corporate_settings.address_line1 %}
|
||||
<p>{{ corporate_settings.address_line1 }}</p>
|
||||
{% endif %}
|
||||
{% if corporate_settings.address_line2 %}
|
||||
<p>{{ corporate_settings.address_line2 }}</p>
|
||||
{% endif %}
|
||||
{% if corporate_settings.phone or corporate_settings.email %}
|
||||
<p>
|
||||
{% if corporate_settings.phone %}Tel.: {{ corporate_settings.phone }}{% endif %}
|
||||
{% if corporate_settings.phone and corporate_settings.email %} · {% endif %}
|
||||
{% if corporate_settings.email %}{{ corporate_settings.email }}{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="cover-confidential">Vertraulich</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="page-break-after: always;"></div>
|
||||
36
app/templates/berichte/sektionen/bilanz.html
Normal file
36
app/templates/berichte/sektionen/bilanz.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!-- Sektion: Jahresbilanz -->
|
||||
<div class="section">
|
||||
<h2>Jahresbilanz {{ jahr }}</h2>
|
||||
<div class="bilanz-grid">
|
||||
<div class="bilanz-card einnahmen">
|
||||
<div class="value">€{{ total_einnahmen|floatformat:2 }}</div>
|
||||
<div class="label">Einnahmen (Pacht)</div>
|
||||
</div>
|
||||
<div class="bilanz-card ausgaben">
|
||||
<div class="value">€{{ total_ausgaben|floatformat:2 }}</div>
|
||||
<div class="label">Ausgaben gesamt</div>
|
||||
</div>
|
||||
<div class="bilanz-card {% if netto >= 0 %}netto-positiv{% else %}netto-negativ{% endif %}">
|
||||
<div class="value">{% if netto >= 0 %}+{% endif %}€{{ netto|floatformat:2 }}</div>
|
||||
<div class="label">Nettosaldo</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ total_ausgaben_foerderung|floatformat:2 }}</div>
|
||||
<div class="label">Förderausgaben</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ total_verwaltungskosten|floatformat:2 }}</div>
|
||||
<div class="label">Verwaltungskosten</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ pacht_vereinnahmt|floatformat:2 }}</div>
|
||||
<div class="label">Pacht vereinnahmt</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ grundsteuer_gesamt|floatformat:2 }}</div>
|
||||
<div class="label">Grundsteuer</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
<!-- Sektion: Destinatär-Übersicht -->
|
||||
<div class="section">
|
||||
<h2>Destinatär-Übersicht{% if jahr %} {{ jahr }}{% endif %}</h2>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="value">{{ destinataere_aktiv }}</div>
|
||||
<div class="label">Aktive Destinatäre</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">{{ destinataere_gesamt }}</div>
|
||||
<div class="label">Gesamt</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ destinataere_total_unterstuetzung|floatformat:2 }}</div>
|
||||
<div class="label">Gesamte Unterstützungen</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if destinataere_liste %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Ort</th>
|
||||
<th>Berufsgruppe</th>
|
||||
<th>Aktiv</th>
|
||||
<th>Unterstützungen</th>
|
||||
<th>Betrag gesamt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for d in destinataere_liste %}
|
||||
<tr>
|
||||
<td>{{ d.get_full_name }}</td>
|
||||
<td>{{ d.ort|default:"-" }}</td>
|
||||
<td>{{ d.get_berufsgruppe_display|default:"-" }}</td>
|
||||
<td>{% if d.aktiv %}Ja{% else %}Nein{% endif %}</td>
|
||||
<td>{{ d.unterstuetzung_count }}</td>
|
||||
<td class="amount">€{{ d.unterstuetzung_summe|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
41
app/templates/berichte/sektionen/foerderungen.html
Normal file
41
app/templates/berichte/sektionen/foerderungen.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- Sektion: Förderungen (Legacy) -->
|
||||
{% if foerderungen %}
|
||||
<div class="section">
|
||||
<h2>Förderungen {{ jahr }}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Begünstigter</th>
|
||||
<th>Kategorie</th>
|
||||
<th>Betrag</th>
|
||||
<th>Status</th>
|
||||
<th>Antragsdatum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for f in foerderungen %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if f.destinataer %}{{ f.destinataer.get_full_name }}
|
||||
{% elif f.person %}{{ f.person.get_full_name }}
|
||||
{% else %}–{% endif %}
|
||||
</td>
|
||||
<td>{{ f.get_kategorie_display }}</td>
|
||||
<td class="amount">€{{ f.betrag|floatformat:2 }}</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ f.status }}">{{ f.get_status_display }}</span>
|
||||
</td>
|
||||
<td>{{ f.antragsdatum|date:"d.m.Y" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="2">Summe</td>
|
||||
<td class="amount">€{{ total_foerderungen_legacy|floatformat:2 }}</td>
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
76
app/templates/berichte/sektionen/grundstuecke.html
Normal file
76
app/templates/berichte/sektionen/grundstuecke.html
Normal file
@@ -0,0 +1,76 @@
|
||||
<!-- Sektion: Grundstücksverwaltung -->
|
||||
<div class="section">
|
||||
<h2>Grundstücksverwaltung</h2>
|
||||
|
||||
{% if verpachtungen %}
|
||||
<h3>Aktive Verpachtungen</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Länderei</th>
|
||||
<th>Pächter</th>
|
||||
<th>Verpachtete Fläche</th>
|
||||
<th>Jahrespachtzins</th>
|
||||
<th>Pachtende</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for v in verpachtungen %}
|
||||
<tr>
|
||||
<td>{{ v.land }}</td>
|
||||
<td>{{ v.paechter.get_full_name }}</td>
|
||||
<td class="amount">{{ v.verpachtete_flaeche|floatformat:0 }} qm</td>
|
||||
<td class="amount">€{{ v.pachtzins_pauschal|floatformat:2 }}</td>
|
||||
<td>{% if v.pachtende %}{{ v.pachtende|date:"d.m.Y" }}{% else %}unbefristet{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="3">Gesamtpachtzins (kalkuliert)</td>
|
||||
<td class="amount">€{{ total_pachtzins|floatformat:2 }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if landabrechnungen %}
|
||||
<h3>Landabrechnungen {{ jahr }}</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Länderei</th>
|
||||
<th>Pacht vereinnahmt</th>
|
||||
<th>Umlagen</th>
|
||||
<th>Grundsteuer</th>
|
||||
<th>Sonstige Einnahmen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for a in landabrechnungen %}
|
||||
<tr>
|
||||
<td>{{ a.land }}</td>
|
||||
<td class="amount">€{{ a.pacht_vereinnahmt|floatformat:2 }}</td>
|
||||
<td class="amount">€{{ a.umlagen_vereinnahmt|floatformat:2 }}</td>
|
||||
<td class="amount">€{{ a.grundsteuer_betrag|floatformat:2 }}</td>
|
||||
<td class="amount">€{{ a.sonstige_einnahmen|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td>Summe</td>
|
||||
<td class="amount">€{{ pacht_vereinnahmt|floatformat:2 }}</td>
|
||||
<td></td>
|
||||
<td class="amount">€{{ grundsteuer_gesamt|floatformat:2 }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if not verpachtungen and not landabrechnungen %}
|
||||
<p style="color: #999;">Keine Verpachtungs- oder Abrechnungsdaten für {{ jahr }} vorhanden.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
46
app/templates/berichte/sektionen/konten_uebersicht.html
Normal file
46
app/templates/berichte/sektionen/konten_uebersicht.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!-- Sektion: Konten-Übersicht -->
|
||||
<div class="section">
|
||||
<h2>Kontenübersicht</h2>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="value">{{ konten_anzahl }}</div>
|
||||
<div class="label">Aktive Konten</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ konten_gesamtsaldo|floatformat:2 }}</div>
|
||||
<div class="label">Gesamtsaldo</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if konten_liste %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kontoname</th>
|
||||
<th>Bank</th>
|
||||
<th>Kontotyp</th>
|
||||
<th>IBAN</th>
|
||||
<th>Saldo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k in konten_liste %}
|
||||
<tr>
|
||||
<td>{{ k.kontoname }}</td>
|
||||
<td>{{ k.bank_name }}</td>
|
||||
<td>{{ k.get_konto_typ_display }}</td>
|
||||
<td>{{ k.iban|default:"-" }}</td>
|
||||
<td class="amount">€{{ k.saldo|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="4">Gesamtsaldo</td>
|
||||
<td class="amount">€{{ konten_gesamtsaldo|floatformat:2 }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
41
app/templates/berichte/sektionen/unterstuetzungen.html
Normal file
41
app/templates/berichte/sektionen/unterstuetzungen.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- Sektion: Unterstützungszahlungen -->
|
||||
{% if unterstuetzungen %}
|
||||
<div class="section">
|
||||
<h2>Unterstützungszahlungen {{ jahr }}</h2>
|
||||
<p style="color: #666; margin-bottom: 12px;">
|
||||
{{ unterstuetzungen.count }} Unterstützung(en) geplant/ausgezahlt ·
|
||||
{{ unterstuetzungen_ausgezahlt.count }} überwiesen (€{{ total_unterstuetzungen|floatformat:2 }})
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Destinatär</th>
|
||||
<th>Betrag</th>
|
||||
<th>Fällig am</th>
|
||||
<th>Status</th>
|
||||
<th>Verwendungszweck</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in unterstuetzungen %}
|
||||
<tr>
|
||||
<td>{{ u.destinataer.get_full_name }}</td>
|
||||
<td class="amount">€{{ u.betrag|floatformat:2 }}</td>
|
||||
<td>{{ u.faellig_am|date:"d.m.Y" }}</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ u.status }}">{{ u.get_status_display }}</span>
|
||||
</td>
|
||||
<td>{{ u.beschreibung|default:"-" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td>Summe ausgezahlt</td>
|
||||
<td class="amount">€{{ total_unterstuetzungen|floatformat:2 }}</td>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
88
app/templates/berichte/sektionen/verpachtungen.html
Normal file
88
app/templates/berichte/sektionen/verpachtungen.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<!-- Sektion: Pachtbericht -->
|
||||
<div class="section">
|
||||
<h2>Pachtbericht{% if jahr %} {{ jahr }}{% endif %}</h2>
|
||||
|
||||
{% if pacht_statistik %}
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="value">{{ pacht_statistik.aktive_vertraege }}</div>
|
||||
<div class="label">Aktive Pachtverträge</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ pacht_statistik.total_pachtzins|floatformat:2 }}</div>
|
||||
<div class="label">Gesamtpachtzins p.a.</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">{{ pacht_statistik.total_flaeche|floatformat:0 }} qm</div>
|
||||
<div class="label">Verpachtete Fläche</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">{{ pacht_statistik.auslaufend_12m }}</div>
|
||||
<div class="label">Laufen in 12 Mon. aus</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if pacht_auslaufend %}
|
||||
<h3>Auslaufende Verträge (nächste 12 Monate)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Länderei</th>
|
||||
<th>Pächter</th>
|
||||
<th>Pachtende</th>
|
||||
<th>Pachtzins</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for v in pacht_auslaufend %}
|
||||
<tr>
|
||||
<td>{{ v.land }}</td>
|
||||
<td>{{ v.paechter.get_full_name }}</td>
|
||||
<td>{{ v.pachtende|date:"d.m.Y" }}</td>
|
||||
<td class="amount">€{{ v.pachtzins_pauschal|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if verpachtungen %}
|
||||
<h3>Alle Verpachtungen</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Länderei</th>
|
||||
<th>Pächter</th>
|
||||
<th>Fläche</th>
|
||||
<th>Pachtzins</th>
|
||||
<th>Beginn</th>
|
||||
<th>Ende</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for v in verpachtungen %}
|
||||
<tr>
|
||||
<td>{{ v.land }}</td>
|
||||
<td>{{ v.paechter.get_full_name }}</td>
|
||||
<td class="amount">{{ v.verpachtete_flaeche|floatformat:0 }} qm</td>
|
||||
<td class="amount">€{{ v.pachtzins_pauschal|floatformat:2 }}</td>
|
||||
<td>{{ v.pachtbeginn|date:"d.m.Y" }}</td>
|
||||
<td>{% if v.pachtende %}{{ v.pachtende|date:"d.m.Y" }}{% else %}unbefristet{% endif %}</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ v.status }}">{{ v.get_status_display }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="3">Gesamtpachtzins</td>
|
||||
<td class="amount">€{{ total_pachtzins|floatformat:2 }}</td>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
30
app/templates/berichte/sektionen/verwaltungskosten.html
Normal file
30
app/templates/berichte/sektionen/verwaltungskosten.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!-- Sektion: Verwaltungskosten -->
|
||||
{% if verwaltungskosten_nach_kategorie %}
|
||||
<div class="section">
|
||||
<h2>Verwaltungskosten {{ jahr }}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kategorie</th>
|
||||
<th>Anzahl</th>
|
||||
<th>Betrag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k in verwaltungskosten_nach_kategorie %}
|
||||
<tr>
|
||||
<td>{{ k.kategorie|capfirst }}</td>
|
||||
<td>{{ k.anzahl }}</td>
|
||||
<td class="amount">€{{ k.summe|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="2">Gesamt</td>
|
||||
<td class="amount">€{{ total_verwaltungskosten|floatformat:2 }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -13,8 +13,52 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Berichtsvorlagen -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-file-alt me-2"></i>Berichtsvorlagen
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-4">
|
||||
{% for key, vorlage in bericht_vorlagen.items %}
|
||||
<div class="col-md-4 col-lg-2">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body text-center p-3">
|
||||
<i class="fas {{ vorlage.icon }} fa-2x text-primary mb-2"></i>
|
||||
<h6 class="card-title mb-1">{{ vorlage.label }}</h6>
|
||||
<p class="card-text text-muted small mb-2">{{ vorlage.beschreibung }}</p>
|
||||
<div class="d-flex gap-1 justify-content-center flex-wrap">
|
||||
<div class="input-group input-group-sm" style="max-width: 200px;">
|
||||
<select class="form-select form-select-sm vorlage-jahr" data-vorlage="{{ key }}">
|
||||
<option value="">Jahr...</option>
|
||||
{% for year in jahre %}
|
||||
<option value="{{ year }}">{{ year }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline-primary vorlage-html-btn" data-vorlage="{{ key }}" title="HTML anzeigen">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-success vorlage-pdf-btn" data-vorlage="{{ key }}" title="PDF herunterladen">
|
||||
<i class="fas fa-file-pdf"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Jahresberichte -->
|
||||
<!-- Jahresberichte (Schnellzugriff) -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-header py-3">
|
||||
@@ -23,9 +67,8 @@
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-4">
|
||||
Generieren Sie detaillierte Jahresberichte mit allen wichtigen Informationen zu Destinatären,
|
||||
Förderungen und Ländereien.
|
||||
<p class="text-muted mb-3">
|
||||
Generieren Sie detaillierte Jahresberichte mit allen wichtigen Informationen.
|
||||
</p>
|
||||
|
||||
<form method="get" action="{% url 'stiftung:jahresbericht_generate_redirect' %}">
|
||||
@@ -47,17 +90,16 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-4">
|
||||
<h6 class="text-primary">Verfügbare Berichte:</h6>
|
||||
<div class="list-group list-group-flush">
|
||||
<div class="mt-3">
|
||||
<div class="list-group list-group-flush" style="max-height: 250px; overflow-y: auto;">
|
||||
{% for year in jahre %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center py-2">
|
||||
<span>Jahresbericht {{ year }}</span>
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{% url 'stiftung:jahresbericht_generate' year %}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="fas fa-eye me-1"></i>Anzeigen
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'stiftung:jahresbericht_generate' year %}" class="btn btn-outline-primary">
|
||||
<i class="fas fa-eye me-1"></i>HTML
|
||||
</a>
|
||||
<a href="{% url 'stiftung:jahresbericht_pdf' year %}" class="btn btn-sm btn-outline-success">
|
||||
<a href="{% url 'stiftung:jahresbericht_pdf' year %}" class="btn btn-outline-success">
|
||||
<i class="fas fa-download me-1"></i>PDF
|
||||
</a>
|
||||
</div>
|
||||
@@ -69,9 +111,70 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistik-Übersicht -->
|
||||
<!-- Bericht-Baukasten -->
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-puzzle-piece me-2"></i>Bericht zusammenstellen
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">
|
||||
Stellen Sie einen individuellen Bericht aus einzelnen Sektionen zusammen.
|
||||
</p>
|
||||
<form method="post" action="{% url 'stiftung:bericht_zusammenstellen' %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">Sektionen auswählen:</label>
|
||||
{% for key, sektion in bericht_sektionen.items %}
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="sektionen" value="{{ key }}" id="sek_{{ key }}">
|
||||
<label class="form-check-label" for="sek_{{ key }}">
|
||||
<i class="fas {{ sektion.icon }} me-1 text-muted"></i>{{ sektion.label }}
|
||||
</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="composer_jahr" class="form-label">Jahr (optional)</label>
|
||||
<select name="jahr" id="composer_jahr" class="form-select form-select-sm">
|
||||
<option value="">Kein Jahr</option>
|
||||
{% for year in jahre %}
|
||||
<option value="{{ year }}">{{ year }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"> </label>
|
||||
<div class="form-check mt-1">
|
||||
<input class="form-check-input" type="checkbox" name="show_cover" id="show_cover" checked>
|
||||
<label class="form-check-label" for="show_cover">Deckblatt anzeigen</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" name="format" value="html" class="btn btn-primary flex-fill">
|
||||
<i class="fas fa-eye me-1"></i>HTML Vorschau
|
||||
</button>
|
||||
<button type="submit" name="format" value="pdf" class="btn btn-success flex-fill">
|
||||
<i class="fas fa-file-pdf me-1"></i>PDF Export
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistik-Übersicht -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-chart-pie me-2"></i>Statistik-Übersicht
|
||||
@@ -79,116 +182,39 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body text-center">
|
||||
<div class="card-body text-center py-3">
|
||||
<i class="fas fa-users fa-2x mb-2"></i>
|
||||
<h5 class="card-title">Destinatäre</h5>
|
||||
<h3 class="card-text">{{ total_destinataere|default:"0" }}</h3>
|
||||
<h6 class="card-title mb-0">Destinatäre</h6>
|
||||
<h3 class="card-text mb-0">{{ total_destinataere|default:"0" }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-success text-white">
|
||||
<div class="card-body text-center">
|
||||
<div class="card-body text-center py-3">
|
||||
<i class="fas fa-gift fa-2x mb-2"></i>
|
||||
<h5 class="card-title">Förderungen</h5>
|
||||
<h3 class="card-text">{{ total_foerderungen|default:"0" }}</h3>
|
||||
<h6 class="card-title mb-0">Förderungen</h6>
|
||||
<h3 class="card-text mb-0">{{ total_foerderungen|default:"0" }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-secondary text-white">
|
||||
<div class="card-body text-center">
|
||||
<i class="fas fa-user-friends fa-2x mb-2"></i>
|
||||
<h5 class="card-title">Destinatäre</h5>
|
||||
<h3 class="card-text">{{ total_destinataere|default:"0" }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-info text-white">
|
||||
<div class="card-body text-center">
|
||||
<div class="card-body text-center py-3">
|
||||
<i class="fas fa-map fa-2x mb-2"></i>
|
||||
<h5 class="card-title">Ländereien</h5>
|
||||
<h3 class="card-text">{{ total_laendereien|default:"0" }}</h3>
|
||||
<h6 class="card-title mb-0">Ländereien</h6>
|
||||
<h3 class="card-text mb-0">{{ total_laendereien|default:"0" }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-warning text-white">
|
||||
<div class="card-body text-center">
|
||||
<div class="card-body text-center py-3">
|
||||
<i class="fas fa-handshake fa-2x mb-2"></i>
|
||||
<h5 class="card-title">Verpachtungen</h5>
|
||||
<h3 class="card-text">{{ total_verpachtungen|default:"0" }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<h6 class="text-primary">Schnellzugriff:</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="{% url 'stiftung:destinataer_list' %}" class="btn btn-outline-primary">
|
||||
<i class="fas fa-users me-2"></i>Alle Destinatäre anzeigen
|
||||
</a>
|
||||
<a href="{% url 'stiftung:foerderung_list' %}" class="btn btn-outline-success">
|
||||
<i class="fas fa-gift me-2"></i>Alle Förderungen anzeigen
|
||||
</a>
|
||||
<a href="{% url 'stiftung:land_list' %}" class="btn btn-outline-info">
|
||||
<i class="fas fa-map me-2"></i>Alle Ländereien anzeigen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zusätzliche Berichte -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-cogs me-2"></i>Weitere Berichtstypen
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<i class="fas fa-euro-sign fa-3x text-success mb-3"></i>
|
||||
<h5 class="card-title">Finanzberichte</h5>
|
||||
<p class="card-text">Detaillierte Auswertungen zu Förderungen und Ausgaben.</p>
|
||||
<button class="btn btn-outline-success" disabled>
|
||||
<i class="fas fa-clock me-2"></i>In Entwicklung
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<i class="fas fa-chart-line fa-3x text-info mb-3"></i>
|
||||
<h5 class="card-title">Trendanalysen</h5>
|
||||
<p class="card-text">Langzeitentwicklungen und Prognosen für die Zukunft.</p>
|
||||
<button class="btn btn-outline-info" disabled>
|
||||
<i class="fas fa-clock me-2"></i>In Entwicklung
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<i class="fas fa-file-export fa-3x text-warning mb-3"></i>
|
||||
<h5 class="card-title">Export-Funktionen</h5>
|
||||
<p class="card-text">Datenexport in verschiedene Formate (Excel, CSV, PDF).</p>
|
||||
<button class="btn btn-outline-warning" disabled>
|
||||
<i class="fas fa-clock me-2"></i>In Entwicklung
|
||||
</button>
|
||||
<h6 class="card-title mb-0">Verpachtungen</h6>
|
||||
<h3 class="card-text mb-0">{{ total_verpachtungen|default:"0" }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,3 +225,29 @@
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
// Berichtsvorlagen Schnellzugriff
|
||||
document.querySelectorAll('.vorlage-html-btn, .vorlage-pdf-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const vorlage = this.dataset.vorlage;
|
||||
const select = document.querySelector(`.vorlage-jahr[data-vorlage="${vorlage}"]`);
|
||||
const jahr = select ? select.value : '';
|
||||
const format = this.classList.contains('vorlage-pdf-btn') ? 'pdf' : 'html';
|
||||
|
||||
if (!jahr) {
|
||||
alert('Bitte wählen Sie ein Jahr aus.');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `{% url 'stiftung:bericht_list' %}${vorlage}/?jahr=${jahr}&format=${format}`;
|
||||
if (format === 'pdf') {
|
||||
window.location.href = url;
|
||||
} else {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,109 +4,62 @@
|
||||
<meta charset="utf-8">
|
||||
<title>Stiftung – Jahresbericht {{ jahr }}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
border-bottom: 3px solid #2c3e50;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.header h1 { color: #2c3e50; margin: 0; font-size: 2.2em; }
|
||||
.header .subtitle { color: #7f8c8d; font-size: 1.1em; margin-top: 8px; }
|
||||
.section { margin-bottom: 30px; page-break-inside: avoid; }
|
||||
.section h2 {
|
||||
color: #1a4a2e;
|
||||
border-bottom: 2px solid #2c7a4b;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.section h3 { color: #34495e; font-size: 1em; margin-top: 16px; margin-bottom: 8px; }
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.stat-card {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
{{ css_content }}
|
||||
/* Cover page styles */
|
||||
.cover-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 85vh;
|
||||
text-align: center;
|
||||
}
|
||||
.stat-card .value { font-size: 1.6em; font-weight: bold; color: #1a4a2e; }
|
||||
.stat-card .label { color: #7f8c8d; margin-top: 4px; font-size: 0.85em; }
|
||||
.cover-logo-img { max-height: 100px; max-width: 250px; margin-bottom: 30px; }
|
||||
.cover-title h1 {
|
||||
font-size: 24pt;
|
||||
color: {{ corporate_settings.primary_color|default:"#2c3e50" }};
|
||||
margin: 0 0 10px 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
.cover-title h2 {
|
||||
font-size: 18pt;
|
||||
color: {{ corporate_settings.secondary_color|default:"#3498db" }};
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
.cover-subtitle { font-size: 12pt; color: #666; }
|
||||
.cover-meta { margin-top: 40px; font-size: 11pt; color: #555; }
|
||||
.cover-meta p { margin: 5px 0; }
|
||||
.cover-footer { margin-top: 60px; font-size: 9pt; color: #999; }
|
||||
.cover-footer p { margin: 3px 0; }
|
||||
.cover-confidential {
|
||||
margin-top: 15px !important;
|
||||
font-weight: bold;
|
||||
color: {{ corporate_settings.primary_color|default:"#2c3e50" }} !important;
|
||||
font-size: 10pt;
|
||||
}
|
||||
/* Bilanz cards */
|
||||
.bilanz-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.bilanz-card {
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
.bilanz-card { border-radius: 8px; padding: 16px; text-align: center; }
|
||||
.bilanz-card.einnahmen { background: #d4edda; border: 1px solid #c3e6cb; }
|
||||
.bilanz-card.ausgaben { background: #f8d7da; border: 1px solid #f5c6cb; }
|
||||
.bilanz-card.netto-positiv { background: #d1ecf1; border: 1px solid #bee5eb; }
|
||||
.bilanz-card.netto-negativ { background: #fff3cd; border: 1px solid #ffeeba; }
|
||||
.bilanz-card .value { font-size: 1.5em; font-weight: bold; }
|
||||
.bilanz-card .label { font-size: 0.85em; margin-top: 4px; color: #555; }
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
th, td { border: 1px solid #dee2e6; padding: 8px 10px; text-align: left; }
|
||||
th { background-color: #f0f7f4; font-weight: 600; color: #1a4a2e; }
|
||||
tr:nth-child(even) { background-color: #f8f9fa; }
|
||||
.amount { text-align: right; font-family: 'Courier New', monospace; }
|
||||
.status-badge {
|
||||
padding: 3px 7px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-beantragt { background-color: #fff3cd; color: #856404; }
|
||||
.status-genehmigt { background-color: #d1ecf1; color: #0c5460; }
|
||||
.status-ausgezahlt, .status-abgeschlossen { background-color: #d4edda; color: #155724; }
|
||||
.status-abgelehnt, .status-storniert { background-color: #f8d7da; color: #721c24; }
|
||||
/* Status badges extra */
|
||||
.status-aktiv { background-color: #d4edda; color: #155724; }
|
||||
.status-beendet { background-color: #e2e3e5; color: #383d41; }
|
||||
.status-gekuendigt { background-color: #f8d7da; color: #721c24; }
|
||||
.status-geplant, .status-faellig { background-color: #e2e3e5; color: #383d41; }
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #dee2e6;
|
||||
text-align: center;
|
||||
color: #7f8c8d;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.status-abgeschlossen { background-color: #d4edda; color: #155724; }
|
||||
@media print {
|
||||
body { margin: 0; padding: 10px; }
|
||||
.section { page-break-inside: avoid; }
|
||||
.no-print { display: none; }
|
||||
}
|
||||
.print-btn {
|
||||
display: inline-block;
|
||||
padding: 8px 20px;
|
||||
background: #1a4a2e;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
text-decoration: none;
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -114,253 +67,52 @@
|
||||
<div class="no-print" style="margin-bottom: 20px; display: flex; align-items: center; gap: 12px;">
|
||||
<a href="{% url 'stiftung:bericht_list' %}" style="color: #1a4a2e;">← Berichte</a>
|
||||
<span style="color: #dee2e6;">|</span>
|
||||
<a href="{% url 'stiftung:jahresbericht_pdf' jahr=jahr %}" class="print-btn">
|
||||
<a href="{% url 'stiftung:jahresbericht_pdf' jahr=jahr %}" style="display: inline-block; padding: 8px 20px; background: #1a4a2e; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 0.9em; text-decoration: none; margin-right: 8px;">
|
||||
PDF herunterladen
|
||||
</a>
|
||||
<button onclick="window.print()" class="print-btn" style="background: #34495e;">
|
||||
<button onclick="window.print()" style="display: inline-block; padding: 8px 20px; background: #34495e; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 0.9em;">
|
||||
Drucken
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{% if show_cover %}
|
||||
{% include "berichte/cover_page.html" %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Kopfzeile -->
|
||||
<div class="header">
|
||||
<h1>Jahresbericht {{ jahr }}</h1>
|
||||
<div class="subtitle">van Hees-Theyssen-Vogel'sche Familienstiftung</div>
|
||||
<div class="subtitle">Erstellt am {% now "d.m.Y" %}</div>
|
||||
</div>
|
||||
|
||||
<!-- 1. Gesamtübersicht / Bilanz -->
|
||||
<div class="section">
|
||||
<h2>1. Jahresbilanz {{ jahr }}</h2>
|
||||
<div class="bilanz-grid">
|
||||
<div class="bilanz-card einnahmen">
|
||||
<div class="value">€{{ total_einnahmen|floatformat:2 }}</div>
|
||||
<div class="label">Einnahmen (Pacht)</div>
|
||||
</div>
|
||||
<div class="bilanz-card ausgaben">
|
||||
<div class="value">€{{ total_ausgaben|floatformat:2 }}</div>
|
||||
<div class="label">Ausgaben gesamt</div>
|
||||
</div>
|
||||
<div class="bilanz-card {% if netto >= 0 %}netto-positiv{% else %}netto-negativ{% endif %}">
|
||||
<div class="value">{% if netto >= 0 %}+{% endif %}€{{ netto|floatformat:2 }}</div>
|
||||
<div class="label">Nettosaldo</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ total_ausgaben_foerderung|floatformat:2 }}</div>
|
||||
<div class="label">Förderausgaben</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ total_verwaltungskosten|floatformat:2 }}</div>
|
||||
<div class="label">Verwaltungskosten</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ pacht_vereinnahmt|floatformat:2 }}</div>
|
||||
<div class="label">Pacht vereinnahmt</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="value">€{{ grundsteuer_gesamt|floatformat:2 }}</div>
|
||||
<div class="label">Grundsteuer</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. Unterstützungen (Zahlungs-Pipeline) -->
|
||||
{% if unterstuetzungen %}
|
||||
<div class="section">
|
||||
<h2>2. Unterstützungszahlungen {{ jahr }}</h2>
|
||||
<p style="color: #666; margin-bottom: 12px;">
|
||||
{{ unterstuetzungen.count }} Unterstützung(en) geplant/ausgezahlt ·
|
||||
{{ unterstuetzungen_ausgezahlt.count }} überwiesen (€{{ total_unterstuetzungen|floatformat:2 }})
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Destinatär</th>
|
||||
<th>Betrag</th>
|
||||
<th>Fällig am</th>
|
||||
<th>Status</th>
|
||||
<th>Verwendungszweck</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in unterstuetzungen %}
|
||||
<tr>
|
||||
<td>{{ u.destinataer.get_full_name }}</td>
|
||||
<td class="amount">€{{ u.betrag|floatformat:2 }}</td>
|
||||
<td>{{ u.faellig_am|date:"d.m.Y" }}</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ u.status }}">{{ u.get_status_display }}</span>
|
||||
</td>
|
||||
<td>{{ u.beschreibung|default:"-" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td>Summe ausgezahlt</td>
|
||||
<td class="amount">€{{ total_unterstuetzungen|floatformat:2 }}</td>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
{% if logo_base64 %}
|
||||
<img src="{{ logo_base64 }}" alt="Logo" class="logo">
|
||||
{% endif %}
|
||||
|
||||
<!-- 3. Förderungen (legacy Foerderung-Modell) -->
|
||||
{% if foerderungen %}
|
||||
<div class="section">
|
||||
<h2>3. Förderungen {{ jahr }}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Begünstigter</th>
|
||||
<th>Kategorie</th>
|
||||
<th>Betrag</th>
|
||||
<th>Status</th>
|
||||
<th>Antragsdatum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for f in foerderungen %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if f.destinataer %}{{ f.destinataer.get_full_name }}
|
||||
{% elif f.person %}{{ f.person.get_full_name }}
|
||||
{% else %}–{% endif %}
|
||||
</td>
|
||||
<td>{{ f.get_kategorie_display }}</td>
|
||||
<td class="amount">€{{ f.betrag|floatformat:2 }}</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ f.status }}">{{ f.get_status_display }}</span>
|
||||
</td>
|
||||
<td>{{ f.antragsdatum|date:"d.m.Y" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="2">Summe</td>
|
||||
<td class="amount">€{{ total_foerderungen_legacy|floatformat:2 }}</td>
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<p class="stiftung-name">{{ corporate_settings.stiftung_name }}</p>
|
||||
<p class="document-title">Jahresbericht {{ jahr }}</p>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="contact-info">
|
||||
{% if corporate_settings.address_line1 %}<p>{{ corporate_settings.address_line1 }}</p>{% endif %}
|
||||
{% if corporate_settings.address_line2 %}<p>{{ corporate_settings.address_line2 }}</p>{% endif %}
|
||||
{% if corporate_settings.phone %}<p>{{ corporate_settings.phone }}</p>{% endif %}
|
||||
{% if corporate_settings.email %}<p>{{ corporate_settings.email }}</p>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-info">
|
||||
Erstellt am {% now "d.m.Y" %} · Berichtszeitraum: {{ jahr }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- 4. Grundstücksverwaltung -->
|
||||
<div class="section">
|
||||
<h2>4. Grundstücksverwaltung</h2>
|
||||
|
||||
{% if verpachtungen %}
|
||||
<h3>Aktive Verpachtungen</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Länderei</th>
|
||||
<th>Pächter</th>
|
||||
<th>Verpachtete Fläche</th>
|
||||
<th>Jahrespachtzins</th>
|
||||
<th>Pachtende</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for v in verpachtungen %}
|
||||
<tr>
|
||||
<td>{{ v.land }}</td>
|
||||
<td>{{ v.paechter.get_full_name }}</td>
|
||||
<td class="amount">{{ v.verpachtete_flaeche|floatformat:0 }} qm</td>
|
||||
<td class="amount">€{{ v.pachtzins_pauschal|floatformat:2 }}</td>
|
||||
<td>{% if v.pachtende %}{{ v.pachtende|date:"d.m.Y" }}{% else %}unbefristet{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="3">Gesamtpachtzins (kalkuliert)</td>
|
||||
<td class="amount">€{{ total_pachtzins|floatformat:2 }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if landabrechnungen %}
|
||||
<h3>Landabrechnungen {{ jahr }}</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Länderei</th>
|
||||
<th>Pacht vereinnahmt</th>
|
||||
<th>Umlagen</th>
|
||||
<th>Grundsteuer</th>
|
||||
<th>Sonstige Einnahmen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for a in landabrechnungen %}
|
||||
<tr>
|
||||
<td>{{ a.land }}</td>
|
||||
<td class="amount">€{{ a.pacht_vereinnahmt|floatformat:2 }}</td>
|
||||
<td class="amount">€{{ a.umlagen_vereinnahmt|floatformat:2 }}</td>
|
||||
<td class="amount">€{{ a.grundsteuer_betrag|floatformat:2 }}</td>
|
||||
<td class="amount">€{{ a.sonstige_einnahmen|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td>Summe</td>
|
||||
<td class="amount">€{{ pacht_vereinnahmt|floatformat:2 }}</td>
|
||||
<td></td>
|
||||
<td class="amount">€{{ grundsteuer_gesamt|floatformat:2 }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if not verpachtungen and not landabrechnungen %}
|
||||
<p style="color: #999;">Keine Verpachtungs- oder Abrechnungsdaten für {{ jahr }} vorhanden.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 5. Verwaltungskosten -->
|
||||
{% if verwaltungskosten_nach_kategorie %}
|
||||
<div class="section">
|
||||
<h2>5. Verwaltungskosten {{ jahr }}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kategorie</th>
|
||||
<th>Anzahl</th>
|
||||
<th>Betrag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k in verwaltungskosten_nach_kategorie %}
|
||||
<tr>
|
||||
<td>{{ k.kategorie|capfirst }}</td>
|
||||
<td>{{ k.anzahl }}</td>
|
||||
<td class="amount">€{{ k.summe|floatformat:2 }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr style="font-weight: bold; background: #f0f7f4;">
|
||||
<td colspan="2">Gesamt</td>
|
||||
<td class="amount">€{{ total_verwaltungskosten|floatformat:2 }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- Modulare Sektionen -->
|
||||
{% include "berichte/sektionen/bilanz.html" %}
|
||||
{% include "berichte/sektionen/unterstuetzungen.html" %}
|
||||
{% include "berichte/sektionen/foerderungen.html" %}
|
||||
{% include "berichte/sektionen/grundstuecke.html" %}
|
||||
{% include "berichte/sektionen/verwaltungskosten.html" %}
|
||||
|
||||
<div class="footer">
|
||||
<p>Jahresbericht {{ jahr }} — automatisch generiert von der Stiftungsverwaltung</p>
|
||||
<p>van Hees-Theyssen-Vogel'sche Familienstiftung · Vertraulich</p>
|
||||
<p>{{ corporate_settings.stiftung_name }} · {{ corporate_settings.footer_text }}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user