feat: add management commands to initialize and run scheduled tasks

This commit is contained in:
Karl Determe 2026-08-14 20:56:38 +02:00
parent d3484e626d
commit 6fb2e00a54
2 changed files with 48 additions and 13 deletions

View file

@ -24,7 +24,7 @@ class Command(BaseCommand):
exports_dir = os.path.join('exports')
if not os.path.exists(exports_dir):
os.makedirs(exports_dir)
self.stdout.write(self.style.SUCCESS(f'✓ Répertoire créé: {exports_dir}'))
self.stdout.write(self.style.SUCCESS(f'[OK] Répertoire créé: {exports_dir}'))
# 1. Tâche d'export mensuel des interventions
task_name = "Export mensuel des interventions"
@ -62,7 +62,7 @@ interventions_export_YYYY_MM.xlsx
task.next_run = task.calculate_next_run()
task.save()
self.stdout.write(self.style.SUCCESS(f'\n✓ Tâche créée: {task_name}'))
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name}'))
self.stdout.write(f' - Fréquence: {task.get_frequency_display()}')
self.stdout.write(f' - Planning: Le {task.day_of_month} de chaque mois à {task.hour:02d}:{task.minute:02d}')
self.stdout.write(f' - Prochaine exécution: {task.next_run.strftime("%Y-%m-%d %H:%M")}')
@ -111,7 +111,7 @@ Données conservées dans le résumé:
task2.next_run = task2.calculate_next_run()
task2.save()
self.stdout.write(self.style.SUCCESS(f'\n✓ Tâche créée: {task_name_analytics}'))
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name_analytics}'))
self.stdout.write(f' - Fréquence: {task2.get_frequency_display()}')
self.stdout.write(f' - Planning: Tous les jours à {task2.hour:02d}:{task2.minute:02d}')
self.stdout.write(f' - Prochaine exécution: {task2.next_run.strftime("%Y-%m-%d %H:%M")}')
@ -158,7 +158,7 @@ Arguments disponibles :
task3.next_run = task3.calculate_next_run()
task3.save()
self.stdout.write(self.style.SUCCESS(f'\n✓ Tâche créée: {task_name_daily}'))
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name_daily}'))
self.stdout.write(f' - Fréquence: {task3.get_frequency_display()}')
self.stdout.write(f' - Planning: Tous les jours à {task3.hour:02d}:{task3.minute:02d}')
self.stdout.write(f' - Statut: {"Active" if task3.is_active else "Inactive (à activer si nécessaire)"}')
@ -200,7 +200,7 @@ Arguments disponibles :
task4.next_run = task4.calculate_next_run()
task4.save()
self.stdout.write(self.style.SUCCESS(f'\n✓ Tâche créée: {task_name_reporting}'))
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name_reporting}'))
self.stdout.write(f' - Fréquence: {task4.get_frequency_display()}')
self.stdout.write(f' - Planning: Tous les jours à {task4.hour:02d}:{task4.minute:02d}')
self.stdout.write(f' - Prochaine exécution: {task4.next_run.strftime("%Y-%m-%d %H:%M")}')
@ -237,7 +237,7 @@ Les observations liées sont également clôturées.
task5.next_run = task5.calculate_next_run()
task5.save()
self.stdout.write(self.style.SUCCESS(f'\n✓ Tâche créée: {task_name_auto_close}'))
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name_auto_close}'))
self.stdout.write(f' - Fréquence: {task5.get_frequency_display()}')
self.stdout.write(f' - Planning: Tous les jours à {task5.hour:02d}:{task5.minute:02d}')
self.stdout.write(f' - Prochaine exécution: {task5.next_run.strftime("%Y-%m-%d %H:%M")}')
@ -280,7 +280,7 @@ Elle effectue les actions suivantes :
task6.next_run = task6.calculate_next_run()
task6.save()
self.stdout.write(self.style.SUCCESS(f'\n✓ Tâche créée: {task_name_backup}'))
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name_backup}'))
self.stdout.write(f' - Fréquence: {task6.get_frequency_display()}')
self.stdout.write(f' - Planning: Tous les jours à {task6.hour:02d}:{task6.minute:02d}')
self.stdout.write(f' - Prochaine exécution: {task6.next_run.strftime("%Y-%m-%d %H:%M")}')
@ -290,6 +290,41 @@ Elle effectue les actions suivantes :
if task6.next_run:
self.stdout.write(f' - Prochaine exécution: {task6.next_run.strftime("%Y-%m-%d %H:%M")}')
# 7. Rappel par e-mail des notifications non lues
task_name_notif_reminders = "Rappels des notifications non lues"
task7, created7 = ScheduledCommand.objects.get_or_create(
name=task_name_notif_reminders,
defaults={
'command_name': 'send_unread_notification_reminders',
'command_args': {},
'frequency': 'hourly',
'minute': 0,
'is_active': True,
'send_email': False,
'description': '''
Envoie un e-mail de rappel aux utilisateurs ayant activé l'option et ayant des notifications non lues depuis plus que le délai configuré.
La tâche s'exécute toutes les heures.
Chaque utilisateur configure son délai et ses préférences dans la page /notifications/settings/.
'''.strip()
}
)
if created7:
task7.next_run = task7.calculate_next_run()
task7.save()
self.stdout.write(self.style.SUCCESS(f'\n[OK] Tâche créée: {task_name_notif_reminders}'))
self.stdout.write(f' - Fréquence: {task7.get_frequency_display()}')
self.stdout.write(f' - Planning: Toutes les heures à :00')
self.stdout.write(f' - Prochaine exécution: {task7.next_run.strftime("%Y-%m-%d %H:%M")}')
else:
self.stdout.write(self.style.WARNING(f'\n! Tâche déjà existante: {task_name_notif_reminders}'))
self.stdout.write(f' - Statut: {"Active" if task7.is_active else "Inactive"}')
if task7.next_run:
self.stdout.write(f' - Prochaine exécution: {task7.next_run.strftime("%Y-%m-%d %H:%M")}')
self.stdout.write(self.style.SUCCESS('\n=== Initialisation terminée ==='))
self.stdout.write('\nPour gérer les tâches planifiées:')
self.stdout.write(' 1. Accédez à l\'admin Django: /admin/')

