HH/apps/surveys/admin.py
2025-12-24 12:42:31 +03:00

235 lines
7.3 KiB
Python

"""
Surveys admin
"""
from django.contrib import admin
from django.utils.html import format_html
from .models import SurveyInstance, SurveyQuestion, SurveyResponse, SurveyTemplate
class SurveyQuestionInline(admin.TabularInline):
"""Inline admin for survey questions"""
model = SurveyQuestion
extra = 1
fields = ['order', 'text', 'question_type', 'is_required', 'weight']
ordering = ['order']
@admin.register(SurveyTemplate)
class SurveyTemplateAdmin(admin.ModelAdmin):
"""Survey template admin"""
list_display = [
'name', 'survey_type', 'hospital', 'scoring_method',
'negative_threshold', 'get_question_count', 'is_active', 'version'
]
list_filter = ['survey_type', 'scoring_method', 'is_active', 'hospital']
search_fields = ['name', 'name_ar', 'description']
ordering = ['hospital', 'name']
inlines = [SurveyQuestionInline]
fieldsets = (
(None, {
'fields': ('name', 'name_ar', 'description', 'description_ar')
}),
('Configuration', {
'fields': ('hospital', 'survey_type', 'version')
}),
('Scoring', {
'fields': ('scoring_method', 'negative_threshold')
}),
('Status', {
'fields': ('is_active',)
}),
('Metadata', {
'fields': ('created_at', 'updated_at')
}),
)
readonly_fields = ['created_at', 'updated_at']
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('hospital').prefetch_related('questions')
@admin.register(SurveyQuestion)
class SurveyQuestionAdmin(admin.ModelAdmin):
"""Survey question admin"""
list_display = [
'survey_template', 'order', 'text_preview',
'question_type', 'is_required', 'weight'
]
list_filter = ['survey_template', 'question_type', 'is_required']
search_fields = ['text', 'text_ar']
ordering = ['survey_template', 'order']
fieldsets = (
(None, {
'fields': ('survey_template', 'order')
}),
('Question Text', {
'fields': ('text', 'text_ar')
}),
('Configuration', {
'fields': ('question_type', 'is_required', 'weight')
}),
('Choices (for multiple choice)', {
'fields': ('choices_json',),
'classes': ('collapse',)
}),
('Branch Logic', {
'fields': ('branch_logic',),
'classes': ('collapse',)
}),
('Help Text', {
'fields': ('help_text', 'help_text_ar'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_at', 'updated_at')
}),
)
readonly_fields = ['created_at', 'updated_at']
def text_preview(self, obj):
"""Show preview of question text"""
return obj.text[:100] + '...' if len(obj.text) > 100 else obj.text
text_preview.short_description = 'Question'
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('survey_template')
class SurveyResponseInline(admin.TabularInline):
"""Inline admin for survey responses"""
model = SurveyResponse
extra = 0
fields = ['question', 'numeric_value', 'text_value', 'choice_value']
readonly_fields = ['question']
ordering = ['question__order']
def has_add_permission(self, request, obj=None):
return False
@admin.register(SurveyInstance)
class SurveyInstanceAdmin(admin.ModelAdmin):
"""Survey instance admin"""
list_display = [
'survey_template', 'patient', 'encounter_id',
'status_badge', 'delivery_channel', 'total_score',
'is_negative', 'sent_at', 'completed_at'
]
list_filter = [
'status', 'delivery_channel', 'is_negative',
'survey_template__survey_type', 'sent_at', 'completed_at'
]
search_fields = [
'patient__mrn', 'patient__first_name', 'patient__last_name',
'encounter_id', 'access_token'
]
ordering = ['-created_at']
inlines = [SurveyResponseInline]
fieldsets = (
(None, {
'fields': ('survey_template', 'patient', 'encounter_id')
}),
('Journey Linkage', {
'fields': ('journey_instance', 'journey_stage_instance'),
'classes': ('collapse',)
}),
('Delivery', {
'fields': (
'delivery_channel', 'recipient_phone', 'recipient_email',
'access_token', 'token_expires_at'
)
}),
('Status & Timestamps', {
'fields': ('status', 'sent_at', 'opened_at', 'completed_at')
}),
('Scoring', {
'fields': ('total_score', 'is_negative')
}),
('Metadata', {
'fields': ('metadata', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = [
'access_token', 'token_expires_at', 'sent_at', 'opened_at',
'completed_at', 'total_score', 'is_negative',
'created_at', 'updated_at'
]
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related(
'survey_template', 'patient', 'journey_instance', 'journey_stage_instance'
).prefetch_related('responses')
def status_badge(self, obj):
"""Display status with color badge"""
colors = {
'pending': 'warning',
'active': 'info',
'completed': 'success',
'cancelled': 'secondary',
}
color = colors.get(obj.status, 'secondary')
return format_html(
'<span class="badge bg-{}">{}</span>',
color,
obj.get_status_display()
)
status_badge.short_description = 'Status'
@admin.register(SurveyResponse)
class SurveyResponseAdmin(admin.ModelAdmin):
"""Survey response admin"""
list_display = [
'survey_instance', 'question_preview',
'numeric_value', 'text_value_preview', 'created_at'
]
list_filter = ['survey_instance__survey_template', 'question__question_type', 'created_at']
search_fields = [
'survey_instance__patient__mrn',
'question__text',
'text_value'
]
ordering = ['survey_instance', 'question__order']
fieldsets = (
(None, {
'fields': ('survey_instance', 'question')
}),
('Response', {
'fields': ('numeric_value', 'text_value', 'choice_value')
}),
('Metadata', {
'fields': ('response_time_seconds', 'created_at', 'updated_at')
}),
)
readonly_fields = ['created_at', 'updated_at']
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('survey_instance', 'question')
def question_preview(self, obj):
"""Show preview of question"""
return obj.question.text[:50] + '...' if len(obj.question.text) > 50 else obj.question.text
question_preview.short_description = 'Question'
def text_value_preview(self, obj):
"""Show preview of text response"""
if obj.text_value:
return obj.text_value[:50] + '...' if len(obj.text_value) > 50 else obj.text_value
return '-'
text_value_preview.short_description = 'Text Response'