2025-08-12 13:33:25 +03:00

428 lines
13 KiB
Python

"""
Admin configuration for patients app.
"""
from django.contrib import admin
from django.utils.html import format_html
from .models import (
PatientProfile, EmergencyContact, InsuranceInfo,
ConsentTemplate, ConsentForm, PatientNote
)
class EmergencyContactInline(admin.TabularInline):
"""
Inline admin for emergency contacts.
"""
model = EmergencyContact
extra = 1
fields = [
'first_name', 'last_name', 'relationship', 'phone_number',
'priority', 'is_authorized_for_medical_decisions', 'is_active'
]
class InsuranceInfoInline(admin.TabularInline):
"""
Inline admin for insurance information.
"""
model = InsuranceInfo
extra = 1
fields = [
'insurance_type', 'insurance_company', 'policy_number',
'effective_date', 'is_verified', 'is_active'
]
class ConsentFormInline(admin.TabularInline):
"""
Inline admin for consent forms.
"""
model = ConsentForm
extra = 0
fields = ['template', 'status', 'effective_date', 'patient_signed_at']
readonly_fields = ['patient_signed_at']
class PatientNoteInline(admin.TabularInline):
"""
Inline admin for patient notes.
"""
model = PatientNote
extra = 0
fields = ['title', 'category', 'priority', 'is_alert', 'created_at']
readonly_fields = ['created_at']
@admin.register(PatientProfile)
class PatientProfileAdmin(admin.ModelAdmin):
"""
Admin configuration for PatientProfile model.
"""
list_display = [
'mrn', 'get_full_name', 'date_of_birth', 'age', 'gender',
'phone_number', 'is_active',
]
list_filter = [
'tenant', 'gender', 'race', 'ethnicity', 'marital_status',
'is_active', 'is_deceased', 'is_vip', 'confidential_patient',
]
search_fields = [
'mrn', 'first_name', 'last_name', 'email', 'phone_number',
'ssn', 'drivers_license'
]
ordering = ['last_name', 'first_name']
fieldsets = (
('Basic Information', {
'fields': (
'tenant', 'mrn', 'first_name', 'last_name', 'middle_name',
'preferred_name', 'suffix', 'photo'
)
}),
('Demographics', {
'fields': (
'date_of_birth', 'gender', 'sex_assigned_at_birth',
'race', 'ethnicity', 'marital_status'
)
}),
('Contact Information', {
'fields': (
'email', 'phone_number', 'mobile_number',
'address_line_1', 'address_line_2', 'city', 'state',
'zip_code', 'country'
)
}),
('Identification', {
'fields': ('ssn', 'drivers_license', 'drivers_license_state')
}),
('Language and Communication', {
'fields': (
'primary_language', 'interpreter_needed', 'communication_preference'
)
}),
('Employment', {
'fields': ('employer', 'occupation')
}),
('Healthcare Information', {
'fields': (
'primary_care_physician', 'referring_physician',
'allergies', 'medical_alerts'
)
}),
('Advance Directives', {
'fields': ('has_advance_directive', 'advance_directive_type')
}),
('Status and Flags', {
'fields': (
'is_active', 'is_deceased', 'date_of_death',
'is_vip', 'confidential_patient'
)
}),
('Registration', {
'fields': ( 'registered_by', 'last_visit_date'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('patient_id', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['patient_id', 'created_at', 'updated_at', 'age']
inlines = [EmergencyContactInline, InsuranceInfoInline, ConsentFormInline, PatientNoteInline]
def get_queryset(self, request):
return super().get_queryset(request).select_related('tenant', 'registered_by')
def age(self, obj):
return obj.age
age.short_description = 'Age'
@admin.register(EmergencyContact)
class EmergencyContactAdmin(admin.ModelAdmin):
"""
Admin configuration for EmergencyContact model.
"""
list_display = [
'get_full_name', 'patient', 'relationship', 'phone_number',
'priority', 'is_authorized_for_medical_decisions', 'is_active'
]
list_filter = [
'relationship', 'priority', 'is_authorized_for_medical_decisions',
'is_authorized_for_financial_decisions', 'is_authorized_for_information',
'is_active'
]
search_fields = [
'first_name', 'last_name', 'phone_number', 'email',
'patient__first_name', 'patient__last_name', 'patient__mrn'
]
ordering = ['patient__last_name', 'priority', 'last_name']
fieldsets = (
('Contact Information', {
'fields': (
'patient', 'first_name', 'last_name', 'relationship'
)
}),
('Contact Details', {
'fields': (
'phone_number', 'mobile_number', 'email'
)
}),
('Address', {
'fields': (
'address_line_1', 'address_line_2', 'city', 'state', 'zip_code'
)
}),
('Authorization', {
'fields': (
'priority', 'is_authorized_for_medical_decisions',
'is_authorized_for_financial_decisions', 'is_authorized_for_information'
)
}),
('Status', {
'fields': ('is_active', 'notes')
}),
('Metadata', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
def get_queryset(self, request):
return super().get_queryset(request).select_related('patient')
@admin.register(InsuranceInfo)
class InsuranceInfoAdmin(admin.ModelAdmin):
"""
Admin configuration for InsuranceInfo model.
"""
list_display = [
'patient', 'insurance_company', 'insurance_type', 'policy_number',
'is_verified', 'is_coverage_active', 'effective_date'
]
list_filter = [
'insurance_type', 'plan_type', 'is_verified', 'is_active',
'subscriber_relationship', 'effective_date'
]
search_fields = [
'insurance_company', 'plan_name', 'policy_number', 'group_number',
'subscriber_name', 'patient__first_name', 'patient__last_name', 'patient__mrn'
]
ordering = ['patient__last_name', 'insurance_type']
fieldsets = (
('Patient Information', {
'fields': ('patient',)
}),
('Insurance Details', {
'fields': (
'insurance_type', 'insurance_company', 'plan_name', 'plan_type'
)
}),
('Policy Information', {
'fields': ('policy_number', 'group_number')
}),
('Subscriber Information', {
'fields': (
'subscriber_name', 'subscriber_relationship',
'subscriber_dob', 'subscriber_ssn'
)
}),
('Coverage', {
'fields': ('effective_date', 'termination_date')
}),
('Financial Information', {
'fields': ('copay_amount', 'deductible_amount', 'out_of_pocket_max')
}),
('Verification', {
'fields': ('is_verified', 'verification_date', 'verified_by')
}),
('Authorization', {
'fields': (
'requires_authorization', 'authorization_number', 'authorization_expiry'
)
}),
('Status', {
'fields': ('is_active', 'notes')
}),
('Metadata', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
def get_queryset(self, request):
return super().get_queryset(request).select_related('patient', 'verified_by')
def is_coverage_active(self, obj):
return obj.is_coverage_active
is_coverage_active.boolean = True
is_coverage_active.short_description = 'Coverage Active'
@admin.register(ConsentTemplate)
class ConsentTemplateAdmin(admin.ModelAdmin):
"""
Admin configuration for ConsentTemplate model.
"""
list_display = [
'name', 'category', 'version', 'is_active',
'effective_date', 'created_by'
]
list_filter = [
'tenant', 'category', 'is_active', 'requires_signature',
'requires_witness', 'requires_guardian', 'effective_date'
]
search_fields = ['name', 'description', 'category']
ordering = ['category', 'name']
fieldsets = (
('Template Information', {
'fields': ('tenant', 'name', 'description', 'category')
}),
('Content', {
'fields': ('content',)
}),
('Requirements', {
'fields': (
'requires_signature', 'requires_witness', 'requires_guardian'
)
}),
('Validity', {
'fields': ('is_active', 'version', 'effective_date', 'expiry_date')
}),
('Metadata', {
'fields': ('created_at', 'updated_at', 'created_by'),
'classes': ('collapse',)
}),
)
readonly_fields = ['created_at', 'updated_at']
def get_queryset(self, request):
return super().get_queryset(request).select_related('tenant', 'created_by')
@admin.register(ConsentForm)
class ConsentFormAdmin(admin.ModelAdmin):
"""
Admin configuration for ConsentForm model.
"""
list_display = [
'patient', 'template', 'status', 'is_valid',
'patient_signed_at', 'effective_date'
]
list_filter = [
'status', 'template__category', 'patient_signed_at',
'effective_date', 'created_at'
]
search_fields = [
'patient__first_name', 'patient__last_name', 'patient__mrn',
'template__name', 'guardian_name', 'witness_name', 'provider_name'
]
ordering = ['-created_at']
fieldsets = (
('Consent Information', {
'fields': ('patient', 'template', 'status')
}),
('Patient Signature', {
'fields': (
'patient_signature', 'patient_signed_at', 'patient_ip_address'
)
}),
('Guardian Signature', {
'fields': (
'guardian_signature', 'guardian_signed_at',
'guardian_name', 'guardian_relationship'
)
}),
('Witness Signature', {
'fields': (
'witness_signature', 'witness_signed_at',
'witness_name', 'witness_title'
)
}),
('Provider Information', {
'fields': (
'provider_name', 'provider_signature', 'provider_signed_at'
)
}),
('Validity', {
'fields': ('effective_date', 'expiry_date')
}),
('Revocation', {
'fields': ('revoked_at', 'revoked_by', 'revocation_reason')
}),
('Notes', {
'fields': ('notes',)
}),
('Metadata', {
'fields': ('consent_id', 'created_at', 'updated_at', 'created_by'),
'classes': ('collapse',)
}),
)
readonly_fields = ['consent_id', 'created_at', 'updated_at']
def get_queryset(self, request):
return super().get_queryset(request).select_related(
'patient', 'template', 'created_by', 'revoked_by'
)
def is_valid(self, obj):
return obj.is_valid
is_valid.boolean = True
is_valid.short_description = 'Valid'
@admin.register(PatientNote)
class PatientNoteAdmin(admin.ModelAdmin):
"""
Admin configuration for PatientNote model.
"""
list_display = [
'title', 'patient', 'category', 'priority',
'is_alert', 'is_confidential', 'created_by', 'created_at'
]
list_filter = [
'category', 'priority', 'is_alert', 'is_confidential',
'is_active', 'created_at'
]
search_fields = [
'title', 'content', 'patient__first_name',
'patient__last_name', 'patient__mrn'
]
ordering = ['-created_at']
fieldsets = (
('Note Information', {
'fields': ('patient', 'title', 'content')
}),
('Classification', {
'fields': ('category', 'priority')
}),
('Visibility', {
'fields': ('is_confidential', 'is_alert', 'is_active')
}),
('Metadata', {
'fields': ('note_id', 'created_at', 'updated_at', 'created_by'),
'classes': ('collapse',)
}),
)
readonly_fields = ['note_id', 'created_at', 'updated_at']
def get_queryset(self, request):
return super().get_queryset(request).select_related('patient', 'created_by')