This commit is contained in:
pacnpal
2026-01-02 07:58:58 -05:00
parent b243b17af7
commit 1adba1b804
36 changed files with 6345 additions and 6 deletions

View File

@@ -0,0 +1,251 @@
# Generated by Django 5.2.9 on 2026-01-02 00:10
import apps.core.state_machine.fields
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("parks", "0026_remove_park_insert_insert_remove_park_update_update_and_more"),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name="company",
name="insert_insert",
),
pgtrigger.migrations.RemoveTrigger(
model_name="company",
name="update_update",
),
migrations.AddField(
model_name="company",
name="average_rating",
field=models.DecimalField(
blank=True,
decimal_places=2,
help_text="Average rating from reviews (auto-calculated)",
max_digits=3,
null=True,
),
),
migrations.AddField(
model_name="company",
name="banner_image_url",
field=models.URLField(blank=True, help_text="Banner image for company page header"),
),
migrations.AddField(
model_name="company",
name="card_image_url",
field=models.URLField(blank=True, help_text="Card/thumbnail image for listings"),
),
migrations.AddField(
model_name="company",
name="founded_date",
field=models.DateField(blank=True, help_text="Full founding date if known", null=True),
),
migrations.AddField(
model_name="company",
name="founded_date_precision",
field=models.CharField(
blank=True,
choices=[("YEAR", "Year only"), ("MONTH", "Month and year"), ("DAY", "Full date")],
help_text="Precision of the founding date",
max_length=10,
),
),
migrations.AddField(
model_name="company",
name="logo_url",
field=models.URLField(blank=True, help_text="Company logo image URL"),
),
migrations.AddField(
model_name="company",
name="person_type",
field=models.CharField(
blank=True,
choices=[
("INDIVIDUAL", "Individual"),
("FIRM", "Firm"),
("ORGANIZATION", "Organization"),
("CORPORATION", "Corporation"),
("PARTNERSHIP", "Partnership"),
("GOVERNMENT", "Government Entity"),
],
help_text="Type of entity (individual, firm, organization, etc.)",
max_length=20,
),
),
migrations.AddField(
model_name="company",
name="review_count",
field=models.PositiveIntegerField(default=0, help_text="Total number of reviews (auto-calculated)"),
),
migrations.AddField(
model_name="company",
name="status",
field=models.CharField(
choices=[
("ACTIVE", "Active"),
("DEFUNCT", "Defunct"),
("MERGED", "Merged"),
("ACQUIRED", "Acquired"),
("RENAMED", "Renamed"),
("DORMANT", "Dormant"),
],
default="ACTIVE",
help_text="Current operational status of the company",
max_length=20,
),
),
migrations.AddField(
model_name="companyevent",
name="average_rating",
field=models.DecimalField(
blank=True,
decimal_places=2,
help_text="Average rating from reviews (auto-calculated)",
max_digits=3,
null=True,
),
),
migrations.AddField(
model_name="companyevent",
name="banner_image_url",
field=models.URLField(blank=True, help_text="Banner image for company page header"),
),
migrations.AddField(
model_name="companyevent",
name="card_image_url",
field=models.URLField(blank=True, help_text="Card/thumbnail image for listings"),
),
migrations.AddField(
model_name="companyevent",
name="founded_date",
field=models.DateField(blank=True, help_text="Full founding date if known", null=True),
),
migrations.AddField(
model_name="companyevent",
name="founded_date_precision",
field=models.CharField(
blank=True,
choices=[("YEAR", "Year only"), ("MONTH", "Month and year"), ("DAY", "Full date")],
help_text="Precision of the founding date",
max_length=10,
),
),
migrations.AddField(
model_name="companyevent",
name="logo_url",
field=models.URLField(blank=True, help_text="Company logo image URL"),
),
migrations.AddField(
model_name="companyevent",
name="person_type",
field=models.CharField(
blank=True,
choices=[
("INDIVIDUAL", "Individual"),
("FIRM", "Firm"),
("ORGANIZATION", "Organization"),
("CORPORATION", "Corporation"),
("PARTNERSHIP", "Partnership"),
("GOVERNMENT", "Government Entity"),
],
help_text="Type of entity (individual, firm, organization, etc.)",
max_length=20,
),
),
migrations.AddField(
model_name="companyevent",
name="review_count",
field=models.PositiveIntegerField(default=0, help_text="Total number of reviews (auto-calculated)"),
),
migrations.AddField(
model_name="companyevent",
name="status",
field=models.CharField(
choices=[
("ACTIVE", "Active"),
("DEFUNCT", "Defunct"),
("MERGED", "Merged"),
("ACQUIRED", "Acquired"),
("RENAMED", "Renamed"),
("DORMANT", "Dormant"),
],
default="ACTIVE",
help_text="Current operational status of the company",
max_length=20,
),
),
migrations.AlterField(
model_name="park",
name="status",
field=apps.core.state_machine.fields.RichFSMField(
allow_deprecated=False,
choice_group="statuses",
choices=[
("OPERATING", "Operating"),
("CLOSED_TEMP", "Temporarily Closed"),
("CLOSED_PERM", "Permanently Closed"),
("UNDER_CONSTRUCTION", "Under Construction"),
("DEMOLISHED", "Demolished"),
("RELOCATED", "Relocated"),
],
default="OPERATING",
domain="parks",
max_length=20,
),
),
migrations.AlterField(
model_name="parkevent",
name="status",
field=apps.core.state_machine.fields.RichFSMField(
allow_deprecated=False,
choice_group="statuses",
choices=[
("OPERATING", "Operating"),
("CLOSED_TEMP", "Temporarily Closed"),
("CLOSED_PERM", "Permanently Closed"),
("UNDER_CONSTRUCTION", "Under Construction"),
("DEMOLISHED", "Demolished"),
("RELOCATED", "Relocated"),
],
default="OPERATING",
domain="parks",
max_length=20,
),
),
pgtrigger.migrations.AddTrigger(
model_name="company",
trigger=pgtrigger.compiler.Trigger(
name="insert_insert",
sql=pgtrigger.compiler.UpsertTriggerSql(
func='INSERT INTO "parks_companyevent" ("average_rating", "banner_image_url", "card_image_url", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "id", "logo_url", "name", "parks_count", "person_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "review_count", "rides_count", "roles", "slug", "status", "updated_at", "website") VALUES (NEW."average_rating", NEW."banner_image_url", NEW."card_image_url", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."id", NEW."logo_url", NEW."name", NEW."parks_count", NEW."person_type", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."review_count", NEW."rides_count", NEW."roles", NEW."slug", NEW."status", NEW."updated_at", NEW."website"); RETURN NULL;',
hash="048dba77acb14b06b8ae12f5f05710f0da71e3fd",
operation="INSERT",
pgid="pgtrigger_insert_insert_35b57",
table="parks_company",
when="AFTER",
),
),
),
pgtrigger.migrations.AddTrigger(
model_name="company",
trigger=pgtrigger.compiler.Trigger(
name="update_update",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
func='INSERT INTO "parks_companyevent" ("average_rating", "banner_image_url", "card_image_url", "created_at", "description", "founded_date", "founded_date_precision", "founded_year", "id", "logo_url", "name", "parks_count", "person_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "review_count", "rides_count", "roles", "slug", "status", "updated_at", "website") VALUES (NEW."average_rating", NEW."banner_image_url", NEW."card_image_url", NEW."created_at", NEW."description", NEW."founded_date", NEW."founded_date_precision", NEW."founded_year", NEW."id", NEW."logo_url", NEW."name", NEW."parks_count", NEW."person_type", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."review_count", NEW."rides_count", NEW."roles", NEW."slug", NEW."status", NEW."updated_at", NEW."website"); RETURN NULL;',
hash="4a93422ca4b79608f941be5baed899d691d88d97",
operation="UPDATE",
pgid="pgtrigger_update_update_d3286",
table="parks_company",
when="AFTER",
),
),
),
]

