249 lines
9.4 KiB
Python
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']
|