589 lines
19 KiB
Markdown
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.
|