461 lines
12 KiB
Markdown
461 lines
12 KiB
Markdown
# Insurance Approval Integration - Quick Reference Card
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### Check if Order Needs Approval
|
|
```python
|
|
if order.requires_approval():
|
|
# Create approval request
|
|
```
|
|
|
|
### Get Approval Status
|
|
```python
|
|
status = order.approval_status
|
|
# Returns: 'APPROVED', 'APPROVAL_REQUIRED', 'NO_INSURANCE', etc.
|
|
```
|
|
|
|
### Check if Has Valid Approval
|
|
```python
|
|
if order.has_valid_approval():
|
|
# Proceed with order
|
|
```
|
|
|
|
### Get Active Approval
|
|
```python
|
|
approval = order.get_active_approval()
|
|
if approval:
|
|
print(f"Auth #: {approval.authorization_number}")
|
|
```
|
|
|
|
---
|
|
|
|
## 📦 Integrated Models
|
|
|
|
| Module | Model | Request Type |
|
|
|--------|-------|--------------|
|
|
| Laboratory | `LabOrder` | `LABORATORY` |
|
|
| Radiology | `ImagingOrder` | `RADIOLOGY` |
|
|
| Pharmacy | `Prescription` | `PHARMACY` |
|
|
| Operating Theatre | `SurgicalCase` | `SURGERY` |
|
|
|
|
---
|
|
|
|
## 🔧 Helper Methods (All Models)
|
|
|
|
### `requires_approval()` → bool
|
|
Returns `True` if order requires insurance approval
|
|
|
|
```python
|
|
if lab_order.requires_approval():
|
|
# Patient has insurance but no valid approval
|
|
```
|
|
|
|
### `has_valid_approval()` → bool
|
|
Returns `True` if order has a valid, non-expired approval
|
|
|
|
```python
|
|
if imaging_order.has_valid_approval():
|
|
# Can proceed with imaging
|
|
```
|
|
|
|
### `get_active_approval()` → InsuranceApprovalRequest | None
|
|
Returns the active approval or None
|
|
|
|
```python
|
|
approval = prescription.get_active_approval()
|
|
if approval:
|
|
auth_number = approval.authorization_number
|
|
```
|
|
|
|
### `approval_status` → str (property)
|
|
Returns current approval status as string
|
|
|
|
```python
|
|
status = surgical_case.approval_status
|
|
# 'APPROVED', 'APPROVAL_REQUIRED', 'NO_INSURANCE', etc.
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 Creating Approval Requests
|
|
|
|
### Laboratory Order
|
|
```python
|
|
from insurance_approvals.models import InsuranceApprovalRequest
|
|
|
|
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,
|
|
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(),
|
|
priority='ROUTINE',
|
|
status='PENDING_SUBMISSION',
|
|
)
|
|
```
|
|
|
|
### Radiology Order
|
|
```python
|
|
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,
|
|
service_description=imaging_order.study_description,
|
|
procedure_codes=imaging_order.modality,
|
|
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(),
|
|
priority='URGENT' if imaging_order.is_stat else 'ROUTINE',
|
|
status='PENDING_SUBMISSION',
|
|
)
|
|
```
|
|
|
|
### Pharmacy Prescription
|
|
```python
|
|
approval = InsuranceApprovalRequest.objects.create(
|
|
tenant=prescription.tenant,
|
|
patient=prescription.patient,
|
|
insurance_info=prescription.patient.insurance_info.first(),
|
|
request_type='PHARMACY',
|
|
content_object=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',
|
|
requested_quantity=prescription.quantity_prescribed,
|
|
status='PENDING_SUBMISSION',
|
|
)
|
|
```
|
|
|
|
### Surgical Case
|
|
```python
|
|
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,
|
|
service_description=surgical_case.primary_procedure,
|
|
procedure_codes=', '.join(surgical_case.procedure_codes),
|
|
diagnosis_codes=', '.join(surgical_case.diagnosis_codes),
|
|
clinical_justification=surgical_case.clinical_notes,
|
|
requesting_provider=surgical_case.primary_surgeon,
|
|
service_start_date=surgical_case.scheduled_start.date(),
|
|
priority='STAT' if surgical_case.is_emergency else 'ROUTINE',
|
|
is_expedited=surgical_case.is_emergency,
|
|
status='PENDING_SUBMISSION',
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 🎨 Template Examples
|
|
|
|
### Display Approval Status Badge
|
|
```django
|
|
{% if order.approval_status == 'APPROVED' %}
|
|
<span class="badge bg-success">
|
|
<i class="fa fa-check"></i> Approved
|
|
</span>
|
|
{% elif order.approval_status == 'APPROVAL_REQUIRED' %}
|
|
<span class="badge bg-warning">
|
|
<i class="fa fa-exclamation-triangle"></i> Approval Required
|
|
</span>
|
|
{% elif order.approval_status == 'NO_INSURANCE' %}
|
|
<span class="badge bg-secondary">No Insurance</span>
|
|
{% else %}
|
|
<span class="badge bg-info">{{ order.approval_status }}</span>
|
|
{% endif %}
|
|
```
|
|
|
|
### Show Approval Details
|
|
```django
|
|
{% if order.has_valid_approval %}
|
|
{% with approval=order.get_active_approval %}
|
|
<div class="alert alert-success">
|
|
<strong>Authorization:</strong> {{ approval.authorization_number }}<br>
|
|
<strong>Expires:</strong> {{ approval.expiration_date|date:"M d, Y" }}<br>
|
|
<strong>Approved Quantity:</strong> {{ approval.approved_quantity }}
|
|
</div>
|
|
{% endwith %}
|
|
{% endif %}
|
|
```
|
|
|
|
### Request Approval Button
|
|
```django
|
|
{% if order.requires_approval %}
|
|
<a href="{% url 'insurance_approvals:create' %}?order_id={{ order.id }}"
|
|
class="btn btn-primary">
|
|
<i class="fa fa-file-medical"></i> Request Approval
|
|
</a>
|
|
{% endif %}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Approval Status Values
|
|
|
|
| Status | Meaning |
|
|
|--------|---------|
|
|
| `NO_INSURANCE` | Patient has no insurance |
|
|
| `APPROVAL_REQUIRED` | Needs approval but none exists |
|
|
| `APPROVED` | Has valid, active approval |
|
|
| `PENDING_SUBMISSION` | Request created but not submitted |
|
|
| `SUBMITTED` | Request submitted to insurance |
|
|
| `UNDER_REVIEW` | Being reviewed by insurance |
|
|
| `MORE_INFO_REQUIRED` | Insurance needs more information |
|
|
| `PARTIALLY_APPROVED` | Partially approved |
|
|
| `DENIED` | Approval denied |
|
|
| `EXPIRED` | Approval has expired |
|
|
| `PRIOR_AUTH_REQUIRED` | Prior authorization required (Pharmacy) |
|
|
| `PRIOR_AUTH_APPROVED` | Prior authorization approved (Pharmacy) |
|
|
| `PRIOR_AUTH_EXPIRED` | Prior authorization expired (Pharmacy) |
|
|
| `EMERGENCY_APPROVAL_REQUIRED` | Emergency approval needed (Surgery) |
|
|
|
|
---
|
|
|
|
## 🔍 Querying Approvals
|
|
|
|
### Get All Approvals for an Order
|
|
```python
|
|
approvals = order.approval_requests.all()
|
|
```
|
|
|
|
### Get Active Approvals
|
|
```python
|
|
from django.utils import timezone
|
|
|
|
active_approvals = order.approval_requests.filter(
|
|
status__in=['APPROVED', 'PARTIALLY_APPROVED'],
|
|
expiration_date__gte=timezone.now().date()
|
|
)
|
|
```
|
|
|
|
### Get Latest Approval
|
|
```python
|
|
latest = order.approval_requests.order_by('-created_at').first()
|
|
```
|
|
|
|
### Get Approvals by Status
|
|
```python
|
|
pending = order.approval_requests.filter(status='PENDING_SUBMISSION')
|
|
approved = order.approval_requests.filter(status='APPROVED')
|
|
denied = order.approval_requests.filter(status='DENIED')
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 Reverse Queries
|
|
|
|
### Get Order from Approval
|
|
```python
|
|
approval = InsuranceApprovalRequest.objects.get(pk=1)
|
|
order = approval.content_object # Returns LabOrder, ImagingOrder, etc.
|
|
```
|
|
|
|
### Get All Lab Orders with Approvals
|
|
```python
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from laboratory.models import LabOrder
|
|
|
|
lab_order_ct = ContentType.objects.get_for_model(LabOrder)
|
|
approvals = InsuranceApprovalRequest.objects.filter(
|
|
content_type=lab_order_ct
|
|
)
|
|
```
|
|
|
|
### Filter Orders by Approval Status
|
|
```python
|
|
# Orders needing approval
|
|
orders_needing_approval = [
|
|
order for order in LabOrder.objects.all()
|
|
if order.requires_approval()
|
|
]
|
|
|
|
# Orders with valid approval
|
|
orders_with_approval = [
|
|
order for order in LabOrder.objects.all()
|
|
if order.has_valid_approval()
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## ⚡ Performance Tips
|
|
|
|
### Use select_related and prefetch_related
|
|
```python
|
|
orders = LabOrder.objects.select_related(
|
|
'patient',
|
|
'patient__insurance_info'
|
|
).prefetch_related(
|
|
'approval_requests'
|
|
)
|
|
```
|
|
|
|
### Bulk Check Approval Status
|
|
```python
|
|
from django.db.models import Prefetch
|
|
|
|
orders = LabOrder.objects.prefetch_related(
|
|
Prefetch(
|
|
'approval_requests',
|
|
queryset=InsuranceApprovalRequest.objects.filter(
|
|
status__in=['APPROVED', 'PARTIALLY_APPROVED']
|
|
)
|
|
)
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Common Patterns
|
|
|
|
### Pattern 1: Create Order with Approval Check
|
|
```python
|
|
def create_order_with_approval(patient, **order_data):
|
|
order = LabOrder.objects.create(patient=patient, **order_data)
|
|
|
|
if order.requires_approval():
|
|
return {
|
|
'order': order,
|
|
'needs_approval': True,
|
|
'redirect': f'/insurance-approvals/create/?order_id={order.id}'
|
|
}
|
|
|
|
return {'order': order, 'needs_approval': False}
|
|
```
|
|
|
|
### Pattern 2: Validate Before Processing
|
|
```python
|
|
def process_order(order):
|
|
if order.requires_approval() and not order.has_valid_approval():
|
|
raise ValidationError("Order requires valid insurance approval")
|
|
|
|
# Process order...
|
|
```
|
|
|
|
### Pattern 3: Auto-Create Approval Request
|
|
```python
|
|
def auto_request_approval(order):
|
|
if not order.requires_approval():
|
|
return None
|
|
|
|
return InsuranceApprovalRequest.objects.create(
|
|
tenant=order.tenant,
|
|
patient=order.patient,
|
|
insurance_info=order.patient.insurance_info.first(),
|
|
request_type='LABORATORY',
|
|
content_object=order,
|
|
# ... other fields
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 🚨 Error Handling
|
|
|
|
### Check for Insurance
|
|
```python
|
|
if not order.patient.insurance_info.exists():
|
|
# No insurance - no approval needed
|
|
pass
|
|
```
|
|
|
|
### Handle Missing Approval
|
|
```python
|
|
try:
|
|
approval = order.get_active_approval()
|
|
if not approval:
|
|
# Create new approval request
|
|
approval = create_approval_request(order)
|
|
except Exception as e:
|
|
logger.error(f"Error getting approval: {e}")
|
|
```
|
|
|
|
### Validate Expiration
|
|
```python
|
|
from django.utils import timezone
|
|
|
|
approval = order.get_active_approval()
|
|
if approval and approval.expiration_date < timezone.now().date():
|
|
# Approval expired - need new one
|
|
pass
|
|
```
|
|
|
|
---
|
|
|
|
## 📱 API/DRF Integration
|
|
|
|
### Serializer with Approval Status
|
|
```python
|
|
from rest_framework import serializers
|
|
|
|
class LabOrderSerializer(serializers.ModelSerializer):
|
|
approval_status = serializers.CharField(read_only=True)
|
|
requires_approval = serializers.SerializerMethodField()
|
|
active_approval = serializers.SerializerMethodField()
|
|
|
|
def get_requires_approval(self, obj):
|
|
return obj.requires_approval()
|
|
|
|
def get_active_approval(self, obj):
|
|
approval = obj.get_active_approval()
|
|
return {
|
|
'id': approval.id,
|
|
'authorization_number': approval.authorization_number,
|
|
'expiration_date': approval.expiration_date
|
|
} if approval else None
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Related Documentation
|
|
|
|
- **Full Integration Guide:** `INSURANCE_APPROVAL_INTEGRATION.md`
|
|
- **Migration Guide:** `INSURANCE_APPROVAL_MIGRATION_GUIDE.md`
|
|
- **Module README:** `insurance_approvals/README.md`
|
|
|
|
---
|
|
|
|
## 💡 Tips
|
|
|
|
1. **Always check `requires_approval()` before processing orders**
|
|
2. **Use `has_valid_approval()` to verify approval is still valid**
|
|
3. **Prefetch approval_requests for better performance**
|
|
4. **Handle emergency cases differently (Surgery module)**
|
|
5. **Check formulary status for medications (Pharmacy module)**
|
|
6. **Use approval templates for consistency**
|
|
7. **Track all status changes with ApprovalStatusHistory**
|
|
8. **Log communications with insurance companies**
|
|
|
|
---
|
|
|
|
## 🎉 Quick Checklist
|
|
|
|
- [ ] Order created
|
|
- [ ] Check if approval required
|
|
- [ ] Create approval request if needed
|
|
- [ ] Submit to insurance
|
|
- [ ] Track status changes
|
|
- [ ] Update when approved
|
|
- [ ] Verify before processing
|
|
- [ ] Handle expiration
|
|
|
|
---
|
|
|
|
**Last Updated:** 2025-01-03
|
|
**Version:** 1.0
|