""" Celery tasks for rides app. This module contains background tasks for ride management including: - Automatic status transitions for closing rides """ import logging from celery import shared_task from django.contrib.auth import get_user_model from django.db import transaction from django.utils import timezone logger = logging.getLogger(__name__) User = get_user_model() @shared_task(name="rides.check_overdue_closings") def check_overdue_closings() -> dict: """ Check for rides in CLOSING status that have reached their closing_date and automatically transition them to their post_closing_status. This task should be run daily via Celery Beat. Returns: dict: Summary with counts of processed, succeeded, and failed rides """ from apps.rides.models import Ride logger.info("Starting overdue closings check") # Get or create system user for automated transitions system_user = _get_system_user() # Query rides that need transition today = timezone.now().date() overdue_rides = Ride.objects.filter( status="CLOSING", closing_date__lte=today ).select_for_update() processed = 0 succeeded = 0 failed = 0 failures = [] for ride in overdue_rides: processed += 1 try: with transaction.atomic(): ride.apply_post_closing_status(user=system_user) succeeded += 1 logger.info( "Successfully transitioned ride %s (%s) from CLOSING to %s", ride.id, ride.name, ride.status, ) except Exception as e: failed += 1 error_msg = f"Ride {ride.id} ({ride.name}): {str(e)}" failures.append(error_msg) logger.error( "Failed to transition ride %s (%s): %s", ride.id, ride.name, str(e), exc_info=True, ) result = { "processed": processed, "succeeded": succeeded, "failed": failed, "failures": failures, "date": today.isoformat(), } logger.info( "Completed overdue closings check: %s processed, %s succeeded, %s failed", processed, succeeded, failed, ) return result def _get_system_user(): """ Get or create a system user for automated transitions. Returns: User: System user instance """ try: # Try to get existing system user system_user = User.objects.get(username="system") except User.DoesNotExist: # Create system user if it doesn't exist try: system_user = User.objects.create_user( username="system", email="system@thrillwiki.com", is_active=False, is_staff=False, ) logger.info("Created system user for automated tasks") except Exception as e: # If creation fails, try to get moderator or admin user logger.warning( "Failed to create system user, falling back to moderator: %s", str(e) ) try: system_user = User.objects.filter(is_staff=True).first() if not system_user: # Last resort: use any user system_user = User.objects.first() except Exception: system_user = None return system_user