Marwan Alwali ab2c4a36c5 update
2025-10-02 10:13:03 +03:00

556 lines
16 KiB
Python

"""
Admin configuration for pharmacy app.
"""
from django.contrib import admin
from django.utils.html import format_html
from django.urls import reverse
from django.utils import timezone
from .models import (
Medication, Prescription, MedicationInventoryItem, DispenseRecord,
MedicationAdministration, DrugInteraction
)
@admin.register(Medication)
class MedicationAdmin(admin.ModelAdmin):
"""
Admin interface for Medication model.
"""
list_display = [
'generic_name', 'brand_name', 'strength', 'dosage_form',
'controlled_substance_schedule', 'formulary_status', 'is_active'
]
list_filter = [
'dosage_form', 'controlled_substance_schedule', 'formulary_status',
'is_active', 'drug_class', 'created_at'
]
search_fields = [
'generic_name', 'brand_name', 'ndc_number', 'rxcui', 'drug_class'
]
readonly_fields = ['medication_id', 'created_at', 'updated_at']
fieldsets = (
('Basic Information', {
'fields': (
'medication_id', 'generic_name', 'brand_name', 'drug_class'
)
}),
('Drug Identification', {
'fields': (
'ndc_number', 'rxcui', 'controlled_substance_schedule'
)
}),
('Formulation', {
'fields': (
'dosage_form', 'strength', 'unit_of_measure'
)
}),
('Clinical Information', {
'fields': (
'indications', 'contraindications', 'side_effects', 'warnings'
)
}),
('Dosing Information', {
'fields': (
'adult_dose_range', 'pediatric_dose_range', 'max_daily_dose',
'routes_of_administration', 'administration_instructions'
)
}),
('Storage and Handling', {
'fields': (
'storage_requirements', 'special_handling'
)
}),
('Formulary and Availability', {
'fields': (
'formulary_status', 'is_active', 'is_available'
)
}),
('Pricing', {
'fields': (
'unit_cost', 'awp'
)
}),
('Manufacturer', {
'fields': (
'manufacturer', 'manufacturer_ndc'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
def get_queryset(self, request):
"""Filter by tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
return qs.filter(tenant=request.user.tenant)
return qs.none()
def save_model(self, request, obj, form, change):
"""Set tenant and created_by."""
if not change:
obj.tenant = request.user.tenant
obj.created_by = request.user
super().save_model(request, obj, form, change)
class DispenseRecordInline(admin.TabularInline):
"""
Inline admin for dispense records.
"""
model = DispenseRecord
extra = 0
readonly_fields = ['dispense_id', 'created_at']
fields = [
'inventory_stock', 'quantity_dispensed', 'date_dispensed',
'dispensed_by', 'status', 'patient_counseled'
]
@admin.register(Prescription)
class PrescriptionAdmin(admin.ModelAdmin):
"""
Admin interface for Prescription model.
"""
list_display = [
'prescription_number', 'patient_name', 'medication_name',
'prescriber', 'status', 'date_prescribed', 'expiration_date'
]
list_filter = [
'status', 'date_prescribed', 'verified', 'electronic_prescription',
'generic_substitution_allowed', 'prior_authorization_required'
]
search_fields = [
'prescription_number', 'patient__first_name', 'patient__last_name',
'patient__mrn', 'medication__generic_name', 'medication__brand_name'
]
readonly_fields = [
'prescription_id', 'prescription_number', 'created_at', 'updated_at'
]
inlines = [DispenseRecordInline]
fieldsets = (
('Prescription Information', {
'fields': (
'prescription_id', 'prescription_number', 'patient',
'prescriber', 'encounter'
)
}),
('Medication', {
'fields': (
'medication', 'quantity_prescribed', 'quantity_unit'
)
}),
('Dosing Instructions', {
'fields': (
'dosage_instructions', 'frequency', 'duration'
)
}),
('Refills', {
'fields': (
'refills_authorized', 'refills_remaining'
)
}),
('Dates', {
'fields': (
'date_prescribed', 'date_written', 'expiration_date'
)
}),
('Status', {
'fields': (
'status', 'verified', 'verified_by', 'verified_datetime'
)
}),
('Clinical Information', {
'fields': (
'indication', 'diagnosis_code'
)
}),
('Instructions', {
'fields': (
'pharmacy_notes', 'patient_instructions'
)
}),
('Prior Authorization', {
'fields': (
'prior_authorization_required', 'prior_authorization_number',
'prior_authorization_expiry'
)
}),
('Substitution', {
'fields': (
'generic_substitution_allowed', 'dispense_as_written'
)
}),
('Electronic Prescription', {
'fields': (
'electronic_prescription', 'e_prescription_id'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at'
)
}),
)
def patient_name(self, obj):
"""Get patient name."""
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def medication_name(self, obj):
"""Get medication name."""
return obj.medication.display_name
medication_name.short_description = 'Medication'
def get_queryset(self, request):
"""Filter by tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
return qs.filter(tenant=request.user.tenant)
return qs.none()
def save_model(self, request, obj, form, change):
"""Set tenant."""
if not change:
obj.tenant = request.user.tenant
super().save_model(request, obj, form, change)
@admin.register(MedicationInventoryItem)
class MedicationInventoryItemAdmin(admin.ModelAdmin):
"""
Admin interface for MedicationInventoryItem model.
"""
list_display = [
'medication_name', 'inventory_item_name', 'formulary_tier',
'requires_counseling', 'requires_id_verification'
]
list_filter = [
'formulary_tier', 'therapeutic_equivalent', 'auto_substitution_allowed',
'requires_counseling', 'requires_id_verification'
]
search_fields = [
'medication__generic_name', 'medication__brand_name',
'inventory_item__item_name', 'inventory_item__item_code'
]
readonly_fields = [
'medication_inventory_id', 'created_at', 'updated_at'
]
fieldsets = (
('Basic Information', {
'fields': (
'medication_inventory_id', 'medication', 'inventory_item'
)
}),
('Pharmacy Settings', {
'fields': (
'formulary_tier', 'therapeutic_equivalent', 'auto_substitution_allowed'
)
}),
('Dispensing Rules', {
'fields': (
'max_dispense_quantity', 'requires_counseling', 'requires_id_verification'
)
}),
('Notes', {
'fields': (
'pharmacy_notes',
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
def medication_name(self, obj):
"""Get medication name."""
return obj.medication.display_name
medication_name.short_description = 'Medication'
def inventory_item_name(self, obj):
"""Get inventory item name."""
return obj.inventory_item.item_name
inventory_item_name.short_description = 'Inventory Item'
def get_queryset(self, request):
"""Filter by tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
return qs.filter(tenant=request.user.tenant)
return qs.none()
def save_model(self, request, obj, form, change):
"""Set tenant and created_by."""
if not change:
obj.tenant = request.user.tenant
obj.created_by = request.user
super().save_model(request, obj, form, change)
@admin.register(DispenseRecord)
class DispenseRecordAdmin(admin.ModelAdmin):
"""
Admin interface for DispenseRecord model.
"""
list_display = [
'prescription_number', 'patient_name', 'medication_name',
'quantity_dispensed', 'date_dispensed', 'dispensed_by', 'status'
]
list_filter = [
'status', 'date_dispensed', 'is_refill', 'patient_counseled',
'quality_check_performed'
]
search_fields = [
'prescription__prescription_number', 'prescription__patient__first_name',
'prescription__patient__last_name'
]
readonly_fields = [
'dispense_id', 'total_price', 'quantity_remaining',
'created_at', 'updated_at'
]
fieldsets = (
('Dispense Information', {
'fields': (
'dispense_id', 'prescription', 'inventory_stock'
)
}),
('Quantity', {
'fields': (
'quantity_dispensed', 'quantity_remaining'
)
}),
('Date and Staff', {
'fields': (
'date_dispensed', 'dispensed_by', 'verified_by'
)
}),
('Pricing', {
'fields': (
'unit_price', 'total_price', 'copay_amount', 'insurance_amount'
)
}),
('Patient Information', {
'fields': (
'patient_counseled', 'counseling_notes'
)
}),
('Refill Information', {
'fields': (
'is_refill', 'refill_number'
)
}),
('Status', {
'fields': (
'status',
)
}),
('Pickup Information', {
'fields': (
'picked_up_by', 'pickup_datetime', 'identification_verified'
)
}),
('Quality Control', {
'fields': (
'quality_check_performed', 'quality_notes'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at'
)
}),
)
def prescription_number(self, obj):
"""Get prescription number."""
return obj.prescription.prescription_number
prescription_number.short_description = 'Prescription #'
def patient_name(self, obj):
"""Get patient name."""
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def medication_name(self, obj):
"""Get medication name."""
return obj.medication
medication_name.short_description = 'Medication'
@admin.register(MedicationAdministration)
class MedicationAdministrationAdmin(admin.ModelAdmin):
"""
Admin interface for MedicationAdministration model.
"""
list_display = [
'patient_name', 'medication_name', 'scheduled_datetime',
'actual_datetime', 'status', 'administered_by'
]
list_filter = [
'status', 'scheduled_datetime', 'route_given', 'double_checked'
]
search_fields = [
'patient__first_name', 'patient__last_name',
'prescription__medication__generic_name'
]
readonly_fields = [
'administration_id', 'created_at', 'updated_at'
]
fieldsets = (
('Administration Information', {
'fields': (
'administration_id', 'prescription', 'patient', 'encounter'
)
}),
('Scheduled vs Actual', {
'fields': (
'scheduled_datetime', 'actual_datetime'
)
}),
('Dosage', {
'fields': (
'dose_given', 'route_given'
)
}),
('Status', {
'fields': (
'status',
)
}),
('Staff', {
'fields': (
'administered_by', 'witnessed_by'
)
}),
('Reason for Not Given', {
'fields': (
'reason_not_given', 'reason_notes'
)
}),
('Patient Response', {
'fields': (
'patient_response', 'side_effects_observed'
)
}),
('Site Information', {
'fields': (
'injection_site', 'site_condition'
)
}),
('Verification', {
'fields': (
'double_checked', 'double_checked_by'
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at'
)
}),
)
def patient_name(self, obj):
"""Get patient name."""
return obj.patient.get_full_name()
patient_name.short_description = 'Patient'
def medication_name(self, obj):
"""Get medication name."""
return obj.medication.display_name
medication_name.short_description = 'Medication'
@admin.register(DrugInteraction)
class DrugInteractionAdmin(admin.ModelAdmin):
"""
Admin interface for DrugInteraction model.
"""
list_display = [
'medication_1_name', 'medication_2_name', 'severity',
'interaction_type', 'evidence_level', 'is_active'
]
list_filter = [
'severity', 'interaction_type', 'evidence_level', 'is_active'
]
search_fields = [
'medication_1__generic_name', 'medication_1__brand_name',
'medication_2__generic_name', 'medication_2__brand_name'
]
readonly_fields = [
'interaction_id', 'created_at', 'updated_at'
]
fieldsets = (
('Interaction Information', {
'fields': (
'interaction_id', 'medication_1', 'medication_2'
)
}),
('Severity and Type', {
'fields': (
'severity', 'interaction_type'
)
}),
('Interaction Details', {
'fields': (
'mechanism', 'clinical_effect'
)
}),
('Management', {
'fields': (
'management_recommendations', 'monitoring_parameters'
)
}),
('Evidence', {
'fields': (
'evidence_level', 'references'
)
}),
('Status', {
'fields': (
'is_active',
)
}),
('Metadata', {
'fields': (
'created_at', 'updated_at', 'created_by'
)
}),
)
def medication_1_name(self, obj):
"""Get first medication name."""
return obj.medication_1.display_name
medication_1_name.short_description = 'Medication 1'
def medication_2_name(self, obj):
"""Get second medication name."""
return obj.medication_2.display_name
medication_2_name.short_description = 'Medication 2'
def get_queryset(self, request):
"""Filter by tenant."""
qs = super().get_queryset(request)
if hasattr(request.user, 'tenant'):
return qs.filter(tenant=request.user.tenant)
return qs.none()
def save_model(self, request, obj, form, change):
"""Set tenant and created_by."""
if not change:
obj.tenant = request.user.tenant
obj.created_by = request.user
super().save_model(request, obj, form, change)