bottleneckcrm/backend/accounts/serializer.py

247 lines
7.3 KiB
Python

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",
)