Files
stiftung-management-system/app/templates/stiftung/kalender/agenda_view.html
Jan Remmer Siebels c289cc3c58 Fix payment system balance integration and add calendar functionality
- 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
2025-10-05 00:38:18 +02:00

337 lines
12 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Calendar Header with View Controls -->
<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-list me-2"></i>{{ title }}
</h1>
<div class="d-flex gap-2">
<!-- View Type Buttons -->
<div class="btn-group" role="group">
<a href="?view=month&year={{ year }}&month={{ month }}"
class="btn btn-sm btn-outline-primary">
<i class="fas fa-calendar me-1"></i>Monat
</a>
<a href="?view=week"
class="btn btn-sm btn-outline-primary">
<i class="fas fa-calendar-week me-1"></i>Woche
</a>
<a href="?view=agenda"
class="btn btn-sm btn-primary">
<i class="fas fa-list me-1"></i>Agenda
</a>
<a href="?view=list"
class="btn btn-sm btn-outline-primary">
<i class="fas fa-list-ul me-1"></i>Liste
</a>
</div>
<a href="{% url 'stiftung:kalender_create' %}" class="btn btn-success">
<i class="fas fa-plus me-1"></i>Neuer Termin
</a>
</div>
</div>
<!-- Agenda View -->
<div class="row">
<div class="col-12">
<div class="card shadow">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h6 class="mb-0">
<i class="fas fa-clock me-2"></i>Agenda - Chronologische Übersicht
</h6>
<div class="btn-group btn-group-sm">
<!-- Date range filters -->
<div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" type="button"
id="dateRangeDropdown" data-bs-toggle="dropdown">
Zeitraum
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="?view=agenda&range=today">Heute</a></li>
<li><a class="dropdown-item" href="?view=agenda&range=week">Diese Woche</a></li>
<li><a class="dropdown-item" href="?view=agenda&range=month">Dieser Monat</a></li>
<li><a class="dropdown-item" href="?view=agenda&range=3months">Nächste 3 Monate</a></li>
<li><a class="dropdown-item" href="?view=agenda">Alle</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="card-body p-0">
{% if events %}
<div class="agenda-timeline">
{% regroup events by date as events_by_date %}
{% for date_group in events_by_date %}
<div class="timeline-date-group">
<div class="date-divider">
<div class="date-line"></div>
<div class="date-badge {% if date_group.grouper == today %}today{% elif date_group.grouper < today %}past{% endif %}">
<div class="date-day">{{ date_group.grouper|date:"d" }}</div>
<div class="date-month-year">
{{ date_group.grouper|date:"M Y" }}
</div>
<div class="date-weekday">{{ date_group.grouper|date:"l" }}</div>
</div>
<div class="date-line"></div>
</div>
<div class="events-for-date">
{% for event in date_group.list %}
<div class="timeline-event event-{{ event.category }} {% if event.priority == 'hoch' %}high-priority{% elif event.priority == 'mittel' %}medium-priority{% endif %}">
<div class="event-time-indicator">
{% if event.time %}
<div class="event-time">{{ event.time|time:"H:i" }}</div>
{% else %}
<div class="event-time all-day">
<i class="fas fa-clock"></i>
<span>ganztags</span>
</div>
{% endif %}
</div>
<div class="event-content">
<div class="event-header">
<h6 class="event-title mb-1">
<i class="{{ event.icon }} me-2"></i>{{ event.title }}
{% if event.priority == 'hoch' %}
<span class="badge bg-danger ms-2">
<i class="fas fa-exclamation-triangle"></i>
</span>
{% endif %}
</h6>
<div class="event-meta">
<span class="badge bg-secondary me-2">{{ event.category_display }}</span>
{% if event.destinataer %}
<span class="badge bg-info">
<i class="fas fa-user me-1"></i>{{ event.destinataer }}
</span>
{% endif %}
</div>
</div>
{% if event.description %}
<div class="event-description">
{{ event.description }}
</div>
{% endif %}
{% if event.location %}
<div class="event-location">
<i class="fas fa-map-marker-alt me-1"></i>{{ event.location }}
</div>
{% endif %}
<div class="event-actions">
<a href="{% url 'stiftung:kalender_detail' event.id %}"
class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye me-1"></i>Details
</a>
<a href="{% url 'stiftung:kalender_edit' event.id %}"
class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit me-1"></i>Bearbeiten
</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</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 Termine gefunden</h5>
<p class="text-muted">Fügen Sie einen neuen Termin hinzu oder erweitern Sie den Zeitraum.</p>
<a href="{% url 'stiftung:kalender_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Termin hinzufügen
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<style>
.agenda-timeline {
padding: 20px;
}
.timeline-date-group {
margin-bottom: 40px;
}
.date-divider {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.date-line {
flex: 1;
height: 2px;
background: linear-gradient(to right, transparent, #dee2e6, transparent);
}
.date-badge {
background: white;
border: 2px solid #dee2e6;
border-radius: 15px;
padding: 15px 25px;
text-align: center;
margin: 0 20px;
min-width: 120px;
}
.date-badge.today {
background: #e3f2fd;
border-color: #2196f3;
color: #1976d2;
}
.date-badge.past {
background: #f5f5f5;
border-color: #bdbdbd;
color: #757575;
}
.date-day {
font-size: 2rem;
font-weight: bold;
line-height: 1;
}
.date-month-year {
font-size: 0.9rem;
font-weight: 600;
margin: 5px 0;
}
.date-weekday {
font-size: 0.8rem;
text-transform: uppercase;
opacity: 0.7;
}
.events-for-date {
padding-left: 40px;
}
.timeline-event {
display: flex;
margin-bottom: 20px;
border-left: 4px solid;
border-radius: 8px;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
}
.timeline-event:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
transform: translateX(5px);
transition: all 0.3s ease;
}
.timeline-event.high-priority {
box-shadow: 0 2px 8px rgba(244, 67, 54, 0.3);
}
.event-time-indicator {
background: #f8f9fa;
padding: 20px 15px;
min-width: 120px;
display: flex;
align-items: center;
justify-content: center;
border-right: 1px solid #dee2e6;
}
.event-time {
font-size: 1.2rem;
font-weight: bold;
color: #495057;
}
.event-time.all-day {
font-size: 0.9rem;
text-align: center;
color: #6c757d;
}
.event-time.all-day i {
display: block;
margin-bottom: 5px;
}
.event-content {
flex: 1;
padding: 20px;
}
.event-title {
color: #343a40;
margin-bottom: 8px;
}
.event-meta {
margin-bottom: 12px;
}
.event-description {
color: #6c757d;
margin-bottom: 12px;
line-height: 1.5;
}
.event-location {
color: #6c757d;
margin-bottom: 15px;
font-size: 0.9rem;
}
.event-actions {
display: flex;
gap: 8px;
}
/* Event category colors */
.event-termin { border-left-color: #2196f3; }
.event-zahlung { border-left-color: #ff9800; }
.event-deadline { border-left-color: #f44336; }
.event-geburtstag { border-left-color: #4caf50; }
.event-vertrag { border-left-color: #9c27b0; }
.event-pruefung { border-left-color: #009688; }
@media (max-width: 768px) {
.timeline-event {
flex-direction: column;
}
.event-time-indicator {
min-width: auto;
padding: 15px;
border-right: none;
border-bottom: 1px solid #dee2e6;
}
.events-for-date {
padding-left: 20px;
}
.date-badge {
margin: 0 10px;
min-width: 100px;
padding: 10px 15px;
}
}
</style>
{% endblock %}