View file

@ -39,7 +39,7 @@ class Command(BaseCommand):
for task in tasks:
if task.should_run_now():
tasks_to_run.append(task)
self.stdout.write(self.style.SUCCESS(f' ✓ {task.name} doit être exécutée'))
self.stdout.write(self.style.SUCCESS(f' [OK] {task.name} doit être exécutée'))
else:
next_run = task.next_run.strftime('%Y-%m-%d %H:%M') if task.next_run else 'Non planifiée'
self.stdout.write(f' - {task.name} : prochaine exécution le {next_run}')
@ -101,7 +101,7 @@ class Command(BaseCommand):
task.next_run = task.calculate_next_run()
task.save()
self.stdout.write(self.style.SUCCESS(f' ✓ Succès (durée: {log.duration_seconds:.1f}s)'))
self.stdout.write(self.style.SUCCESS(f' [OK] Succès (durée: {log.duration_seconds:.1f}s)'))
# Envoyer l'email si configuré
if task.send_email and task.email_recipients:
@ -125,7 +125,7 @@ class Command(BaseCommand):
task.next_run = task.calculate_next_run()
task.save()
self.stdout.write(self.style.ERROR(f' ✗ Erreur: {str(e)}'))
self.stdout.write(self.style.ERROR(f' [ERREUR] Erreur: {str(e)}'))
# Envoyer l'email d'erreur si configuré
if task.send_email and task.email_recipients:
@ -175,17 +175,17 @@ StreetUp - Système de tâches planifiées
# Attacher le fichier si il existe
if output_file and os.path.exists(output_file):
email.attach_file(output_file)
self.stdout.write(self.style.SUCCESS(f' ✓ Fichier attaché: {output_file}'))
self.stdout.write(self.style.SUCCESS(f' [OK] Fichier attaché: {output_file}'))
email.send(fail_silently=False)
log.email_sent = True
log.save(update_fields=['email_sent'])
self.stdout.write(self.style.SUCCESS(f' ✓ Email envoyé à: {", ".join(recipients)}'))
self.stdout.write(self.style.SUCCESS(f' [OK] Email envoyé à: {", ".join(recipients)}'))
except Exception as e:
self.stdout.write(self.style.ERROR(f' ✗ Erreur lors de l\'envoi de l\'email: {str(e)}'))
self.stdout.write(self.style.ERROR(f' [ERREUR] Erreur lors de l\'envoi de l\'email: {str(e)}'))
def send_error_email(self, task, log):
"""