Phase 1: Sidebar-Navigation, Dashboard-Cockpit & HTMX-Integration
- New sidebar layout (6 sections: Dashboard, Personen, Land, Finanzen, Dokumente, System) - Collapsible sidebar with localStorage persistence - Top bar with user dropdown and breadcrumbs - Dashboard cockpit with live KPI cards (Destinataere, Foerderungen, Zahlungen, Laendereien) - Action items: overdue Nachweise, pending payments, upcoming events, new emails, expiring leases - Quick actions panel and recent audit log - HTMX (2.0.4) and Alpine.js (3.14.8) integration via CDN - django-htmx middleware and CSRF token setup - Fix IMAP_PORT empty string handling in settings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# views/dashboard.py
|
||||
# Phase 0: Vision 2026 – Code-Refactoring
|
||||
# Vision 2026 – Phase 1: Dashboard Cockpit
|
||||
|
||||
import csv
|
||||
import io
|
||||
@@ -59,38 +59,86 @@ from stiftung.forms import (
|
||||
|
||||
@login_required
|
||||
def home(request):
|
||||
"""Home page for the Stiftungsverwaltung application"""
|
||||
"""Vision 2026 Dashboard Cockpit"""
|
||||
from stiftung.services.calendar_service import StiftungsKalenderService
|
||||
|
||||
# Get upcoming events for the calendar widget
|
||||
calendar_service = StiftungsKalenderService()
|
||||
|
||||
# Get all events for the next 14 days
|
||||
from datetime import timedelta
|
||||
|
||||
today = timezone.now().date()
|
||||
current_quarter = (today.month - 1) // 3 + 1
|
||||
current_year = today.year
|
||||
|
||||
# ── Calendar events ──
|
||||
calendar_service = StiftungsKalenderService()
|
||||
end_date = today + timedelta(days=14)
|
||||
all_events = calendar_service.get_all_events(today, end_date)
|
||||
|
||||
# Filter for upcoming and overdue
|
||||
upcoming_events = [e for e in all_events if not getattr(e, 'overdue', False)]
|
||||
overdue_events = [e for e in all_events if getattr(e, 'overdue', False)]
|
||||
|
||||
# Get current month events for mini calendar
|
||||
from calendar import monthrange
|
||||
_, last_day = monthrange(today.year, today.month)
|
||||
month_start = today.replace(day=1)
|
||||
month_end = today.replace(day=last_day)
|
||||
current_month_events = calendar_service.get_all_events(month_start, month_end)
|
||||
|
||||
|
||||
# ── Stats ──
|
||||
destinataer_count = Destinataer.objects.count()
|
||||
paechter_count = Paechter.objects.count()
|
||||
land_count = Land.objects.count()
|
||||
|
||||
# Active Foerderungen (not rejected/cancelled, current or future year)
|
||||
foerderung_active = Foerderung.objects.filter(
|
||||
jahr__gte=current_year,
|
||||
status__in=['beantragt', 'genehmigt'],
|
||||
).count()
|
||||
|
||||
# ── Overdue Nachweise (current quarter) ──
|
||||
overdue_nachweise = VierteljahresNachweis.objects.filter(
|
||||
quartal=current_quarter,
|
||||
jahr=current_year,
|
||||
status__in=['offen', 'teilweise', 'nachbesserung'],
|
||||
).select_related('destinataer').order_by('jahr', 'quartal')[:10]
|
||||
|
||||
# ── Pending payments (not yet paid out) ──
|
||||
pending_payments = DestinataerUnterstuetzung.objects.filter(
|
||||
status__in=['geplant', 'faellig', 'in_bearbeitung'],
|
||||
).select_related('destinataer').order_by('faellig_am')[:10]
|
||||
|
||||
pending_payment_total = DestinataerUnterstuetzung.objects.filter(
|
||||
status__in=['geplant', 'faellig', 'in_bearbeitung'],
|
||||
).aggregate(total=Coalesce(Sum('betrag'), Decimal('0')))['total']
|
||||
|
||||
# ── New emails ──
|
||||
new_emails = DestinataerEmailEingang.objects.filter(
|
||||
status='neu',
|
||||
).order_by('-eingangsdatum')[:5]
|
||||
new_email_count = DestinataerEmailEingang.objects.filter(status='neu').count()
|
||||
|
||||
# ── Expiring leases (next 90 days) ──
|
||||
lease_cutoff = today + timedelta(days=90)
|
||||
expiring_leases = LandVerpachtung.objects.filter(
|
||||
pachtende__lte=lease_cutoff,
|
||||
pachtende__gte=today,
|
||||
).select_related('paechter', 'land').order_by('pachtende')[:5]
|
||||
|
||||
# ── Recent audit log ──
|
||||
recent_audit = AuditLog.objects.order_by('-timestamp')[:5]
|
||||
|
||||
context = {
|
||||
"title": "Stiftungsverwaltung",
|
||||
"description": "Foundation Management System",
|
||||
"upcoming_events": upcoming_events[:5], # Show only 5 upcoming events
|
||||
"overdue_events": overdue_events[:3], # Show only 3 overdue events
|
||||
"current_month_events": current_month_events,
|
||||
"title": "Dashboard",
|
||||
# Stats
|
||||
"destinataer_count": destinataer_count,
|
||||
"paechter_count": paechter_count,
|
||||
"land_count": land_count,
|
||||
"foerderung_active": foerderung_active,
|
||||
# Calendar
|
||||
"upcoming_events": upcoming_events[:5],
|
||||
"overdue_events": overdue_events[:3],
|
||||
"today": today,
|
||||
# Action items
|
||||
"overdue_nachweise": overdue_nachweise,
|
||||
"pending_payments": pending_payments,
|
||||
"pending_payment_total": pending_payment_total,
|
||||
"new_emails": new_emails,
|
||||
"new_email_count": new_email_count,
|
||||
"expiring_leases": expiring_leases,
|
||||
"recent_audit": recent_audit,
|
||||
"current_quarter": current_quarter,
|
||||
"current_year": current_year,
|
||||
}
|
||||
|
||||
|
||||
return render(request, "stiftung/home.html", context)
|
||||
|
||||
|
||||
@@ -106,12 +154,7 @@ def health_check(request):
|
||||
)
|
||||
|
||||
|
||||
## Removed duplicate paperless_ping referencing non-existent PAPERLESS_URL
|
||||
|
||||
|
||||
# CSV Import Views
|
||||
@api_view(["GET"])
|
||||
def health(_request):
|
||||
return Response({"status": "ok"})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user