"""Bill model for legislative bills linked to campaigns."""
from django.core.exceptions import ValidationError
from django.db import models
from coalition.campaigns.constants import BILL_PREFIXES, CHAMBER_CHOICES, LEVEL_CHOICES
[docs]
class Bill(models.Model):
"""Model representing legislative bills at federal and state levels."""
[docs]
level = models.CharField(
max_length=10,
choices=LEVEL_CHOICES,
default="federal",
help_text="Whether this is a federal or state bill",
)
[docs]
policy = models.ForeignKey(
"campaigns.PolicyCampaign",
on_delete=models.CASCADE,
related_name="bills",
help_text="The policy campaign this bill supports",
)
[docs]
number = models.CharField(
max_length=50,
help_text="Bill number without prefix (e.g., '123' not 'H.R. 123')",
)
[docs]
title = models.CharField(
max_length=255,
help_text="Official title of the bill",
)
[docs]
chamber = models.CharField(
max_length=25,
choices=CHAMBER_CHOICES,
help_text="Legislative chamber where bill was introduced",
)
[docs]
session = models.CharField(
max_length=20,
default="119",
help_text=(
"Congressional session (e.g., '118') or state session (e.g., '2023-2024')"
),
)
[docs]
state = models.ForeignKey(
"regions.Region",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="bills",
help_text="State for state-level bills",
)
[docs]
introduced_date = models.DateField(
help_text="Date the bill was introduced",
)
[docs]
status = models.CharField(
max_length=100,
blank=True,
help_text="Current status of the bill (e.g., 'In Committee', 'Passed House')",
)
[docs]
url = models.URLField(
blank=True,
help_text="Link to official bill text or legislative tracking page",
)
[docs]
is_primary = models.BooleanField(
default=False,
help_text="Whether this is the primary bill for the campaign",
)
[docs]
def __str__(self) -> str:
if self.level == "federal":
prefix = BILL_PREFIXES.get(self.chamber, "")
return f"{prefix} {self.number}"
else:
# For state bills, include state name
state_name = self.state.name if self.state else "Unknown State"
prefix = BILL_PREFIXES.get(self.chamber, "B")
return f"{state_name} {prefix} {self.number}"
[docs]
def clean(self) -> None:
super().clean()
if self.level == "state" and not self.state:
raise ValidationError("State bills must have a state specified")
if self.level == "federal" and self.state:
raise ValidationError("Federal bills should not have a state specified")