hospital-management/INSURANCE_APPROVAL_INTEGRATION.md
2025-10-03 20:11:25 +03:00

589 lines
19 KiB
Markdown

# Insurance Approval Integration Documentation
## Overview
The Insurance Approval Request module has been successfully integrated with all relevant clinical order modules in the hospital management system. This document outlines the integration points and usage patterns.
---
## Integrated Modules
### 1. Laboratory Module ✅
**Model:** `LabOrder`
**File:** `laboratory/models.py`
#### Integration Details:
- Added `GenericRelation` to link lab orders with approval requests
- Added helper methods for approval status checking
- Supports multi-tenant approval tracking
#### Helper Methods Added:
```python
# Check if order has valid approval
lab_order.has_valid_approval() # Returns True/False
# Get active approval
lab_order.get_active_approval() # Returns InsuranceApprovalRequest or None
# Check if approval is required
lab_order.requires_approval() # Returns True/False
# Get approval status for display
lab_order.approval_status # Returns status string
```
#### Usage Example:
```python
from laboratory.models import LabOrder
from insurance_approvals.models import InsuranceApprovalRequest
# Create a lab order
lab_order = LabOrder.objects.get(order_number='LAB-1-000001')
# Check if approval is needed
if lab_order.requires_approval():
# Create approval request
approval = InsuranceApprovalRequest.objects.create(
tenant=lab_order.tenant,
patient=lab_order.patient,
insurance_info=lab_order.patient.insurance_info.first(),
request_type='LABORATORY',
content_object=lab_order, # Links to lab order
service_description=f"Lab tests: {', '.join([t.test_name for t in lab_order.tests.all()])}",
procedure_codes=', '.join([t.cpt_code for t in lab_order.tests.all() if t.cpt_code]),
diagnosis_codes=lab_order.diagnosis_code or '',
clinical_justification=lab_order.clinical_indication,
requesting_provider=lab_order.ordering_provider,
service_start_date=lab_order.collection_datetime.date() if lab_order.collection_datetime else timezone.now().date(),
priority='ROUTINE',
status='PENDING_SUBMISSION',
)
# Check approval status
if lab_order.has_valid_approval():
print("Order has valid approval - proceed with processing")
else:
print(f"Approval status: {lab_order.approval_status}")
# Get all approval requests for this order
approvals = lab_order.approval_requests.all()
```
---
### 2. Radiology Module ✅
**Model:** `ImagingOrder`
**File:** `radiology/models.py`
#### Integration Details:
- Added `GenericRelation` to link imaging orders with approval requests
- Added identical helper methods as laboratory module
- Supports all imaging modalities (CT, MRI, X-Ray, etc.)
#### Helper Methods Added:
```python
# Check if order has valid approval
imaging_order.has_valid_approval() # Returns True/False
# Get active approval
imaging_order.get_active_approval() # Returns InsuranceApprovalRequest or None
# Check if approval is required
imaging_order.requires_approval() # Returns True/False
# Get approval status for display
imaging_order.approval_status # Returns status string
```
#### Usage Example:
```python
from radiology.models import ImagingOrder
from insurance_approvals.models import InsuranceApprovalRequest
# Create an imaging order
imaging_order = ImagingOrder.objects.get(order_number='IMG-1-000001')
# Check if approval is needed
if imaging_order.requires_approval():
# Create approval request
approval = InsuranceApprovalRequest.objects.create(
tenant=imaging_order.tenant,
patient=imaging_order.patient,
insurance_info=imaging_order.patient.insurance_info.first(),
request_type='RADIOLOGY',
content_object=imaging_order, # Links to imaging order
service_description=imaging_order.study_description,
procedure_codes=imaging_order.modality, # Could be enhanced with CPT codes
diagnosis_codes=imaging_order.diagnosis_code or '',
clinical_justification=imaging_order.clinical_indication,
requesting_provider=imaging_order.ordering_provider,
service_start_date=imaging_order.requested_datetime.date() if imaging_order.requested_datetime else timezone.now().date(),
priority='URGENT' if imaging_order.is_stat else 'ROUTINE',
status='PENDING_SUBMISSION',
)
# Access approvals
active_approval = imaging_order.get_active_approval()
if active_approval:
print(f"Authorization Number: {active_approval.authorization_number}")
print(f"Expires: {active_approval.expiration_date}")
```
---
## Common Integration Patterns
### Pattern 1: Pre-Order Approval Check
```python
def create_order_with_approval_check(patient, order_type, **order_data):
"""
Create an order and check if insurance approval is required.
"""
# Create the order
if order_type == 'LAB':
order = LabOrder.objects.create(patient=patient, **order_data)
elif order_type == 'IMAGING':
order = ImagingOrder.objects.create(patient=patient, **order_data)
# Check if approval is required
if order.requires_approval():
# Redirect to approval request creation
return {
'order': order,
'requires_approval': True,
'redirect_url': f'/insurance-approvals/create/?order_type={order_type}&order_id={order.id}'
}
return {
'order': order,
'requires_approval': False
}
```
### Pattern 2: Approval Status Display
```python
def get_order_status_with_approval(order):
"""
Get comprehensive order status including approval information.
"""
status = {
'order_status': order.status,
'has_insurance': order.patient.insurance_info.exists(),
'requires_approval': order.requires_approval(),
'approval_status': order.approval_status,
'can_proceed': False
}
if not status['has_insurance']:
status['can_proceed'] = True # No insurance, no approval needed
elif order.has_valid_approval():
status['can_proceed'] = True
status['approval'] = order.get_active_approval()
return status
```
### Pattern 3: Bulk Approval Status Check
```python
def get_orders_needing_approval(tenant, order_type='LAB'):
"""
Get all orders that need insurance approval.
"""
if order_type == 'LAB':
Model = LabOrder
elif order_type == 'IMAGING':
Model = ImagingOrder
orders = Model.objects.filter(
tenant=tenant,
status__in=['PENDING', 'SCHEDULED']
)
orders_needing_approval = []
for order in orders:
if order.requires_approval():
orders_needing_approval.append({
'order': order,
'patient': order.patient,
'insurance': order.patient.insurance_info.first(),
'approval_status': order.approval_status
})
return orders_needing_approval
```
---
## Approval Request Types
The system supports the following request types:
1. **LABORATORY** - Lab tests and panels
2. **RADIOLOGY** - Imaging studies (CT, MRI, X-Ray, etc.)
3. **PHARMACY** - Medications (to be integrated)
4. **PROCEDURE** - Medical procedures (to be integrated)
5. **SURGERY** - Surgical procedures (to be integrated)
6. **THERAPY** - Physical/Occupational therapy
7. **DME** - Durable Medical Equipment
8. **HOME_HEALTH** - Home health services
9. **HOSPICE** - Hospice care
10. **TRANSPORTATION** - Medical transportation
11. **OTHER** - Other services
---
## Approval Workflow States
```
DRAFT → PENDING_SUBMISSION → SUBMITTED → UNDER_REVIEW
MORE_INFO_REQUIRED (can loop back to SUBMITTED)
APPROVED / PARTIALLY_APPROVED / DENIED
APPEAL_SUBMITTED → APPEAL_APPROVED / APPEAL_DENIED
EXPIRED (if expiration_date passes)
```
---
## Database Relationships
### GenericForeignKey Pattern
```python
# In InsuranceApprovalRequest model
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
# In LabOrder/ImagingOrder models
approval_requests = GenericRelation(
'insurance_approvals.InsuranceApprovalRequest',
content_type_field='content_type',
object_id_field='object_id',
related_query_name='lab_order' # or 'imaging_order'
)
```
### Querying Across Relationships
```python
# Get all lab orders with approvals
from django.contrib.contenttypes.models import ContentType
from laboratory.models import LabOrder
from insurance_approvals.models import InsuranceApprovalRequest
lab_order_ct = ContentType.objects.get_for_model(LabOrder)
approvals_for_lab_orders = InsuranceApprovalRequest.objects.filter(
content_type=lab_order_ct
)
# Get specific lab order's approvals
lab_order = LabOrder.objects.get(pk=1)
approvals = lab_order.approval_requests.all()
# Reverse query - get order from approval
approval = InsuranceApprovalRequest.objects.get(pk=1)
order = approval.content_object # Returns LabOrder or ImagingOrder instance
```
---
## Template Integration Examples
### Display Approval Status in Order List
```django
{% for order in orders %}
<tr>
<td>{{ order.order_number }}</td>
<td>{{ order.patient.get_full_name }}</td>
<td>
{% if order.approval_status == 'APPROVED' %}
<span class="badge bg-success">Approved</span>
{% elif order.approval_status == 'APPROVAL_REQUIRED' %}
<span class="badge bg-warning">Approval Required</span>
<a href="{% url 'insurance_approvals:create' %}?order_id={{ order.id }}"
class="btn btn-sm btn-primary">Request Approval</a>
{% elif order.approval_status == 'NO_INSURANCE' %}
<span class="badge bg-secondary">No Insurance</span>
{% else %}
<span class="badge bg-info">{{ order.get_approval_status_display }}</span>
{% endif %}
</td>
</tr>
{% endfor %}
```
### Display Approval Details in Order Detail
```django
{% if order.has_valid_approval %}
<div class="alert alert-success">
<h6><i class="fa fa-check-circle"></i> Insurance Approval Active</h6>
{% with approval=order.get_active_approval %}
<p><strong>Authorization Number:</strong> {{ approval.authorization_number }}</p>
<p><strong>Expires:</strong> {{ approval.expiration_date|date:"M d, Y" }}</p>
<p><strong>Approved Quantity:</strong> {{ approval.approved_quantity }}</p>
{% endwith %}
</div>
{% elif order.requires_approval %}
<div class="alert alert-warning">
<h6><i class="fa fa-exclamation-triangle"></i> Insurance Approval Required</h6>
<p>This order requires insurance approval before processing.</p>
<a href="{% url 'insurance_approvals:create' %}?order_id={{ order.id }}"
class="btn btn-primary">Request Approval</a>
</div>
{% endif %}
```
---
## API Integration (DRF)
### Serializer Example
```python
from rest_framework import serializers
from laboratory.models import LabOrder
from insurance_approvals.models import InsuranceApprovalRequest
class LabOrderSerializer(serializers.ModelSerializer):
approval_status = serializers.CharField(read_only=True)
has_valid_approval = serializers.BooleanField(read_only=True)
requires_approval = serializers.SerializerMethodField()
active_approval = serializers.SerializerMethodField()
class Meta:
model = LabOrder
fields = '__all__'
def get_requires_approval(self, obj):
return obj.requires_approval()
def get_active_approval(self, obj):
approval = obj.get_active_approval()
if approval:
return {
'id': approval.id,
'approval_number': approval.approval_number,
'authorization_number': approval.authorization_number,
'status': approval.status,
'expiration_date': approval.expiration_date
}
return None
```
---
## Future Integration Points
### Pharmacy Module (Pending)
- **Model:** `PharmacyOrder` or `Prescription`
- **Request Type:** `PHARMACY`
- Same integration pattern as Lab and Radiology
### Operating Theatre Module (Pending)
- **Model:** `SurgerySchedule` or `OperativeCase`
- **Request Type:** `SURGERY` or `PROCEDURE`
- Same integration pattern
### Other Potential Integrations:
- Home Health Orders
- DME Orders
- Physical Therapy Orders
- Hospice Care Orders
---
## Migration Notes
**IMPORTANT:** Migrations are NOT included in this integration. The user will handle migrations separately.
### To apply changes:
1. Create migrations: `python manage.py makemigrations laboratory radiology`
2. Review migrations carefully
3. Apply migrations: `python manage.py migrate`
---
## Testing Recommendations
### Unit Tests
```python
from django.test import TestCase
from laboratory.models import LabOrder
from insurance_approvals.models import InsuranceApprovalRequest
class LabOrderApprovalIntegrationTest(TestCase):
def test_order_requires_approval_with_insurance(self):
# Create patient with insurance
patient = self.create_patient_with_insurance()
order = LabOrder.objects.create(patient=patient, ...)
self.assertTrue(order.requires_approval())
def test_order_has_valid_approval(self):
order = self.create_lab_order()
approval = InsuranceApprovalRequest.objects.create(
content_object=order,
status='APPROVED',
expiration_date=timezone.now().date() + timedelta(days=30),
...
)
self.assertTrue(order.has_valid_approval())
self.assertEqual(order.get_active_approval(), approval)
```
---
### 3. Pharmacy Module ✅
**Model:** `Prescription`
**File:** `pharmacy/models.py`
#### Integration Details:
- Added `GenericRelation` to link prescriptions with approval requests
- Added helper methods for approval status checking
- Enhanced with prior authorization support
- Checks medication formulary status for approval requirements
#### Helper Methods Added:
```python
# Check if prescription has valid approval
prescription.has_valid_approval() # Returns True/False
# Get active approval
prescription.get_active_approval() # Returns InsuranceApprovalRequest or None
# Check if approval is required
prescription.requires_approval() # Returns True/False
# Get approval status for display
prescription.approval_status # Returns status string
```
#### Special Features:
- **Prior Authorization Integration**: Checks both approval requests and prior authorization fields
- **Formulary Status**: Automatically requires approval for RESTRICTED or PRIOR_AUTH medications
- **Enhanced Status**: Returns specific statuses like 'PRIOR_AUTH_REQUIRED', 'PRIOR_AUTH_EXPIRED', etc.
#### Usage Example:
```python
from pharmacy.models import Prescription
from insurance_approvals.models import InsuranceApprovalRequest
# Create a prescription
prescription = Prescription.objects.get(prescription_number='RX-1-000001')
# Check if approval is needed (considers formulary status)
if prescription.requires_approval():
# Create approval request
approval = InsuranceApprovalRequest.objects.create(
tenant=prescription.tenant,
patient=prescription.patient,
insurance_info=prescription.patient.insurance_info.first(),
request_type='PHARMACY',
content_object=prescription, # Links to prescription
service_description=f"{prescription.medication.display_name} - {prescription.quantity_prescribed} {prescription.quantity_unit}",
procedure_codes=prescription.medication.ndc_number or '',
diagnosis_codes=prescription.diagnosis_code or '',
clinical_justification=prescription.indication or 'As prescribed',
requesting_provider=prescription.prescriber,
service_start_date=prescription.date_written,
priority='URGENT' if prescription.medication.is_controlled_substance else 'ROUTINE',
status='PENDING_SUBMISSION',
requested_quantity=prescription.quantity_prescribed,
)
# Check prior authorization
if prescription.prior_authorization_required:
if not prescription.prior_authorization_number:
print("Prior authorization required but not obtained")
```
---
### 4. Operating Theatre Module ✅
**Model:** `SurgicalCase`
**File:** `operating_theatre/models.py`
#### Integration Details:
- Added `GenericRelation` to link surgical cases with approval requests
- Added helper methods for approval status checking
- Enhanced with emergency case handling
- Supports elective and emergency approval workflows
#### Helper Methods Added:
```python
# Check if surgical case has valid approval
surgical_case.has_valid_approval() # Returns True/False
# Get active approval
surgical_case.get_active_approval() # Returns InsuranceApprovalRequest or None
# Check if approval is required
surgical_case.requires_approval() # Returns True/False
# Get approval status for display
surgical_case.approval_status # Returns status string
```
#### Special Features:
- **Emergency Case Handling**: Different approval requirements for emergency vs elective cases
- **Enhanced Status**: Returns 'EMERGENCY_APPROVAL_REQUIRED' for emergency cases
- **Procedure Code Support**: Integrates with procedure_codes JSON field
#### Usage Example:
```python
from operating_theatre.models import SurgicalCase
from insurance_approvals.models import InsuranceApprovalRequest
# Create a surgical case
surgical_case = SurgicalCase.objects.get(case_number='SURG-20250103-0001')
# Check if approval is needed
if surgical_case.requires_approval():
# Determine priority based on case type
if surgical_case.is_emergency:
priority = 'STAT'
is_expedited = True
else:
priority = 'ROUTINE'
is_expedited = False
# Create approval request
approval = InsuranceApprovalRequest.objects.create(
tenant=surgical_case.tenant,
patient=surgical_case.patient,
insurance_info=surgical_case.patient.insurance_info.first(),
request_type='SURGERY',
content_object=surgical_case, # Links to surgical case
service_description=surgical_case.primary_procedure,
procedure_codes=', '.join(surgical_case.procedure_codes) if surgical_case.procedure_codes else '',
diagnosis_codes=', '.join(surgical_case.diagnosis_codes) if surgical_case.diagnosis_codes else surgical_case.diagnosis,
clinical_justification=surgical_case.clinical_notes or f"Surgical intervention required for {surgical_case.diagnosis}",
requesting_provider=surgical_case.primary_surgeon,
service_start_date=surgical_case.scheduled_start.date(),
priority=priority,
is_expedited=is_expedited,
status='PENDING_SUBMISSION',
)
```
---
## Summary
**Laboratory Module** - Fully integrated
**Radiology Module** - Fully integrated
**Pharmacy Module** - Fully integrated (with prior auth support)
**Operating Theatre Module** - Fully integrated (with emergency handling)
All integrated modules now support:
- Automatic approval requirement detection
- Approval status tracking
- Multi-tenant approval management
- Complete audit trail
- Flexible workflow states
- Module-specific enhancements (prior auth, emergency cases, etc.)
The integration is backward compatible and does not affect existing functionality.