from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from accounts.models import Account, AccountEmail, AccountEmailLog from common.serializer import ( AttachmentsSerializer, OrganizationSerializer, ProfileSerializer, TagsSerializer, TeamsSerializer, UserSerializer, ) from contacts.serializer import ContactSerializer # Note: Removed unused serializer properties that were computed but never used by frontend: # - get_team_users, get_team_and_assigned_users, get_assigned_users_not_in_teams # - created_on_arrow (frontend computes its own humanized timestamps) class AccountSerializer(serializers.ModelSerializer): """Serializer for reading Account data""" created_by = UserSerializer() org = OrganizationSerializer() tags = TagsSerializer(read_only=True, many=True) assigned_to = ProfileSerializer(read_only=True, many=True) contacts = ContactSerializer(read_only=True, many=True) teams = TeamsSerializer(read_only=True, many=True) account_attachment = AttachmentsSerializer(read_only=True, many=True) country_display = serializers.SerializerMethodField() cases = serializers.SerializerMethodField() tasks = serializers.SerializerMethodField() opportunities = serializers.SerializerMethodField() @extend_schema_field(str) def get_country_display(self, obj): return obj.get_country_display() if obj.country else None @extend_schema_field(list) def get_cases(self, obj): """Return cases linked to this account""" return [{"id": str(c.id), "name": c.name} for c in obj.accounts_cases.all()] @extend_schema_field(list) def get_tasks(self, obj): """Return tasks linked to this account""" return [{"id": str(t.id), "title": t.title} for t in obj.accounts_tasks.all()] @extend_schema_field(list) def get_opportunities(self, obj): """Return opportunities linked to this account""" return [ { "id": str(o.id), "name": o.name, "stage": o.stage, "amount": str(o.amount) if o.amount else "0", } for o in obj.opportunities.all() ] class Meta: model = Account fields = ( "id", # Core Account Information "name", "email", "phone", "website", # Business Information "industry", "number_of_employees", "annual_revenue", "currency", # Address "address_line", "city", "state", "postcode", "country", "country_display", # Assignment "assigned_to", "teams", "contacts", # Tags "tags", # Notes "description", # Related "account_attachment", "cases", "tasks", "opportunities", # System "created_by", "created_at", "is_active", "org", ) class EmailSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class Meta: model = AccountEmail fields = ( "message_subject", "message_body", "timezone", "scheduled_date_time", "scheduled_later", "created_at", "from_email", "rendered_message_body", ) def validate_message_body(self, message_body): count = 0 for i in message_body: if i == "{": count += 1 elif i == "}": count -= 1 if count < 0: raise serializers.ValidationError( "Brackets do not match, Enter valid tags." ) if count != 0: raise serializers.ValidationError( "Brackets do not match, Enter valid tags." ) return message_body class EmailLogSerializer(serializers.ModelSerializer): email = EmailSerializer() class Meta: model = AccountEmailLog fields = ["email", "contact", "is_sent"] class AccountWriteSerializer(serializers.ModelSerializer): """Serializer for API documentation of Account write operations""" class Meta: model = Account fields = [ "name", "phone", "email", "website", "industry", "number_of_employees", "annual_revenue", "address_line", "city", "state", "postcode", "country", "description", ] class AccountCreateSerializer(serializers.ModelSerializer): """Serializer for creating/updating Account data""" def __init__(self, *args, **kwargs): request_obj = kwargs.pop("request_obj", None) kwargs.pop("account", None) # Remove unused 'account' parameter passed by views super().__init__(*args, **kwargs) if request_obj: self.org = request_obj.profile.org def validate_name(self, name): if self.instance: if self.instance.name != name: if not Account.objects.filter(name__iexact=name, org=self.org).exists(): return name raise serializers.ValidationError( "Account already exists with this name" ) return name if not Account.objects.filter(name__iexact=name, org=self.org).exists(): return name raise serializers.ValidationError("Account already exists with this name") class Meta: model = Account fields = ( # Core Account Information "name", "email", "phone", "website", # Business Information "industry", "number_of_employees", "annual_revenue", "currency", # Address "address_line", "city", "state", "postcode", "country", # Notes "description", # Status "is_active", ) def create(self, validated_data): # Default currency from org if not provided and has annual_revenue if not validated_data.get("currency") and validated_data.get("annual_revenue"): request = self.context.get("request") if request and hasattr(request, "profile") and request.profile.org: validated_data["currency"] = request.profile.org.default_currency return super().create(validated_data) class AccountDetailEditSwaggerSerializer(serializers.Serializer): comment = serializers.CharField() account_attachment = serializers.FileField() class AccountCommentEditSwaggerSerializer(serializers.Serializer): comment = serializers.CharField() class EmailWriteSerializer(serializers.ModelSerializer): class Meta: model = AccountEmail fields = ( "from_email", "recipients", "message_subject", "scheduled_later", "timezone", "scheduled_date_time", "message_body", )