mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 15:31:08 -05:00
- Update pghistory dependency from 0007 to 0006 in account migrations - Add docstrings and remove unused imports in htmx_forms.py - Add DJANGO_SETTINGS_MODULE bash commands to Claude settings - Add state transition definitions for ride statuses
310 lines
8.6 KiB
Python
310 lines
8.6 KiB
Python
"""
|
|
Services for ride-related business logic.
|
|
Following Django styleguide pattern for business logic encapsulation.
|
|
"""
|
|
|
|
from typing import Optional, Dict, Any
|
|
from django.db import transaction
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import AbstractBaseUser
|
|
|
|
from apps.rides.models import Ride
|
|
|
|
# Use AbstractBaseUser for type hinting
|
|
UserType = AbstractBaseUser
|
|
User = get_user_model()
|
|
|
|
|
|
class RideService:
|
|
"""Service for managing ride operations."""
|
|
|
|
@staticmethod
|
|
def create_ride(
|
|
*,
|
|
name: str,
|
|
park_id: int,
|
|
description: str = "",
|
|
status: str = "OPERATING",
|
|
category: str = "",
|
|
manufacturer_id: Optional[int] = None,
|
|
designer_id: Optional[int] = None,
|
|
ride_model_id: Optional[int] = None,
|
|
park_area_id: Optional[int] = None,
|
|
opening_date: Optional[str] = None,
|
|
closing_date: Optional[str] = None,
|
|
created_by: Optional[UserType] = None,
|
|
) -> Ride:
|
|
"""
|
|
Create a new ride with validation.
|
|
|
|
Args:
|
|
name: Ride name
|
|
park_id: ID of the park
|
|
description: Ride description
|
|
status: Operating status
|
|
category: Ride category
|
|
manufacturer_id: ID of manufacturer company
|
|
designer_id: ID of designer company
|
|
ride_model_id: ID of ride model
|
|
park_area_id: ID of park area
|
|
opening_date: Opening date
|
|
closing_date: Closing date
|
|
created_by: User creating the ride
|
|
|
|
Returns:
|
|
Created Ride instance
|
|
|
|
Raises:
|
|
ValidationError: If ride data is invalid
|
|
"""
|
|
with transaction.atomic():
|
|
from apps.parks.models import Park
|
|
|
|
# Get park
|
|
park = Park.objects.get(id=park_id)
|
|
|
|
# Create ride instance
|
|
ride = Ride(
|
|
name=name,
|
|
park=park,
|
|
description=description,
|
|
status=status,
|
|
category=category,
|
|
opening_date=opening_date,
|
|
closing_date=closing_date,
|
|
)
|
|
|
|
# Set foreign key relationships if provided
|
|
if park_area_id:
|
|
from apps.parks.models import ParkArea
|
|
|
|
ride.park_area = ParkArea.objects.get(id=park_area_id)
|
|
|
|
if manufacturer_id:
|
|
from apps.rides.models import Company
|
|
|
|
ride.manufacturer = Company.objects.get(id=manufacturer_id)
|
|
|
|
if designer_id:
|
|
from apps.rides.models import Company
|
|
|
|
ride.designer = Company.objects.get(id=designer_id)
|
|
|
|
if ride_model_id:
|
|
from apps.rides.models import RideModel
|
|
|
|
ride.ride_model = RideModel.objects.get(id=ride_model_id)
|
|
|
|
# CRITICAL STYLEGUIDE FIX: Call full_clean before save
|
|
ride.full_clean()
|
|
ride.save()
|
|
|
|
return ride
|
|
|
|
@staticmethod
|
|
def update_ride(
|
|
*,
|
|
ride_id: int,
|
|
updates: Dict[str, Any],
|
|
updated_by: Optional[UserType] = None,
|
|
) -> Ride:
|
|
"""
|
|
Update an existing ride with validation.
|
|
|
|
Args:
|
|
ride_id: ID of ride to update
|
|
updates: Dictionary of field updates
|
|
updated_by: User performing the update
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
ValidationError: If update data is invalid
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
|
|
# Apply updates
|
|
for field, value in updates.items():
|
|
if hasattr(ride, field):
|
|
setattr(ride, field, value)
|
|
|
|
# CRITICAL STYLEGUIDE FIX: Call full_clean before save
|
|
ride.full_clean()
|
|
ride.save()
|
|
|
|
return ride
|
|
|
|
@staticmethod
|
|
def close_ride_temporarily(
|
|
*, ride_id: int, user: Optional[UserType] = None
|
|
) -> Ride:
|
|
"""
|
|
Temporarily close a ride.
|
|
|
|
Args:
|
|
ride_id: ID of ride to close temporarily
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
ride.close_temporarily(user=user)
|
|
return ride
|
|
|
|
@staticmethod
|
|
def mark_ride_sbno(
|
|
*, ride_id: int, user: Optional[UserType] = None
|
|
) -> Ride:
|
|
"""
|
|
Mark a ride as SBNO (Standing But Not Operating).
|
|
|
|
Args:
|
|
ride_id: ID of ride to mark as SBNO
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
ride.mark_sbno(user=user)
|
|
return ride
|
|
|
|
@staticmethod
|
|
def schedule_ride_closing(
|
|
*,
|
|
ride_id: int,
|
|
closing_date,
|
|
post_closing_status: str,
|
|
user: Optional[UserType] = None,
|
|
) -> Ride:
|
|
"""
|
|
Schedule a ride to close on a specific date with a post-closing status.
|
|
|
|
Args:
|
|
ride_id: ID of ride to schedule for closing
|
|
closing_date: Date when ride will close
|
|
post_closing_status: Status to transition to after closing
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
ValidationError: If post_closing_status is not set
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
ride.mark_closing(
|
|
closing_date=closing_date,
|
|
post_closing_status=post_closing_status,
|
|
user=user,
|
|
)
|
|
return ride
|
|
|
|
@staticmethod
|
|
def close_ride_permanently(
|
|
*, ride_id: int, user: Optional[UserType] = None
|
|
) -> Ride:
|
|
"""
|
|
Permanently close a ride.
|
|
|
|
Args:
|
|
ride_id: ID of ride to close permanently
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
ride.close_permanently(user=user)
|
|
return ride
|
|
|
|
@staticmethod
|
|
def demolish_ride(*, ride_id: int, user: Optional[UserType] = None) -> Ride:
|
|
"""
|
|
Mark a ride as demolished.
|
|
|
|
Args:
|
|
ride_id: ID of ride to demolish
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
ride.demolish(user=user)
|
|
return ride
|
|
|
|
@staticmethod
|
|
def relocate_ride(
|
|
*, ride_id: int, new_park_id: int, user: Optional[UserType] = None
|
|
) -> Ride:
|
|
"""
|
|
Relocate a ride to a new park.
|
|
|
|
Args:
|
|
ride_id: ID of ride to relocate
|
|
new_park_id: ID of the new park
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
with transaction.atomic():
|
|
from apps.parks.models import Park
|
|
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
new_park = Park.objects.get(id=new_park_id)
|
|
|
|
# Mark as relocated first
|
|
ride.relocate(user=user)
|
|
|
|
# Move to new park
|
|
ride.move_to_park(new_park, clear_park_area=True)
|
|
|
|
return ride
|
|
|
|
@staticmethod
|
|
def reopen_ride(*, ride_id: int, user: Optional[UserType] = None) -> Ride:
|
|
"""
|
|
Reopen a ride for operation.
|
|
|
|
Args:
|
|
ride_id: ID of ride to reopen
|
|
user: User performing the action
|
|
|
|
Returns:
|
|
Updated Ride instance
|
|
|
|
Raises:
|
|
Ride.DoesNotExist: If ride doesn't exist
|
|
"""
|
|
with transaction.atomic():
|
|
ride = Ride.objects.select_for_update().get(id=ride_id)
|
|
ride.open(user=user)
|
|
return ride
|