View File

@@ -0,0 +1,96 @@
# Generated by Django 5.2.9 on 2026-01-02 02:30
import pgtrigger.compiler
import pgtrigger.migrations
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("parks", "0027_add_company_entity_fields"),
]
operations = [
pgtrigger.migrations.RemoveTrigger(
model_name="park",
name="insert_insert",
),
pgtrigger.migrations.RemoveTrigger(
model_name="park",
name="update_update",
),
migrations.AddField(
model_name="park",
name="closing_date_precision",
field=models.CharField(
blank=True,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
help_text="Precision of the closing date",
max_length=10,
),
),
migrations.AddField(
model_name="park",
name="opening_date_precision",
field=models.CharField(
blank=True,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
help_text="Precision of the opening date (YEAR for circa dates)",
max_length=10,
),
),
migrations.AddField(
model_name="parkevent",
name="closing_date_precision",
field=models.CharField(
blank=True,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
help_text="Precision of the closing date",
max_length=10,
),
),
migrations.AddField(
model_name="parkevent",
name="opening_date_precision",
field=models.CharField(
blank=True,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
help_text="Precision of the opening date (YEAR for circa dates)",
max_length=10,
),
),
pgtrigger.migrations.AddTrigger(
model_name="park",
trigger=pgtrigger.compiler.Trigger(
name="insert_insert",
sql=pgtrigger.compiler.UpsertTriggerSql(
func='INSERT INTO "parks_parkevent" ("average_rating", "banner_image_id", "card_image_id", "closing_date", "closing_date_precision", "coaster_count", "created_at", "description", "email", "id", "name", "opening_date", "opening_date_precision", "opening_year", "operating_season", "operator_id", "park_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "phone", "property_owner_id", "ride_count", "search_text", "size_acres", "slug", "status", "timezone", "updated_at", "url", "website") VALUES (NEW."average_rating", NEW."banner_image_id", NEW."card_image_id", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_count", NEW."created_at", NEW."description", NEW."email", NEW."id", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."operating_season", NEW."operator_id", NEW."park_type", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."phone", NEW."property_owner_id", NEW."ride_count", NEW."search_text", NEW."size_acres", NEW."slug", NEW."status", NEW."timezone", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;',
hash="ba8a1efa2a6987e5803856a7d583d15379374976",
operation="INSERT",
pgid="pgtrigger_insert_insert_66883",
table="parks_park",
when="AFTER",
),
),
),
pgtrigger.migrations.AddTrigger(
model_name="park",
trigger=pgtrigger.compiler.Trigger(
name="update_update",
sql=pgtrigger.compiler.UpsertTriggerSql(
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
func='INSERT INTO "parks_parkevent" ("average_rating", "banner_image_id", "card_image_id", "closing_date", "closing_date_precision", "coaster_count", "created_at", "description", "email", "id", "name", "opening_date", "opening_date_precision", "opening_year", "operating_season", "operator_id", "park_type", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "phone", "property_owner_id", "ride_count", "search_text", "size_acres", "slug", "status", "timezone", "updated_at", "url", "website") VALUES (NEW."average_rating", NEW."banner_image_id", NEW."card_image_id", NEW."closing_date", NEW."closing_date_precision", NEW."coaster_count", NEW."created_at", NEW."description", NEW."email", NEW."id", NEW."name", NEW."opening_date", NEW."opening_date_precision", NEW."opening_year", NEW."operating_season", NEW."operator_id", NEW."park_type", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."phone", NEW."property_owner_id", NEW."ride_count", NEW."search_text", NEW."size_acres", NEW."slug", NEW."status", NEW."timezone", NEW."updated_at", NEW."url", NEW."website"); RETURN NULL;',
hash="03e752224a0f76749f4348abf48cb9e6929c9e19",
operation="UPDATE",
pgid="pgtrigger_update_update_19f56",
table="parks_park",
when="AFTER",
),
),
),
]

