Files
GNX-WEB/gnx-react/backend/support/serializers.py
Iliyan Angelov 5ad9cbe3a6 update
2025-10-13 01:49:06 +03:00

212 lines
8.3 KiB
Python

from rest_framework import serializers
from .models import (
SupportTicket, TicketStatus, TicketPriority, TicketCategory,
TicketMessage, TicketActivity, KnowledgeBaseCategory,
KnowledgeBaseArticle, SupportSettings
)
from .email_service import SupportEmailService
import logging
logger = logging.getLogger(__name__)
class TicketStatusSerializer(serializers.ModelSerializer):
class Meta:
model = TicketStatus
fields = ['id', 'name', 'color', 'description', 'is_closed', 'display_order']
class TicketPrioritySerializer(serializers.ModelSerializer):
class Meta:
model = TicketPriority
fields = ['id', 'name', 'level', 'color', 'description', 'sla_hours']
class TicketCategorySerializer(serializers.ModelSerializer):
class Meta:
model = TicketCategory
fields = ['id', 'name', 'description', 'color', 'icon', 'display_order']
class TicketMessageSerializer(serializers.ModelSerializer):
class Meta:
model = TicketMessage
fields = [
'id', 'ticket', 'message_type', 'content', 'author_name',
'author_email', 'is_internal', 'created_at', 'updated_at',
'attachments', 'is_read'
]
read_only_fields = ['created_at', 'updated_at']
class TicketActivitySerializer(serializers.ModelSerializer):
class Meta:
model = TicketActivity
fields = [
'id', 'activity_type', 'description', 'user_name',
'old_value', 'new_value', 'created_at'
]
read_only_fields = ['created_at']
class SupportTicketSerializer(serializers.ModelSerializer):
status_name = serializers.CharField(source='status.name', read_only=True)
status_color = serializers.CharField(source='status.color', read_only=True)
priority_name = serializers.CharField(source='priority.name', read_only=True)
priority_color = serializers.CharField(source='priority.color', read_only=True)
category_name = serializers.CharField(source='category.name', read_only=True)
messages = TicketMessageSerializer(many=True, read_only=True)
activities = TicketActivitySerializer(many=True, read_only=True)
class Meta:
model = SupportTicket
fields = [
'id', 'ticket_number', 'title', 'description', 'ticket_type',
'user_name', 'user_email', 'user_phone', 'company',
'category', 'category_name', 'priority', 'priority_name', 'priority_color',
'status', 'status_name', 'status_color', 'assigned_to', 'assigned_at',
'created_at', 'updated_at', 'closed_at', 'last_activity',
'first_response_at', 'sla_deadline', 'tags', 'is_escalated',
'escalation_reason', 'attachments', 'messages', 'activities'
]
read_only_fields = [
'ticket_number', 'created_at', 'updated_at', 'last_activity',
'assigned_at', 'closed_at', 'first_response_at', 'sla_deadline'
]
class SupportTicketCreateSerializer(serializers.ModelSerializer):
"""Simplified serializer for creating tickets from public form"""
ticket_number = serializers.CharField(read_only=True)
class Meta:
model = SupportTicket
fields = [
'ticket_number', 'title', 'description', 'ticket_type', 'user_name',
'user_email', 'user_phone', 'company', 'category'
]
read_only_fields = ['ticket_number']
def validate_user_email(self, value):
"""
Validate email format and optionally check if registered
"""
from .models import RegisteredEmail
from django.core.validators import validate_email
from django.core.exceptions import ValidationError as DjangoValidationError
# Basic email format validation
try:
validate_email(value)
except DjangoValidationError:
raise serializers.ValidationError("Please enter a valid email address.")
# Optional: Check if email is registered (for analytics/tracking)
# But don't block ticket creation if not registered
try:
registered_email = RegisteredEmail.objects.get(email=value)
if not registered_email.is_active:
# Log this but don't block the ticket
logger.warning(f'Ticket submitted by deactivated registered email: {value}')
except RegisteredEmail.DoesNotExist:
# This is fine - unregistered users can submit tickets
logger.info(f'Ticket submitted by unregistered email: {value}')
return value
def create(self, validated_data):
from .models import RegisteredEmail
# Set default status and priority if not set
if not validated_data.get('status'):
default_status = TicketStatus.objects.filter(name='Open').first()
if default_status:
validated_data['status'] = default_status
if not validated_data.get('priority'):
default_priority = TicketPriority.objects.filter(name='Medium').first()
if default_priority:
validated_data['priority'] = default_priority
ticket = SupportTicket.objects.create(**validated_data)
# Create initial activity
TicketActivity.objects.create(
ticket=ticket,
activity_type='created',
description=f'Ticket created by {ticket.user_name}',
user_name=ticket.user_name
)
# Update registered email statistics (only if email is registered)
try:
registered_email = RegisteredEmail.objects.get(email=validated_data['user_email'])
registered_email.increment_ticket_count()
logger.info(f'Updated ticket count for registered email: {validated_data["user_email"]}')
except RegisteredEmail.DoesNotExist:
# This is normal now - unregistered users can submit tickets
logger.info(f'Ticket created by unregistered email: {validated_data["user_email"]}')
# Send email notifications
try:
email_results = SupportEmailService.send_ticket_created_emails(ticket)
logger.info(f'Email notifications sent for ticket {ticket.ticket_number}: {email_results}')
except Exception as e:
logger.error(f'Failed to send email notifications for ticket {ticket.ticket_number}: {str(e)}')
# Don't fail ticket creation if emails fail
return ticket
class TicketStatusCheckSerializer(serializers.Serializer):
"""Serializer for checking ticket status by ticket number"""
ticket_number = serializers.CharField(max_length=20)
class KnowledgeBaseCategorySerializer(serializers.ModelSerializer):
article_count = serializers.SerializerMethodField()
class Meta:
model = KnowledgeBaseCategory
fields = [
'id', 'name', 'slug', 'description', 'icon', 'color',
'display_order', 'article_count'
]
def get_article_count(self, obj):
return obj.articles.filter(is_published=True).count()
class KnowledgeBaseArticleListSerializer(serializers.ModelSerializer):
category_name = serializers.CharField(source='category.name', read_only=True)
category_slug = serializers.CharField(source='category.slug', read_only=True)
class Meta:
model = KnowledgeBaseArticle
fields = [
'id', 'title', 'slug', 'category', 'category_name', 'category_slug',
'summary', 'is_featured', 'view_count', 'helpful_count',
'not_helpful_count', 'created_at', 'updated_at', 'published_at'
]
class KnowledgeBaseArticleDetailSerializer(serializers.ModelSerializer):
category_name = serializers.CharField(source='category.name', read_only=True)
category_slug = serializers.CharField(source='category.slug', read_only=True)
class Meta:
model = KnowledgeBaseArticle
fields = [
'id', 'title', 'slug', 'category', 'category_name', 'category_slug',
'content', 'summary', 'meta_description', 'keywords',
'is_featured', 'view_count', 'helpful_count', 'not_helpful_count',
'created_at', 'updated_at', 'published_at'
]
class SupportSettingsSerializer(serializers.ModelSerializer):
class Meta:
model = SupportSettings
fields = ['id', 'setting_name', 'setting_value', 'description', 'is_active']