from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.db import models from django_choices_field.fields import TextChoicesField from core.models import Customer from core.models.base import Contact from core.models.enums import StatusChoices, RoleChoices class Profile(Contact): """Base profile class with common functionality""" user = models.OneToOneField( User, on_delete=models.SET_NULL, related_name='%(class)s', null=True, blank=True, help_text="Optional Django user for admin access only" ) status = TextChoicesField(choices_enum=StatusChoices, default=StatusChoices.ACTIVE, help_text="Current status of the profile") notes = models.TextField(blank=True, default="", verbose_name="Notes") ory_kratos_id = models.CharField( max_length=255, unique=True, null=True, blank=True, verbose_name="Ory Kratos Identity ID", help_text="Unique identifier from Ory Kratos authentication system" ) email = models.EmailField(null=True, blank=True) class Meta: abstract = True ordering = ['last_name', 'first_name'] def save(self, *args, **kwargs): # Validate new users against existing profiles (if user is set) # Strict enforcement of one profile per user if not self.pk and self.user: profile_types = [CustomerProfile, TeamProfile] current_type = type(self) for profile_type in profile_types: if profile_type != current_type: if profile_type.objects.filter(user=self.user).exists(): raise ValidationError( f"User already has a {profile_type.__name__}. " f"Cannot create {current_type.__name__}." ) super().save(*args, **kwargs) class CustomerProfile(Profile): """External/public-facing customer accounts""" customers = models.ManyToManyField( Customer, related_name='profiles', blank=True, help_text="Customers this profile has access to" ) class Meta: verbose_name = "Customer Profile" verbose_name_plural = "Customer Profiles" class TeamProfile(Profile): """Internal team member accounts""" role = TextChoicesField(choices_enum=RoleChoices, default=RoleChoices.TEAM_MEMBER, help_text="Role of the team member") class Meta: verbose_name = "Team Profile" verbose_name_plural = "Team Profiles"