- Implement automated payment tracking with Django signals - Fix duplicate transaction creation with unique referenz system - Add calendar system with CRUD operations and event management - Reorganize navigation menu (rename sections, move admin functions) - Replace Geschichte editor with EasyMDE markdown editor - Add management commands for balance reconciliation - Create missing transactions for previously paid payments - Ensure account balances accurately reflect all payment activity Features added: - Calendar entries creation and administration via menu - Payment status tracking with automatic balance updates - Duplicate prevention for payment transactions - Markdown editor with live preview for Geschichte pages - Database reconciliation tools for payment/balance sync Bug fixes: - Resolved IntegrityError on payment status changes - Fixed missing account balance updates for paid payments - Prevented duplicate balance deductions on re-saves - Corrected menu structure and admin function placement
346 lines
18 KiB
HTML
346 lines
18 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ title }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Header -->
|
|
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
|
<h1 class="h3 mb-0 text-gray-800">
|
|
<i class="fas fa-cogs me-2"></i>{{ title }}
|
|
</h1>
|
|
<div class="d-flex gap-2">
|
|
<a href="{% url 'stiftung:kalender' %}" class="btn btn-secondary">
|
|
<i class="fas fa-arrow-left me-1"></i>Zurück zum Kalender
|
|
</a>
|
|
<a href="{% url 'stiftung:kalender_create' %}" class="btn btn-success">
|
|
<i class="fas fa-plus me-1"></i>Neuer Termin
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-primary shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
|
|
Benutzerdefinierte Termine
|
|
</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.custom_count }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-success shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
|
|
Zahlungsereignisse
|
|
</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.payment_events }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-euro-sign fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-info shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">
|
|
Pachtverträge
|
|
</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.lease_events }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-handshake fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-warning shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
|
|
Geburtstage
|
|
</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.birthday_events }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-birthday-cake fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Controls -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card shadow mb-4">
|
|
<div class="card-header py-3">
|
|
<h6 class="m-0 font-weight-bold text-primary">
|
|
<i class="fas fa-filter me-2"></i>Ereignisquellen & Filter
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="get" class="row g-3">
|
|
<!-- Event Source Toggles -->
|
|
<div class="col-12">
|
|
<label class="form-label fw-bold">Ereignisquellen anzeigen:</label>
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="show_custom"
|
|
name="show_custom" value="true"
|
|
{% if show_custom %}checked{% endif %}
|
|
onchange="this.form.submit()">
|
|
<label class="form-check-label" for="show_custom">
|
|
<i class="fas fa-calendar text-primary me-1"></i>Benutzerdefinierte Termine
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="show_payments"
|
|
name="show_payments" value="true"
|
|
{% if show_payments %}checked{% endif %}
|
|
onchange="this.form.submit()">
|
|
<label class="form-check-label" for="show_payments">
|
|
<i class="fas fa-euro-sign text-success me-1"></i>Zahlungserinnerungen
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="show_leases"
|
|
name="show_leases" value="true"
|
|
{% if show_leases %}checked{% endif %}
|
|
onchange="this.form.submit()">
|
|
<label class="form-check-label" for="show_leases">
|
|
<i class="fas fa-handshake text-info me-1"></i>Pachtverträge
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="show_birthdays"
|
|
name="show_birthdays" value="true"
|
|
{% if show_birthdays %}checked{% endif %}
|
|
onchange="this.form.submit()">
|
|
<label class="form-check-label" for="show_birthdays">
|
|
<i class="fas fa-birthday-cake text-warning me-1"></i>Geburtstage
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Filters -->
|
|
<div class="col-md-4">
|
|
<label for="category" class="form-label">Kategorie:</label>
|
|
<select class="form-control" id="category" name="category" onchange="this.form.submit()">
|
|
<option value="">Alle Kategorien</option>
|
|
{% for value, display in categories %}
|
|
<option value="{{ value }}" {% if category_filter == value %}selected{% endif %}>
|
|
{{ display }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<label for="priority" class="form-label">Priorität:</label>
|
|
<select class="form-control" id="priority" name="priority" onchange="this.form.submit()">
|
|
<option value="">Alle Prioritäten</option>
|
|
{% for value, display in priorities %}
|
|
<option value="{{ value }}" {% if priority_filter == value %}selected{% endif %}>
|
|
{{ display }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<label class="form-label"> </label>
|
|
<div>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-search me-1"></i>Filter anwenden
|
|
</button>
|
|
<a href="{% url 'stiftung:kalender_admin' %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-undo me-1"></i>Zurücksetzen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Events Table -->
|
|
<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-list me-2"></i>Ereignisse ({{ stats.total_events }} Einträge)
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if events %}
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered" id="eventsTable">
|
|
<thead>
|
|
<tr>
|
|
<th>Datum</th>
|
|
<th>Titel</th>
|
|
<th>Kategorie</th>
|
|
<th>Priorität</th>
|
|
<th>Quelle</th>
|
|
<th>Status</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for event in events %}
|
|
<tr>
|
|
<td>
|
|
<strong>{{ event.date|date:"d.m.Y" }}</strong>
|
|
{% if event.time %}
|
|
<br><small class="text-muted">{{ event.time|time:"H:i" }}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<i class="{{ event.icon }} me-2"></i>{{ event.title }}
|
|
{% if event.description %}
|
|
<br><small class="text-muted">{{ event.description|truncatechars:50 }}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ event.category_display }}</span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-{% if event.priority == 'hoch' %}danger{% elif event.priority == 'mittel' %}warning{% else %}secondary{% endif %}">
|
|
{% if event.priority == 'hoch' %}
|
|
<i class="fas fa-exclamation-triangle me-1"></i>
|
|
{% elif event.priority == 'mittel' %}
|
|
<i class="fas fa-exclamation-circle me-1"></i>
|
|
{% else %}
|
|
<i class="fas fa-info-circle me-1"></i>
|
|
{% endif %}
|
|
{{ event.priority_display|default:"Normal" }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{% if event.source == 'custom' %}
|
|
<span class="badge bg-primary">Benutzerdefiniert</span>
|
|
{% elif event.source == 'payment' %}
|
|
<span class="badge bg-success">Zahlung</span>
|
|
{% elif event.source == 'lease' %}
|
|
<span class="badge bg-info">Pacht</span>
|
|
{% elif event.source == 'birthday' %}
|
|
<span class="badge bg-warning">Geburtstag</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">System</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if event.source == 'custom' %}
|
|
{% if event.completed %}
|
|
<span class="badge bg-success">
|
|
<i class="fas fa-check me-1"></i>Erledigt
|
|
</span>
|
|
{% else %}
|
|
<span class="badge bg-warning">
|
|
<i class="fas fa-clock me-1"></i>Ausstehend
|
|
</span>
|
|
{% endif %}
|
|
{% else %}
|
|
<span class="badge bg-light text-dark">
|
|
<i class="fas fa-robot me-1"></i>Automatisch
|
|
</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if event.source == 'custom' and event.id %}
|
|
<div class="btn-group btn-group-sm">
|
|
<a href="{% url 'stiftung:kalender_detail' event.id %}"
|
|
class="btn btn-outline-primary btn-sm" title="Details">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<a href="{% url 'stiftung:kalender_edit' event.id %}"
|
|
class="btn btn-outline-secondary btn-sm" title="Bearbeiten">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<a href="{% url 'stiftung:kalender_delete' event.id %}"
|
|
class="btn btn-outline-danger btn-sm" title="Löschen">
|
|
<i class="fas fa-trash"></i>
|
|
</a>
|
|
</div>
|
|
{% else %}
|
|
<span class="text-muted small">
|
|
<i class="fas fa-lock me-1"></i>Systemereignis
|
|
</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-5">
|
|
<i class="fas fa-calendar-times fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">Keine Ereignisse gefunden</h5>
|
|
<p class="text-muted">
|
|
Aktivieren Sie Ereignisquellen oder fügen Sie neue Termine hinzu.
|
|
</p>
|
|
<a href="{% url 'stiftung:kalender_create' %}" class="btn btn-primary">
|
|
<i class="fas fa-plus me-1"></i>Neuen Termin hinzufügen
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.border-left-primary { border-left: 0.25rem solid #4e73df !important; }
|
|
.border-left-success { border-left: 0.25rem solid #1cc88a !important; }
|
|
.border-left-info { border-left: 0.25rem solid #36b9cc !important; }
|
|
.border-left-warning { border-left: 0.25rem solid #f6c23e !important; }
|
|
|
|
.form-switch .form-check-input {
|
|
width: 2rem;
|
|
height: 1rem;
|
|
}
|
|
|
|
#eventsTable th {
|
|
background-color: #f8f9fc;
|
|
border-top: none;
|
|
}
|
|
</style>
|
|
{% endblock %} |