Files
SysAdmin Agent faeb7c1073
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy (push) Has been cancelled
Code Quality / quality (push) Has been cancelled
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>
2026-03-14 20:55:31 +00:00

254 lines
12 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}Berichte - Stiftungsverwaltung{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<h1 class="h3 mb-4">
<i class="fas fa-chart-bar text-primary me-2"></i>Berichte & Auswertungen
</h1>
</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 (Schnellzugriff) -->
<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-calendar-alt me-2"></i>Jahresberichte
</h6>
</div>
<div class="card-body">
<p class="text-muted mb-3">
Generieren Sie detaillierte Jahresberichte mit allen wichtigen Informationen.
</p>
<form method="get" action="{% url 'stiftung:jahresbericht_generate_redirect' %}">
<div class="row g-3">
<div class="col-md-6">
<label for="jahr" class="form-label">Jahr auswählen</label>
<select name="jahr" id="jahr" class="form-select" required>
<option value="">Jahr wählen...</option>
{% for year in jahre %}
<option value="{{ year }}">{{ year }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-6 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-file-alt me-2"></i>Bericht generieren
</button>
</div>
</div>
</form>
<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 py-2">
<span>Jahresbericht {{ year }}</span>
<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-outline-success">
<i class="fas fa-download me-1"></i>PDF
</a>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<!-- 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">&nbsp;</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
</h6>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<div class="card bg-primary text-white">
<div class="card-body text-center py-3">
<i class="fas fa-users fa-2x mb-2"></i>
<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-3">
<div class="card bg-success text-white">
<div class="card-body text-center py-3">
<i class="fas fa-gift fa-2x mb-2"></i>
<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-3">
<div class="card bg-info text-white">
<div class="card-body text-center py-3">
<i class="fas fa-map fa-2x mb-2"></i>
<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-3">
<div class="card bg-warning text-white">
<div class="card-body text-center py-3">
<i class="fas fa-handshake fa-2x mb-2"></i>
<h6 class="card-title mb-0">Verpachtungen</h6>
<h3 class="card-text mb-0">{{ total_verpachtungen|default:"0" }}</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</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 %}