HH/apps/surveys/serializers.py
2026-01-24 15:27:30 +03:00

249 lines
9.4 KiB
Python

"""
Surveys serializers
"""
from rest_framework import serializers
from .models import SurveyInstance, SurveyQuestion, SurveyResponse, SurveyTemplate, SurveyTracking
class SurveyQuestionSerializer(serializers.ModelSerializer):
"""Survey question serializer"""
class Meta:
model = SurveyQuestion
fields = [
'id', 'survey_template', 'text', 'text_ar',
'question_type', 'order', 'is_required',
'choices_json', 'weight', 'branch_logic',
'help_text', 'help_text_ar',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at']
class SurveyTemplateSerializer(serializers.ModelSerializer):
"""Survey template serializer"""
hospital_name = serializers.CharField(source='hospital.name', read_only=True)
questions = SurveyQuestionSerializer(many=True, read_only=True)
question_count = serializers.SerializerMethodField()
class Meta:
model = SurveyTemplate
fields = [
'id', 'name', 'name_ar', 'description', 'description_ar',
'hospital', 'hospital_name', 'survey_type',
'scoring_method', 'negative_threshold',
'is_active', 'version',
'questions', 'question_count',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at']
def get_question_count(self, obj):
"""Get number of questions"""
return obj.get_question_count()
class SurveyResponseSerializer(serializers.ModelSerializer):
"""Survey response serializer"""
question_text = serializers.CharField(source='question.text', read_only=True)
question_type = serializers.CharField(source='question.question_type', read_only=True)
class Meta:
model = SurveyResponse
fields = [
'id', 'survey_instance', 'question', 'question_text', 'question_type',
'numeric_value', 'text_value', 'choice_value',
'response_time_seconds',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at']
class SurveyInstanceSerializer(serializers.ModelSerializer):
"""Survey instance serializer"""
survey_template_name = serializers.CharField(source='survey_template.name', read_only=True)
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
patient_mrn = serializers.CharField(source='patient.mrn', read_only=True)
responses = SurveyResponseSerializer(many=True, read_only=True)
survey_url = serializers.SerializerMethodField()
class Meta:
model = SurveyInstance
fields = [
'id', 'survey_template', 'survey_template_name',
'patient', 'patient_name', 'patient_mrn',
'journey_instance', 'encounter_id',
'delivery_channel', 'recipient_phone', 'recipient_email',
'access_token', 'token_expires_at', 'survey_url',
'status', 'sent_at', 'opened_at', 'completed_at',
'total_score', 'is_negative',
'responses', 'metadata',
'created_at', 'updated_at'
]
read_only_fields = [
'id', 'access_token', 'token_expires_at',
'sent_at', 'opened_at', 'completed_at',
'total_score', 'is_negative',
'created_at', 'updated_at'
]
def get_survey_url(self, obj):
"""Get survey URL"""
return obj.get_survey_url()
class SurveySubmissionSerializer(serializers.Serializer):
"""
Serializer for submitting survey responses.
Used by the public survey form.
"""
responses = serializers.ListField(
child=serializers.DictField(),
help_text="Array of {question_id, numeric_value, text_value, choice_value}"
)
def validate_responses(self, value):
"""Validate responses"""
if not value:
raise serializers.ValidationError("At least one response is required")
for response in value:
if 'question_id' not in response:
raise serializers.ValidationError("Each response must have question_id")
return value
def create(self, validated_data):
"""
Create survey responses and calculate score.
This is called when a patient submits the survey.
"""
survey_instance = self.context['survey_instance']
responses_data = validated_data['responses']
from apps.surveys.models import SurveyResponse
from django.utils import timezone
# Create responses
for response_data in responses_data:
SurveyResponse.objects.create(
survey_instance=survey_instance,
question_id=response_data['question_id'],
numeric_value=response_data.get('numeric_value'),
text_value=response_data.get('text_value', ''),
choice_value=response_data.get('choice_value', ''),
response_time_seconds=response_data.get('response_time_seconds')
)
# Update survey instance
survey_instance.status = 'completed'
survey_instance.completed_at = timezone.now()
survey_instance.save()
# Calculate score
survey_instance.calculate_score()
# Queue processing task
from apps.surveys.tasks import process_survey_completion
process_survey_completion.delay(str(survey_instance.id))
return survey_instance
class SurveyTrackingSerializer(serializers.ModelSerializer):
"""
Survey tracking events serializer.
Tracks detailed engagement metrics for surveys.
"""
survey_template_name = serializers.CharField(source='survey_instance.survey_template.name', read_only=True)
patient_name = serializers.CharField(source='survey_instance.patient.get_full_name', read_only=True)
class Meta:
model = SurveyTracking
fields = [
'id', 'survey_instance', 'survey_template_name', 'patient_name',
'event_type', 'time_on_page', 'total_time_spent',
'current_question', 'user_agent', 'ip_address',
'device_type', 'browser', 'country', 'city', 'metadata',
'created_at'
]
read_only_fields = ['id', 'created_at']
class SurveyInstanceAnalyticsSerializer(serializers.ModelSerializer):
"""
Enhanced survey instance serializer with tracking analytics.
"""
survey_template_name = serializers.CharField(source='survey_template.name', read_only=True)
patient_name = serializers.CharField(source='patient.get_full_name', read_only=True)
patient_mrn = serializers.CharField(source='patient.mrn', read_only=True)
responses = SurveyResponseSerializer(many=True, read_only=True)
survey_url = serializers.SerializerMethodField()
tracking_events_count = serializers.SerializerMethodField()
time_to_complete_minutes = serializers.SerializerMethodField()
class Meta:
model = SurveyInstance
fields = [
'id', 'survey_template', 'survey_template_name',
'patient', 'patient_name', 'patient_mrn',
'journey_instance', 'encounter_id',
'delivery_channel', 'recipient_phone', 'recipient_email',
'access_token', 'token_expires_at', 'survey_url',
'status', 'sent_at', 'opened_at', 'completed_at',
'open_count', 'last_opened_at', 'time_spent_seconds',
'total_score', 'is_negative',
'responses', 'metadata',
'tracking_events_count', 'time_to_complete_minutes',
'created_at', 'updated_at'
]
read_only_fields = [
'id', 'access_token', 'token_expires_at',
'sent_at', 'opened_at', 'completed_at',
'open_count', 'last_opened_at', 'time_spent_seconds',
'total_score', 'is_negative',
'tracking_events_count', 'time_to_complete_minutes',
'created_at', 'updated_at'
]
def get_survey_url(self, obj):
"""Get survey URL"""
return obj.get_survey_url()
def get_tracking_events_count(self, obj):
"""Get count of tracking events"""
return obj.tracking_events.count()
def get_time_to_complete_minutes(self, obj):
"""Calculate time to complete in minutes"""
if obj.sent_at and obj.completed_at:
time_diff = obj.completed_at - obj.sent_at
return round(time_diff.total_seconds() / 60, 2)
return None
class PublicSurveySerializer(serializers.ModelSerializer):
"""
Public survey serializer for patient-facing survey form.
Excludes sensitive information.
"""
survey_name = serializers.CharField(source='survey_template.name', read_only=True)
survey_name_ar = serializers.CharField(source='survey_template.name_ar', read_only=True)
survey_description = serializers.CharField(source='survey_template.description', read_only=True)
survey_description_ar = serializers.CharField(source='survey_template.description_ar', read_only=True)
questions = SurveyQuestionSerializer(source='survey_template.questions', many=True, read_only=True)
class Meta:
model = SurveyInstance
fields = [
'id', 'survey_name', 'survey_name_ar',
'survey_description', 'survey_description_ar',
'questions', 'status', 'completed_at'
]
read_only_fields = ['id', 'status', 'completed_at']