import pghistory from django.contrib.postgres.fields import ArrayField from django.db import models from django.utils.text import slugify from apps.core.choices.fields import RichChoiceField from apps.core.models import TrackedModel @pghistory.track() class Company(TrackedModel): # Import managers from ..managers import CompanyManager 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( RichChoiceField(choice_group="company_roles", domain="parks", max_length=20), default=list, blank=True, help_text="Company roles (operator, manufacturer, etc.)", ) description = models.TextField(blank=True, help_text="Detailed company description") website = models.URLField(blank=True, help_text="Company website URL") # Person/Entity Type - using RichChoiceField person_type = RichChoiceField( choice_group="person_types", domain="parks", max_length=20, blank=True, help_text="Type of entity (individual, firm, organization, etc.)", ) # Company Status - using RichChoiceField status = RichChoiceField( choice_group="company_statuses", domain="parks", max_length=20, 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") founded_date_precision = RichChoiceField( choice_group="date_precision", domain="parks", max_length=20, 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") # Image ID fields (for frontend submissions - Cloudflare image IDs) logo_image_id = models.CharField( max_length=255, blank=True, help_text="Cloudflare image ID for logo image", ) banner_image_id = models.CharField( max_length=255, blank=True, help_text="Cloudflare image ID for banner image", ) card_image_id = models.CharField( max_length=255, blank=True, help_text="Cloudflare image ID for card image", ) # Location relationship (for headquarters coordinates) location = models.ForeignKey( "ParkLocation", on_delete=models.SET_NULL, null=True, blank=True, related_name="companies_hq", help_text="Linked location record for headquarters", ) # Text-based headquarters location (matches frontend schema) headquarters_location = models.CharField( max_length=200, blank=True, help_text="Headquarters location description (e.g., 'Los Angeles, CA, USA')", ) # 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)") # Submission metadata fields (from frontend schema) source_url = models.URLField( blank=True, help_text="Source URL for the data (e.g., official website, Wikipedia)", ) is_test_data = models.BooleanField( default=False, help_text="Whether this is test/development data", ) def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) def __str__(self): return self.name class Meta(TrackedModel.Meta): app_label = "parks" verbose_name = "Company" verbose_name_plural = "Companies" ordering = ["name"] @pghistory.track() class CompanyHeadquarters(models.Model): """ Simple address storage for company headquarters without coordinate tracking. Focus on human-readable location information for display purposes. """ # Relationships company = models.OneToOneField( "Company", on_delete=models.CASCADE, related_name="headquarters", help_text="Company this headquarters belongs to", ) # Address Fields (No coordinates needed) street_address = models.CharField( max_length=255, blank=True, help_text="Mailing address if publicly available", ) city = models.CharField(max_length=100, db_index=True, help_text="Headquarters city") state_province = models.CharField( max_length=100, blank=True, db_index=True, help_text="State/Province/Region", ) country = models.CharField( max_length=100, default="USA", db_index=True, help_text="Country where headquarters is located", ) postal_code = models.CharField(max_length=20, blank=True, help_text="ZIP or postal code") # Optional mailing address if different or more complete mailing_address = models.TextField( blank=True, help_text="Complete mailing address if different from basic address", ) # Metadata created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @property def formatted_location(self): """Returns a formatted address string for display.""" components = [] if self.street_address: components.append(self.street_address) if self.city: components.append(self.city) if self.state_province: components.append(self.state_province) if self.postal_code: components.append(self.postal_code) if self.country and self.country != "USA": components.append(self.country) return ", ".join(components) if components else f"{self.city}, {self.country}" @property def location_display(self): """Simple city, state/country display for compact views.""" parts = [self.city] if self.state_province: parts.append(self.state_province) elif self.country != "USA": parts.append(self.country) return ", ".join(parts) if parts else "Unknown Location" def __str__(self): return f"{self.company.name} Headquarters - {self.location_display}" class Meta: verbose_name = "Company Headquarters" verbose_name_plural = "Company Headquarters" ordering = ["company__name"] indexes = [ models.Index(fields=["city", "country"]), ]