diff --git a/MANUAL_SEND_DOCUMENTATION.md b/MANUAL_SEND_DOCUMENTATION.md new file mode 100644 index 0000000..6314212 --- /dev/null +++ b/MANUAL_SEND_DOCUMENTATION.md @@ -0,0 +1,108 @@ +# Manuelle "Sofort senden" Funktion für Automatische Reports + +## Übersicht + +Die neue "Sofort senden" Aktion im Django Admin ermöglicht es Administratoren, automatische Reports manuell und sofort zu versenden, ohne auf den geplanten Zeitpunkt warten zu müssen. + +## Verwendung + +1. **Admin-Bereich öffnen**: Navigieren Sie zu `/admin/reports/automaticreport/` +2. **Reports auswählen**: Wählen Sie einen oder mehrere automatische Reports aus der Liste aus +3. **Aktion ausführen**: Wählen Sie aus dem Aktions-Dropdown "Ausgewählte Reports sofort senden" +4. **Bestätigen**: Klicken Sie auf "Ausführen" + +## Funktionalität + +### Automatische Zeitraumberechnung +Die Aktion berechnet automatisch den Zeitraum basierend auf der Frequenz des Reports: + +- **Wöchentlich**: Letzte 7 Tage +- **Monatlich**: Letzter Monat (vom 1. des Vormonats bis heute) +- **Vierteljährlich**: Letztes Quartal (3 Monate zurück) + +### Validierung und Filterung +Vor dem Versenden wird überprüft: + +- ✅ **Aktivierung**: Report muss aktiv sein (`is_active = True`) +- ✅ **E-Mail-Adressen**: Mindestens eine E-Mail-Adresse muss konfiguriert sein +- ✅ **Filter**: Die konfigurierten Filter (Naturschutz-/Jagdbehörde) werden angewendet + +### Rückmeldungen +Das System gibt detaillierte Rückmeldungen: + +- ✅ **Erfolgreich**: Anzahl gesendeter E-Mails, Zeitraum, Patientenzahl +- ⚠️ **Übersprungen**: Grund für das Überspringen (deaktiviert, keine E-Mail-Adressen) +- ❌ **Fehler**: Detaillierte Fehlermeldungen bei Problemen + +### Protokollierung +- Alle versendeten Reports werden in `ReportLog` protokolliert +- Das `last_sent` Feld des AutomaticReport wird aktualisiert +- CSV-Dateien werden gespeichert und können später heruntergeladen werden + +## Technische Details + +### Implementierung +- **Datei**: `/app/reports/admin.py` +- **Methode**: `send_report_now()` +- **Service**: Verwendet `ReportGenerator` aus `reports.services` + +### Sicherheit +- Nur Administratoren mit entsprechenden Berechtigungen können diese Aktion ausführen +- Deaktivierte Reports werden automatisch übersprungen +- Umfassende Fehlerbehandlung verhindert Systemausfälle + +## Beispiel-Ausgaben + +### Erfolgreicher Versand +``` +✅ Report 'Monatlicher Naturschutzbericht' erfolgreich gesendet (letzter Monat, 15 Patienten, 3 Empfänger). +✅ Zusammenfassung: 1 Report(s) erfolgreich gesendet. +``` + +### Übersprungener Report +``` +⚠️ Report 'Deaktivierter Report' ist deaktiviert und wurde übersprungen. +ℹ️ Alle 1 ausgewählten Reports wurden übersprungen (deaktiviert oder keine E-Mail-Adressen). +``` + +### Fehler beim Versand +``` +❌ Fehler beim Senden von 'Fehlerhafter Report': SMTP-Server nicht erreichbar. +❌ Alle 1 Reports konnten nicht gesendet werden. +``` + +## Troubleshooting + +### Häufige Probleme + +1. **"Report ist deaktiviert"** + - Lösung: Report in der Detail-Ansicht aktivieren (`is_active = True`) + +2. **"Keine E-Mail-Adressen"** + - Lösung: E-Mail-Adressen im Report konfigurieren + +3. **"'Emailadress' object has no attribute 'email'"** + - Technischer Fehler: Das Emailadress-Model verwendet `email_address` statt `email` + - Lösung: Wurde in Version 1.1 behoben + +4. **"SMTP-Fehler"** + - Lösung: E-Mail-Konfiguration in `settings.py` überprüfen + +5. **"Keine Patienten gefunden"** + - Normal: Report wird trotzdem versendet, zeigt 0 Patienten an + +### Log-Überprüfung +- Alle Versandaktivitäten werden in `/admin/reports/reportlog/` protokolliert +- Bei Fehlern die Django-Logs überprüfen + +## Entwickler-Hinweise + +### Anpassungen +- Zeitraumberechnung kann in der `send_report_now()` Methode angepasst werden +- Zusätzliche Validierungen können hinzugefügt werden +- E-Mail-Templates befinden sich in `/templates/reports/email/` + +### Erweiterungen +- Mögliche Erweiterung: Benutzerdefinierte Zeiträume +- Mögliche Erweiterung: Vorschau vor dem Versand +- Mögliche Erweiterung: Stapelverarbeitung mit Fortschrittsanzeige diff --git a/app/reports/admin.py b/app/reports/admin.py index 6da3636..bb134f6 100644 --- a/app/reports/admin.py +++ b/app/reports/admin.py @@ -2,7 +2,11 @@ from django.contrib import admin from django.utils.translation import gettext_lazy as _ from django.utils.html import format_html from django.urls import reverse +from django.contrib import messages +from django.http import HttpResponseRedirect +from datetime import date, timedelta from .models import AutomaticReport, ReportLog +from .services import ReportGenerator @admin.register(AutomaticReport) @@ -19,6 +23,7 @@ class AutomaticReportAdmin(admin.ModelAdmin): list_filter = ['frequency', 'is_active', 'created_at', 'include_naturschutzbehoerde', 'include_jagdbehoerde'] search_fields = ['name', 'description'] readonly_fields = ['created_by', 'created_at', 'updated_at'] + actions = ['send_report_now'] fieldsets = ( (None, { @@ -49,6 +54,117 @@ class AutomaticReportAdmin(admin.ModelAdmin): count = obj.email_addresses.count() return f"{count} E-Mail-Adresse(n)" email_count.short_description = _("E-Mail-Adressen") + + def send_report_now(self, request, queryset): + """Send selected reports immediately.""" + sent_count = 0 + error_count = 0 + skipped_count = 0 + + for report in queryset: + if not report.is_active: + messages.warning( + request, + f"Report '{report.name}' ist deaktiviert und wurde übersprungen." + ) + skipped_count += 1 + continue + + if not report.email_addresses.exists(): + messages.warning( + request, + f"Report '{report.name}' hat keine E-Mail-Adressen und wurde übersprungen." + ) + skipped_count += 1 + continue + + # Get email addresses + email_addresses = [addr.email_address for addr in report.email_addresses.all()] + + # Calculate date range based on frequency + today = date.today() + if report.frequency == 'weekly': + date_from = today - timedelta(days=7) + range_description = "letzte 7 Tage" + elif report.frequency == 'monthly': + # Go back one month + if today.month == 1: + date_from = today.replace(year=today.year-1, month=12, day=1) + else: + date_from = today.replace(month=today.month-1, day=1) + range_description = "letzter Monat" + elif report.frequency == 'quarterly': + # Go back three months + if today.month <= 3: + date_from = today.replace(year=today.year-1, month=today.month+9, day=1) + else: + date_from = today.replace(month=today.month-3, day=1) + range_description = "letztes Quartal" + else: + date_from = today - timedelta(days=30) # Default to 30 days + range_description = "letzte 30 Tage" + + # Generate and send report + try: + generator = ReportGenerator( + date_from=date_from, + date_to=today, + include_naturschutzbehoerde=report.include_naturschutzbehoerde, + include_jagdbehoerde=report.include_jagdbehoerde + ) + + report_log, success, error_msg = generator.send_email_report( + email_addresses=email_addresses, + automatic_report=report + ) + + if success: + # Update last_sent timestamp + report.last_sent = today + report.save(update_fields=['last_sent']) + sent_count += 1 + + # Success message with details + messages.success( + request, + f"Report '{report.name}' erfolgreich gesendet " + f"({range_description}, {report_log.patient_count} Patienten, " + f"{len(email_addresses)} Empfänger)." + ) + else: + error_count += 1 + messages.error( + request, + f"Fehler beim Senden von '{report.name}': {error_msg}" + ) + + except Exception as e: + error_count += 1 + messages.error( + request, + f"Unerwarteter Fehler bei '{report.name}': {str(e)}" + ) + + # Show summary message + if sent_count > 0: + messages.success( + request, + f"Zusammenfassung: {sent_count} Report(s) erfolgreich gesendet" + + (f", {skipped_count} übersprungen" if skipped_count > 0 else "") + + (f", {error_count} Fehler" if error_count > 0 else "") + "." + ) + elif skipped_count > 0 and error_count == 0: + messages.info( + request, + f"Alle {skipped_count} ausgewählten Reports wurden übersprungen (deaktiviert oder keine E-Mail-Adressen)." + ) + elif error_count > 0 and sent_count == 0: + messages.error( + request, + f"Alle {error_count} Reports konnten nicht gesendet werden." + ) + + send_report_now.short_description = _("Ausgewählte Reports sofort senden") @admin.register(ReportLog)