428 lines
13 KiB
Python
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')
|
|
|