mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 13:51:09 -05:00
chore: fix pghistory migration deps and improve htmx utilities
- 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
This commit is contained in:
@@ -3,9 +3,11 @@ from django.utils.text import slugify
|
||||
from config.django import base as settings
|
||||
from apps.core.models import TrackedModel
|
||||
from apps.core.choices import RichChoiceField
|
||||
from apps.core.state_machine import RichFSMField, StateMachineMixin
|
||||
from .company import Company
|
||||
import pghistory
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from django.contrib.auth.models import AbstractBaseUser
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .rides import RollerCoasterStats
|
||||
@@ -430,7 +432,7 @@ class RideModelTechnicalSpec(TrackedModel):
|
||||
|
||||
|
||||
@pghistory.track()
|
||||
class Ride(TrackedModel):
|
||||
class Ride(StateMachineMixin, TrackedModel):
|
||||
"""Model for individual ride installations at parks
|
||||
|
||||
Note: The average_rating field is denormalized and refreshed by background
|
||||
@@ -440,6 +442,8 @@ class Ride(TrackedModel):
|
||||
if TYPE_CHECKING:
|
||||
coaster_stats: 'RollerCoasterStats'
|
||||
|
||||
state_field_name = "status"
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
slug = models.SlugField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
@@ -485,7 +489,7 @@ class Ride(TrackedModel):
|
||||
blank=True,
|
||||
help_text="The specific model/type of this ride",
|
||||
)
|
||||
status = RichChoiceField(
|
||||
status = RichFSMField(
|
||||
choice_group="statuses",
|
||||
domain="rides",
|
||||
max_length=20,
|
||||
@@ -602,6 +606,87 @@ class Ride(TrackedModel):
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name} at {self.park.name}"
|
||||
|
||||
# FSM Transition Wrapper Methods
|
||||
def open(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Transition ride to OPERATING status."""
|
||||
self.transition_to_operating(user=user)
|
||||
self.save()
|
||||
|
||||
def close_temporarily(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Transition ride to CLOSED_TEMP status."""
|
||||
self.transition_to_closed_temp(user=user)
|
||||
self.save()
|
||||
|
||||
def mark_sbno(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Transition ride to SBNO (Standing But Not Operating) status."""
|
||||
self.transition_to_sbno(user=user)
|
||||
self.save()
|
||||
|
||||
def mark_closing(
|
||||
self,
|
||||
*,
|
||||
closing_date,
|
||||
post_closing_status: str,
|
||||
user: Optional[AbstractBaseUser] = None,
|
||||
) -> None:
|
||||
"""Transition ride to CLOSING status with closing date and target status."""
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
if not post_closing_status:
|
||||
raise ValidationError(
|
||||
"post_closing_status must be set when entering CLOSING status"
|
||||
)
|
||||
self.transition_to_closing(user=user)
|
||||
self.closing_date = closing_date
|
||||
self.post_closing_status = post_closing_status
|
||||
self.save()
|
||||
|
||||
def close_permanently(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Transition ride to CLOSED_PERM status."""
|
||||
self.transition_to_closed_perm(user=user)
|
||||
self.save()
|
||||
|
||||
def demolish(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Transition ride to DEMOLISHED status."""
|
||||
self.transition_to_demolished(user=user)
|
||||
self.save()
|
||||
|
||||
def relocate(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Transition ride to RELOCATED status."""
|
||||
self.transition_to_relocated(user=user)
|
||||
self.save()
|
||||
|
||||
def apply_post_closing_status(self, *, user: Optional[AbstractBaseUser] = None) -> None:
|
||||
"""Apply post_closing_status if closing_date has been reached."""
|
||||
from django.utils import timezone
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
if self.status != "CLOSING":
|
||||
raise ValidationError("Ride must be in CLOSING status")
|
||||
|
||||
if not self.closing_date:
|
||||
raise ValidationError("closing_date must be set")
|
||||
|
||||
if not self.post_closing_status:
|
||||
raise ValidationError("post_closing_status must be set")
|
||||
|
||||
if timezone.now().date() < self.closing_date:
|
||||
return # Not yet time to transition
|
||||
|
||||
# Transition to the target status
|
||||
if self.post_closing_status == "SBNO":
|
||||
self.transition_to_sbno(user=user)
|
||||
elif self.post_closing_status == "CLOSED_PERM":
|
||||
self.transition_to_closed_perm(user=user)
|
||||
elif self.post_closing_status == "DEMOLISHED":
|
||||
self.transition_to_demolished(user=user)
|
||||
elif self.post_closing_status == "RELOCATED":
|
||||
self.transition_to_relocated(user=user)
|
||||
else:
|
||||
raise ValidationError(f"Invalid post_closing_status: {self.post_closing_status}")
|
||||
|
||||
self.save()
|
||||
|
||||
def save(self, *args, **kwargs) -> None:
|
||||
# Handle slug generation and conflicts
|
||||
if not self.slug:
|
||||
|
||||
Reference in New Issue
Block a user