from django.db import models from django.utils.text import slugify from django.contrib.auth.models import User class Tenant(models.Model): name = models.CharField(max_length=255) slug = models.SlugField(unique=True, blank=True) description = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) 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 TenantUserRole(models.Model): ROLE_CHOICES = [ ('system_admin', 'System Administrator'), ('campaign_admin', 'Campaign Administrator'), ('campaign_staff', 'Campaign Staff'), ] user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tenant_roles') tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='user_roles') role = models.CharField(max_length=20, choices=ROLE_CHOICES) class Meta: unique_together = ('user', 'tenant', 'role') def __str__(self): return f"{self.user.username} - {self.tenant.name} ({self.role})" class InteractionType(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='interaction_types') name = models.CharField(max_length=100) is_active = models.BooleanField(default=True) class Meta: unique_together = ('tenant', 'name') def __str__(self): return f"{self.name} ({self.tenant.name})" class DonationMethod(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='donation_methods') name = models.CharField(max_length=100) is_active = models.BooleanField(default=True) class Meta: unique_together = ('tenant', 'name') def __str__(self): return f"{self.name} ({self.tenant.name})" class ElectionType(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='election_types') name = models.CharField(max_length=100) is_active = models.BooleanField(default=True) class Meta: unique_together = ('tenant', 'name') def __str__(self): return f"{self.name} ({self.tenant.name})" class EventType(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='event_types') name = models.CharField(max_length=100) is_active = models.BooleanField(default=True) class Meta: unique_together = ('tenant', 'name') def __str__(self): return f"{self.name} ({self.tenant.name})" class Voter(models.Model): SUPPORT_CHOICES = [ ('unknown', 'Unknown'), ('supporting', 'Supporting'), ('not_supporting', 'Not Supporting'), ] YARD_SIGN_CHOICES = [ ('none', 'None'), ('wants', 'Wants a yard sign'), ('has', 'Has a yard sign'), ] tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='voters') voter_id = models.CharField(max_length=50, blank=True) first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) address = models.TextField(blank=True) phone = models.CharField(max_length=20, blank=True) email = models.EmailField(blank=True) district = models.CharField(max_length=100, blank=True) precinct = models.CharField(max_length=100, blank=True) registration_date = models.DateField(null=True, blank=True) candidate_support = models.CharField(max_length=20, choices=SUPPORT_CHOICES, default='unknown') yard_sign = models.CharField(max_length=20, choices=YARD_SIGN_CHOICES, default='none') created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.first_name} {self.last_name}" class VotingRecord(models.Model): voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='voting_records') election_date = models.DateField() election_description = models.CharField(max_length=255) primary_party = models.CharField(max_length=100, blank=True) def __str__(self): return f"{self.voter} - {self.election_description}" class Event(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='events') date = models.DateField() event_type = models.ForeignKey(EventType, on_delete=models.PROTECT, null=True) description = models.TextField(blank=True) def __str__(self): return f"{self.event_type} on {self.date}" class EventParticipation(models.Model): event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='participations') voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='event_participations') def __str__(self): return f"{self.voter} at {self.event}" class Donation(models.Model): voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='donations') date = models.DateField() method = models.ForeignKey(DonationMethod, on_delete=models.SET_NULL, null=True) amount = models.DecimalField(max_digits=10, decimal_places=2) def __str__(self): return f"{self.voter} - {self.amount} on {self.date}" class Interaction(models.Model): voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='interactions') type = models.ForeignKey(InteractionType, on_delete=models.SET_NULL, null=True) date = models.DateField() description = models.CharField(max_length=255) notes = models.TextField(blank=True) def __str__(self): return f"{self.voter} - {self.type} on {self.date}" class VoterLikelihood(models.Model): LIKELIHOOD_CHOICES = [ ('not_likely', 'Not Likely'), ('somewhat_likely', 'Somewhat Likely'), ('very_likely', 'Very Likely'), ] voter = models.ForeignKey(Voter, on_delete=models.CASCADE, related_name='likelihoods') election_type = models.ForeignKey(ElectionType, on_delete=models.CASCADE) likelihood = models.CharField(max_length=20, choices=LIKELIHOOD_CHOICES) class Meta: unique_together = ('voter', 'election_type') def __str__(self): return f"{self.voter} - {self.election_type}: {self.get_likelihood_display()}"