Marwan Alwali 4d06ca4b5e update
2025-09-20 14:26:19 +03:00

583 lines
16 KiB
Python

"""
Admin configuration for EMR app.
"""
from django.contrib import admin
from django.utils.html import format_html
from django.urls import reverse
from django.utils.safestring import mark_safe
from .models import (
Encounter, VitalSigns, ProblemList, CarePlan,
ClinicalNote, NoteTemplate, Icd10
)
admin.site.register(Icd10)
@admin.register(Encounter)
class EncounterAdmin(admin.ModelAdmin):
"""
Admin interface for Encounter model.
"""
list_display = [
'encounter_id', 'patient_name', 'provider_name', 'encounter_type',
'status', 'start_datetime', 'duration_display', 'documentation_complete'
]
list_filter = [
'tenant', 'encounter_type', 'encounter_class', 'status',
'priority', 'documentation_complete', 'signed_off'
]
search_fields = [
'patient__first_name', 'patient__last_name', 'patient__mrn',
'provider__first_name', 'provider__last_name',
'chief_complaint', 'reason_for_visit'
]
readonly_fields = ['encounter_id', 'created_at', 'updated_at', 'duration_display']
fieldsets = (
('Basic Information', {
'fields': (
'encounter_id', 'tenant', 'patient', 'provider',
'encounter_type', 'encounter_class'
)
}),
('Timing', {
'fields': (
'start_datetime', 'end_datetime', 'duration_display'
)
}),
('Status', {
'fields': (
'status', 'priority', 'acuity_level'
)
}),
('Location', {
'fields': (
'location', 'room_number'
)
}),
('Related Records', {
'fields': (
'appointment', 'admission'
)
}),
('Clinical Information', {
'fields': (
'chief_complaint', 'reason_for_visit'
)
}),
('Documentation', {
'fields': (
'documentation_complete', 'signed_off', 'signed_by', 'signed_datetime'
)
}),
('Billing', {
'fields': (
'billable', 'billing_codes'
)
}),
('Quality', {
'fields': (
'quality_measures',
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
def patient_name(self, obj):
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def provider_name(self, obj):
return obj.provider.get_full_name()
provider_name.short_description = 'Provider'
def duration_display(self, obj):
duration = obj.duration
if duration:
hours = duration.total_seconds() // 3600
minutes = (duration.total_seconds() % 3600) // 60
return f"{int(hours)}h {int(minutes)}m"
return "Ongoing" if obj.is_active else "Not set"
duration_display.short_description = 'Duration'
@admin.register(VitalSigns)
class VitalSignsAdmin(admin.ModelAdmin):
"""
Admin interface for VitalSigns model.
"""
list_display = [
'measurement_id', 'patient_name', 'measured_datetime',
'temperature', 'blood_pressure_display', 'heart_rate',
'respiratory_rate', 'oxygen_saturation', 'measured_by_name'
]
list_filter = [
'measured_datetime', 'temperature_method', 'bp_position',
'oxygen_delivery', 'device_calibrated'
]
search_fields = [
'patient__first_name', 'patient__last_name', 'patient__mrn',
'measured_by__first_name', 'measured_by__last_name'
]
readonly_fields = ['measurement_id', 'bmi', 'created_at', 'updated_at']
fieldsets = (
('Basic Information', {
'fields': (
'measurement_id', 'encounter', 'patient', 'measured_datetime'
)
}),
('Temperature', {
'fields': (
'temperature', 'temperature_method'
)
}),
('Blood Pressure', {
'fields': (
'systolic_bp', 'diastolic_bp', 'bp_position', 'bp_cuff_size'
)
}),
('Heart Rate', {
'fields': (
'heart_rate', 'heart_rhythm'
)
}),
('Respiratory', {
'fields': (
'respiratory_rate', 'oxygen_saturation', 'oxygen_delivery', 'oxygen_flow_rate'
)
}),
('Pain Assessment', {
'fields': (
'pain_scale', 'pain_location', 'pain_quality'
)
}),
('Anthropometric', {
'fields': (
'weight', 'height', 'bmi', 'head_circumference'
)
}),
('Device Information', {
'fields': (
'device_used', 'device_calibrated'
)
}),
('Staff', {
'fields': (
'measured_by', 'verified_by'
)
}),
('Quality', {
'fields': (
'critical_values', 'alerts_generated', 'notes'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at'
)
}),
)
def patient_name(self, obj):
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def blood_pressure_display(self, obj):
return obj.blood_pressure or "Not recorded"
blood_pressure_display.short_description = 'Blood Pressure'
def measured_by_name(self, obj):
return obj.measured_by.get_full_name()
measured_by_name.short_description = 'Measured By'
@admin.register(ProblemList)
class ProblemListAdmin(admin.ModelAdmin):
"""
Admin interface for ProblemList model.
"""
list_display = [
'problem_id', 'patient_name', 'problem_name', 'problem_type',
'status', 'severity', 'priority', 'onset_date', 'diagnosing_provider_name'
]
list_filter = [
'tenant', 'problem_type', 'status', 'severity', 'priority',
'coding_system', 'verified'
]
search_fields = [
'patient__first_name', 'patient__last_name', 'patient__mrn',
'problem_name', 'problem_code',
'diagnosing_provider__first_name', 'diagnosing_provider__last_name'
]
readonly_fields = ['problem_id', 'created_at', 'updated_at']
fieldsets = (
('Basic Information', {
'fields': (
'problem_id', 'tenant', 'patient', 'problem_name'
)
}),
('Coding', {
'fields': (
'problem_code', 'coding_system'
)
}),
('Classification', {
'fields': (
'problem_type', 'severity', 'priority'
)
}),
('Clinical Information', {
'fields': (
'onset_date', 'onset_description', 'body_site', 'laterality'
)
}),
('Status', {
'fields': (
'status', 'resolution_date', 'resolution_notes'
)
}),
('Providers', {
'fields': (
'diagnosing_provider', 'managing_provider'
)
}),
('Related Information', {
'fields': (
'related_encounter',
)
}),
('Documentation', {
'fields': (
'clinical_notes', 'patient_concerns'
)
}),
('Goals and Outcomes', {
'fields': (
'treatment_goals', 'outcome_measures'
)
}),
('Verification', {
'fields': (
'verified', 'verified_by', 'verified_date'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
def patient_name(self, obj):
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def diagnosing_provider_name(self, obj):
return obj.diagnosing_provider.get_full_name()
diagnosing_provider_name.short_description = 'Diagnosing Provider'
@admin.register(CarePlan)
class CarePlanAdmin(admin.ModelAdmin):
"""
Admin interface for CarePlan model.
"""
list_display = [
'care_plan_id', 'patient_name', 'title', 'plan_type',
'status', 'priority', 'start_date', 'completion_percentage',
'primary_provider_name'
]
list_filter = [
'tenant', 'plan_type', 'category', 'status', 'priority', 'approved'
]
search_fields = [
'patient__first_name', 'patient__last_name', 'patient__mrn',
'title', 'description',
'primary_provider__first_name', 'primary_provider__last_name'
]
readonly_fields = ['care_plan_id', 'created_at', 'updated_at']
filter_horizontal = ['care_team', 'related_problems']
fieldsets = (
('Basic Information', {
'fields': (
'care_plan_id', 'tenant', 'patient', 'title', 'description'
)
}),
('Plan Type', {
'fields': (
'plan_type', 'category', 'priority'
)
}),
('Timing', {
'fields': (
'start_date', 'end_date', 'target_completion_date'
)
}),
('Status', {
'fields': (
'status', 'completion_percentage'
)
}),
('Providers', {
'fields': (
'primary_provider', 'care_team'
)
}),
('Related Problems', {
'fields': (
'related_problems',
)
}),
('Goals and Objectives', {
'fields': (
'goals', 'objectives'
)
}),
('Interventions', {
'fields': (
'interventions', 'activities'
)
}),
('Monitoring', {
'fields': (
'monitoring_parameters', 'evaluation_criteria'
)
}),
('Patient Involvement', {
'fields': (
'patient_goals', 'patient_preferences', 'patient_barriers'
)
}),
('Resources', {
'fields': (
'resources_needed', 'support_systems'
)
}),
('Progress', {
'fields': (
'progress_notes', 'last_reviewed', 'next_review_date'
)
}),
('Outcomes', {
'fields': (
'outcomes_achieved',
)
}),
('Approval', {
'fields': (
'approved', 'approved_by', 'approved_date'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
def patient_name(self, obj):
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def primary_provider_name(self, obj):
return obj.primary_provider.get_full_name()
primary_provider_name.short_description = 'Primary Provider'
@admin.register(ClinicalNote)
class ClinicalNoteAdmin(admin.ModelAdmin):
"""
Admin interface for ClinicalNote model.
"""
list_display = [
'note_id', 'patient_name', 'title', 'note_type',
'status', 'author_name', 'note_datetime', 'word_count_display',
'electronically_signed'
]
list_filter = [
'note_type', 'status', 'electronically_signed', 'confidential',
'restricted_access', 'note_datetime'
]
search_fields = [
'patient__first_name', 'patient__last_name', 'patient__mrn',
'title', 'content',
'author__first_name', 'author__last_name'
]
readonly_fields = ['note_id', 'word_count_display', 'created_at', 'updated_at']
filter_horizontal = ['co_signers', 'related_problems', 'related_care_plans']
fieldsets = (
('Basic Information', {
'fields': (
'note_id', 'encounter', 'patient', 'note_type', 'title'
)
}),
('Content', {
'fields': (
'content', 'word_count_display'
)
}),
('Template', {
'fields': (
'template', 'structured_data'
)
}),
('Provider Information', {
'fields': (
'author', 'co_signers'
)
}),
('Status', {
'fields': (
'status', 'note_datetime'
)
}),
('Signatures', {
'fields': (
'electronically_signed', 'signed_datetime', 'signature_method'
)
}),
('Amendment', {
'fields': (
'amended_note', 'amendment_reason'
)
}),
('Quality', {
'fields': (
'quality_score', 'compliance_flags'
)
}),
('Privacy', {
'fields': (
'confidential', 'restricted_access', 'access_restrictions'
)
}),
('Related Information', {
'fields': (
'related_problems', 'related_care_plans'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at'
)
}),
)
def patient_name(self, obj):
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def author_name(self, obj):
return obj.author.get_full_name()
author_name.short_description = 'Author'
def word_count_display(self, obj):
return f"{obj.word_count} words"
word_count_display.short_description = 'Word Count'
@admin.register(NoteTemplate)
class NoteTemplateAdmin(admin.ModelAdmin):
"""
Admin interface for NoteTemplate model.
"""
list_display = [
'template_id', 'name', 'note_type', 'specialty',
'is_active', 'is_default', 'version', 'usage_count'
]
list_filter = [
'tenant', 'note_type', 'specialty', 'is_active', 'is_default'
]
search_fields = [
'name', 'description', 'template_content'
]
readonly_fields = ['template_id', 'usage_count', 'created_at', 'updated_at']
fieldsets = (
('Basic Information', {
'fields': (
'template_id', 'tenant', 'name', 'description'
)
}),
('Template Type', {
'fields': (
'note_type', 'specialty'
)
}),
('Content', {
'fields': (
'template_content', 'structured_fields'
)
}),
('Usage', {
'fields': (
'is_active', 'is_default', 'usage_count'
)
}),
('Version Control', {
'fields': (
'version', 'previous_version'
)
}),
('Quality', {
'fields': (
'quality_indicators', 'compliance_requirements'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
# Inline admin classes for related models
class VitalSignsInline(admin.TabularInline):
"""
Inline admin for VitalSigns.
"""
model = VitalSigns
extra = 0
readonly_fields = ['measurement_id', 'bmi']
fields = [
'measured_datetime', 'temperature', 'systolic_bp', 'diastolic_bp',
'heart_rate', 'respiratory_rate', 'oxygen_saturation', 'measured_by'
]
class ClinicalNoteInline(admin.TabularInline):
"""
Inline admin for ClinicalNote.
"""
model = ClinicalNote
extra = 0
readonly_fields = ['note_id']
fields = ['note_type', 'title', 'status', 'author', 'note_datetime']
class ProblemListInline(admin.TabularInline):
"""
Inline admin for ProblemList.
"""
model = ProblemList
extra = 0
readonly_fields = ['problem_id']
fields = ['problem_name', 'problem_type', 'status', 'severity', 'diagnosing_provider']
# Add inlines to Encounter admin
EncounterAdmin.inlines = [VitalSignsInline, ClinicalNoteInline, ProblemListInline]