View File

@@ -14,6 +14,7 @@ class Company(TrackedModel):
objects = CompanyManager()
# Core Fields
name = models.CharField(max_length=255, help_text="Company name")
slug = models.SlugField(max_length=255, unique=True, help_text="URL-friendly identifier")
roles = ArrayField(
@@ -25,8 +26,72 @@ class Company(TrackedModel):
description = models.TextField(blank=True, help_text="Detailed company description")
website = models.URLField(blank=True, help_text="Company website URL")
# Operator-specific fields
# Person/Entity Type (ported from legacy thrillwiki-87)
PERSON_TYPES = [
("INDIVIDUAL", "Individual"),
("FIRM", "Firm"),
("ORGANIZATION", "Organization"),
("CORPORATION", "Corporation"),
("PARTNERSHIP", "Partnership"),
("GOVERNMENT", "Government Entity"),
]
person_type = models.CharField(
max_length=20,
choices=PERSON_TYPES,
blank=True,
help_text="Type of entity (individual, firm, organization, etc.)",
)
# Company Status (ported from legacy)
COMPANY_STATUSES = [
("ACTIVE", "Active"),
("DEFUNCT", "Defunct"),
("MERGED", "Merged"),
("ACQUIRED", "Acquired"),
("RENAMED", "Renamed"),
("DORMANT", "Dormant"),
]
status = models.CharField(
max_length=20,
choices=COMPANY_STATUSES,
default="ACTIVE",
help_text="Current operational status of the company",
)
# Founding Information (enhanced from just founded_year)
founded_year = models.PositiveIntegerField(blank=True, null=True, help_text="Year the company was founded")
founded_date = models.DateField(blank=True, null=True, help_text="Full founding date if known")
DATE_PRECISION_CHOICES = [
("YEAR", "Year only"),
("MONTH", "Month and year"),
("DAY", "Full date"),
]
founded_date_precision = models.CharField(
max_length=10,
choices=DATE_PRECISION_CHOICES,
blank=True,
help_text="Precision of the founding date",
)
# Image URLs (ported from legacy)
logo_url = models.URLField(blank=True, help_text="Company logo image URL")
banner_image_url = models.URLField(blank=True, help_text="Banner image for company page header")
card_image_url = models.URLField(blank=True, help_text="Card/thumbnail image for listings")
# Rating & Review Aggregates (computed fields, updated by triggers/signals)
average_rating = models.DecimalField(
max_digits=3,
decimal_places=2,
blank=True,
null=True,
help_text="Average rating from reviews (auto-calculated)",
)
review_count = models.PositiveIntegerField(
default=0,
help_text="Total number of reviews (auto-calculated)",
)
# Counts (auto-calculated)
parks_count = models.IntegerField(default=0, help_text="Number of parks operated (auto-calculated)")
rides_count = models.IntegerField(default=0, help_text="Number of rides manufactured (auto-calculated)")

View File

@@ -54,7 +54,21 @@ class Park(StateMachineMixin, TrackedModel):
# Details
opening_date = models.DateField(null=True, blank=True, help_text="Opening date")
opening_date_precision = models.CharField(
max_length=10,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
blank=True,
help_text="Precision of the opening date (YEAR for circa dates)",
)
closing_date = models.DateField(null=True, blank=True, help_text="Closing date")
closing_date_precision = models.CharField(
max_length=10,
choices=[("YEAR", "Year"), ("MONTH", "Month"), ("DAY", "Day")],
default="DAY",
blank=True,
help_text="Precision of the closing date",
)
operating_season = models.CharField(max_length=255, blank=True, help_text="Operating season")
size_acres = models.DecimalField(
max_digits=10, decimal_places=2, null=True, blank=True, help_text="Park size in acres"
@@ -310,6 +324,14 @@ class Park(StateMachineMixin, TrackedModel):
return self.location.formatted_address
return ""
@property
def is_closing(self) -> bool:
"""Returns True if this park has a closing date in the future (announced closure)."""
from django.utils import timezone
if self.closing_date:
return self.closing_date > timezone.now().date()
return False
@property
def coordinates(self) -> list[float] | None:
"""Returns coordinates as a list [latitude, longitude]"""