277 lines
11 KiB
Python
277 lines
11 KiB
Python
"""
|
|
Complaints serializers
|
|
"""
|
|
from rest_framework import serializers
|
|
|
|
from .models import Complaint, ComplaintAttachment, ComplaintUpdate, Inquiry,ComplaintExplanation
|
|
|
|
|
|
class ComplaintAttachmentSerializer(serializers.ModelSerializer):
|
|
"""Complaint attachment serializer"""
|
|
uploaded_by_name = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = ComplaintAttachment
|
|
fields = [
|
|
'id', 'complaint', 'file', 'filename', 'file_type', 'file_size',
|
|
'uploaded_by', 'uploaded_by_name', 'description',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'file_size', 'created_at', 'updated_at']
|
|
|
|
def get_uploaded_by_name(self, obj):
|
|
"""Get uploader name"""
|
|
if obj.uploaded_by:
|
|
return obj.uploaded_by.get_full_name()
|
|
return None
|
|
|
|
|
|
class ComplaintUpdateSerializer(serializers.ModelSerializer):
|
|
"""Complaint update serializer"""
|
|
created_by_name = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = ComplaintUpdate
|
|
fields = [
|
|
'id', 'complaint', 'update_type', 'message',
|
|
'created_by', 'created_by_name',
|
|
'old_status', 'new_status', 'metadata',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_created_by_name(self, obj):
|
|
"""Get creator name"""
|
|
if obj.created_by:
|
|
return obj.created_by.get_full_name()
|
|
return None
|
|
|
|
|
|
class ComplaintSerializer(serializers.ModelSerializer):
|
|
"""Complaint serializer"""
|
|
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
|
|
patient_mrn = serializers.CharField(source='patient.mrn', read_only=True)
|
|
hospital_name = serializers.CharField(source='hospital.name', read_only=True)
|
|
department_name = serializers.CharField(source='department.name', read_only=True)
|
|
staff_name = serializers.SerializerMethodField()
|
|
assigned_to_name = serializers.SerializerMethodField()
|
|
created_by_name = serializers.SerializerMethodField()
|
|
source_name = serializers.CharField(source='source.name_en', read_only=True)
|
|
source_code = serializers.CharField(source='source.code', read_only=True)
|
|
attachments = ComplaintAttachmentSerializer(many=True, read_only=True)
|
|
updates = ComplaintUpdateSerializer(many=True, read_only=True)
|
|
sla_status = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Complaint
|
|
fields = [
|
|
'id', 'patient', 'patient_name', 'patient_mrn', 'encounter_id',
|
|
'hospital', 'hospital_name', 'department', 'department_name',
|
|
'staff', 'staff_name',
|
|
'title', 'description', 'category', 'subcategory',
|
|
'priority', 'severity', 'source', 'source_name', 'source_code', 'status',
|
|
'created_by', 'created_by_name',
|
|
'assigned_to', 'assigned_to_name', 'assigned_at',
|
|
'due_at', 'is_overdue', 'sla_status',
|
|
'reminder_sent_at', 'escalated_at',
|
|
'resolution', 'resolved_at', 'resolved_by',
|
|
'closed_at', 'closed_by',
|
|
'resolution_survey', 'resolution_survey_sent_at',
|
|
'attachments', 'updates', 'metadata',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = [
|
|
'id', 'created_by', 'assigned_at', 'is_overdue',
|
|
'reminder_sent_at', 'escalated_at',
|
|
'resolved_at', 'closed_at', 'resolution_survey_sent_at',
|
|
'created_at', 'updated_at'
|
|
]
|
|
|
|
def create(self, validated_data):
|
|
"""
|
|
Create complaint with auto-setting of department from AI analysis.
|
|
|
|
If metadata contains AI analysis with department name,
|
|
automatically set the department field by querying the database.
|
|
"""
|
|
from apps.organizations.models import Department
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Extract metadata if present
|
|
metadata = validated_data.get('metadata', {})
|
|
|
|
# Check if department is not already set and AI analysis contains department info
|
|
if not validated_data.get('department') and metadata.get('ai_analysis'):
|
|
ai_analysis = metadata['ai_analysis']
|
|
department_name = ai_analysis.get('department')
|
|
|
|
# If AI identified a department, try to match it in the database
|
|
if department_name:
|
|
hospital = validated_data.get('hospital')
|
|
|
|
if hospital:
|
|
try:
|
|
# Try exact match first
|
|
department = Department.objects.filter(
|
|
hospital=hospital,
|
|
status='active',
|
|
name__iexact=department_name
|
|
).first()
|
|
|
|
# If no exact match, try partial match
|
|
if not department:
|
|
department = Department.objects.filter(
|
|
hospital=hospital,
|
|
status='active',
|
|
name__icontains=department_name
|
|
).first()
|
|
|
|
if department:
|
|
validated_data['department'] = department
|
|
logger.info(
|
|
f"Auto-set department '{department.name}' from AI analysis "
|
|
f"for complaint (matched from '{department_name}')"
|
|
)
|
|
else:
|
|
logger.warning(
|
|
f"AI suggested department '{department_name}' but no match found "
|
|
f"in hospital '{hospital.name}'"
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Error auto-setting department: {e}")
|
|
|
|
# Create the complaint
|
|
return super().create(validated_data)
|
|
|
|
def get_staff_name(self, obj):
|
|
"""Get staff name"""
|
|
if obj.staff:
|
|
return f"{obj.staff.first_name} {obj.staff.last_name}"
|
|
return None
|
|
|
|
def get_assigned_to_name(self, obj):
|
|
"""Get assigned user name"""
|
|
if obj.assigned_to:
|
|
return obj.assigned_to.get_full_name()
|
|
return None
|
|
|
|
def get_created_by_name(self, obj):
|
|
"""Get creator name"""
|
|
if obj.created_by:
|
|
return obj.created_by.get_full_name()
|
|
return None
|
|
|
|
def get_sla_status(self, obj):
|
|
"""Get SLA status"""
|
|
return obj.sla_status if hasattr(obj, 'sla_status') else 'on_track'
|
|
|
|
|
|
class ComplaintExplanationSerializer(serializers.ModelSerializer):
|
|
"""Complaint explanation serializer"""
|
|
staff_name = serializers.SerializerMethodField()
|
|
requested_by_name = serializers.SerializerMethodField()
|
|
attachment_count = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = ComplaintExplanation
|
|
fields = [
|
|
'id', 'complaint', 'staff', 'staff_name',
|
|
'explanation', 'token', 'is_used',
|
|
'email_sent_at', 'responded_at',
|
|
'submitted_via', 'requested_by', 'requested_by_name',
|
|
'request_message', 'attachment_count',
|
|
'created_at'
|
|
]
|
|
read_only_fields = ['id', 'email_sent_at', 'responded_at', 'created_at']
|
|
|
|
def get_staff_name(self, obj):
|
|
if obj.staff:
|
|
return f"{obj.staff.first_name} {obj.staff.last_name}" if obj.staff.last_name else ""
|
|
return ""
|
|
|
|
def get_requested_by_name(self, obj):
|
|
if obj.requested_by:
|
|
return obj.requested_by.get_full_name()
|
|
return None
|
|
|
|
def get_attachment_count(self, obj):
|
|
return obj.attachments.count()
|
|
|
|
|
|
class ComplaintListSerializer(serializers.ModelSerializer):
|
|
"""Simplified complaint serializer for list views"""
|
|
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
|
|
patient_mrn = serializers.CharField(source='patient.mrn', read_only=True)
|
|
hospital_name = serializers.CharField(source='hospital.name', read_only=True)
|
|
department_name = serializers.CharField(source='department.name', read_only=True)
|
|
staff_name = serializers.SerializerMethodField()
|
|
assigned_to_name = serializers.SerializerMethodField()
|
|
source_name = serializers.CharField(source='source.name_en', read_only=True)
|
|
sla_status = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Complaint
|
|
fields = [
|
|
'id', 'patient_name', 'patient_mrn', 'encounter_id',
|
|
'hospital_name', 'department_name', 'staff_name',
|
|
'title', 'category', 'subcategory',
|
|
'priority', 'severity', 'source_name', 'status',
|
|
'assigned_to_name', 'assigned_at',
|
|
'due_at', 'is_overdue', 'sla_status',
|
|
'resolution', 'resolved_at',
|
|
'closed_at',
|
|
'created_at', 'updated_at'
|
|
]
|
|
|
|
def get_staff_name(self, obj):
|
|
"""Get staff name"""
|
|
if obj.staff:
|
|
return f"{obj.staff.first_name} {obj.staff.last_name}"
|
|
return None
|
|
|
|
def get_assigned_to_name(self, obj):
|
|
"""Get assigned user name"""
|
|
if obj.assigned_to:
|
|
return obj.assigned_to.get_full_name()
|
|
return None
|
|
|
|
def get_sla_status(self, obj):
|
|
"""Get SLA status"""
|
|
return obj.sla_status if hasattr(obj, 'sla_status') else 'on_track'
|
|
|
|
|
|
class InquirySerializer(serializers.ModelSerializer):
|
|
"""Inquiry serializer"""
|
|
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
|
|
hospital_name = serializers.CharField(source='hospital.name', read_only=True)
|
|
department_name = serializers.CharField(source='department.name', read_only=True)
|
|
assigned_to_name = serializers.SerializerMethodField()
|
|
created_by_name = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Inquiry
|
|
fields = [
|
|
'id', 'patient', 'patient_name',
|
|
'contact_name', 'contact_phone', 'contact_email',
|
|
'hospital', 'hospital_name', 'department', 'department_name',
|
|
'subject', 'message', 'category', 'source',
|
|
'created_by', 'created_by_name',
|
|
'assigned_to', 'assigned_to_name',
|
|
'response', 'responded_at', 'responded_by',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_by', 'responded_at', 'created_at', 'updated_at']
|
|
|
|
def get_assigned_to_name(self, obj):
|
|
"""Get assigned user name"""
|
|
if obj.assigned_to:
|
|
return obj.assigned_to.get_full_name()
|
|
return None
|
|
|
|
def get_created_by_name(self, obj):
|
|
"""Get creator name"""
|
|
if obj.created_by:
|
|
return obj.created_by.get_full_name()
|
|
return None
|