776 lines
23 KiB
Python
776 lines
23 KiB
Python
"""
|
|
Insurance Approvals app models for hospital management system.
|
|
Provides universal insurance approval request management for all order types.
|
|
"""
|
|
|
|
import uuid
|
|
from django.db import models
|
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.utils import timezone
|
|
from django.conf import settings
|
|
from datetime import timedelta
|
|
from decimal import Decimal
|
|
|
|
|
|
class InsuranceApprovalRequest(models.Model):
|
|
"""
|
|
Universal insurance approval request for any order type.
|
|
Uses GenericForeignKey for polymorphic relationships.
|
|
"""
|
|
|
|
class RequestType(models.TextChoices):
|
|
LABORATORY = 'LABORATORY', 'Laboratory Test'
|
|
RADIOLOGY = 'RADIOLOGY', 'Radiology/Imaging'
|
|
PHARMACY = 'PHARMACY', 'Medication/Prescription'
|
|
PROCEDURE = 'PROCEDURE', 'Medical Procedure'
|
|
SURGERY = 'SURGERY', 'Surgical Procedure'
|
|
THERAPY = 'THERAPY', 'Therapy Services'
|
|
DME = 'DME', 'Durable Medical Equipment'
|
|
HOME_HEALTH = 'HOME_HEALTH', 'Home Health Services'
|
|
OTHER = 'OTHER', 'Other Services'
|
|
|
|
class ApprovalStatus(models.TextChoices):
|
|
DRAFT = 'DRAFT', 'Draft'
|
|
PENDING_SUBMISSION = 'PENDING_SUBMISSION', 'Pending Submission'
|
|
SUBMITTED = 'SUBMITTED', 'Submitted to Insurance'
|
|
UNDER_REVIEW = 'UNDER_REVIEW', 'Under Review'
|
|
ADDITIONAL_INFO_REQUESTED = 'ADDITIONAL_INFO_REQUESTED', 'Additional Info Requested'
|
|
APPROVED = 'APPROVED', 'Approved'
|
|
PARTIALLY_APPROVED = 'PARTIALLY_APPROVED', 'Partially Approved'
|
|
DENIED = 'DENIED', 'Denied'
|
|
APPEALED = 'APPEALED', 'Appealed'
|
|
APPEAL_APPROVED = 'APPEAL_APPROVED', 'Appeal Approved'
|
|
APPEAL_DENIED = 'APPEAL_DENIED', 'Appeal Denied'
|
|
EXPIRED = 'EXPIRED', 'Expired'
|
|
CANCELLED = 'CANCELLED', 'Cancelled'
|
|
|
|
class Priority(models.TextChoices):
|
|
ROUTINE = 'ROUTINE', 'Routine'
|
|
URGENT = 'URGENT', 'Urgent'
|
|
STAT = 'STAT', 'STAT'
|
|
EMERGENCY = 'EMERGENCY', 'Emergency'
|
|
|
|
class SubmissionMethod(models.TextChoices):
|
|
FAX = 'FAX', 'Fax'
|
|
PHONE = 'PHONE', 'Phone'
|
|
PORTAL = 'PORTAL', 'Insurance Portal'
|
|
EMAIL = 'EMAIL', 'Email'
|
|
MAIL = 'MAIL', 'Mail'
|
|
EDI = 'EDI', 'Electronic Data Interchange'
|
|
|
|
# Tenant
|
|
tenant = models.ForeignKey(
|
|
'core.Tenant',
|
|
on_delete=models.CASCADE,
|
|
related_name='approval_requests',
|
|
help_text='Organization tenant'
|
|
)
|
|
|
|
# Identifiers
|
|
approval_id = models.UUIDField(
|
|
default=uuid.uuid4,
|
|
unique=True,
|
|
editable=False,
|
|
help_text='Unique approval identifier'
|
|
)
|
|
approval_number = models.CharField(
|
|
max_length=30,
|
|
unique=True,
|
|
help_text='Approval request number'
|
|
)
|
|
|
|
# Patient & Insurance
|
|
patient = models.ForeignKey(
|
|
'patients.PatientProfile',
|
|
on_delete=models.CASCADE,
|
|
related_name='approval_requests',
|
|
help_text='Patient'
|
|
)
|
|
insurance_info = models.ForeignKey(
|
|
'patients.InsuranceInfo',
|
|
on_delete=models.CASCADE,
|
|
related_name='approval_requests',
|
|
help_text='Insurance information'
|
|
)
|
|
|
|
# Polymorphic relationship to any order (optional - can create approval before order)
|
|
content_type = models.ForeignKey(
|
|
ContentType,
|
|
on_delete=models.CASCADE,
|
|
null=True,
|
|
blank=True,
|
|
help_text='Type of order (Lab, Radiology, Pharmacy, etc.)'
|
|
)
|
|
object_id = models.PositiveIntegerField(
|
|
null=True,
|
|
blank=True,
|
|
help_text='ID of the related order'
|
|
)
|
|
order = GenericForeignKey('content_type', 'object_id')
|
|
|
|
# Request Details
|
|
request_type = models.CharField(
|
|
max_length=20,
|
|
choices=RequestType.choices,
|
|
help_text='Type of approval request'
|
|
)
|
|
service_description = models.CharField(
|
|
max_length=500,
|
|
help_text='Description of service/procedure'
|
|
)
|
|
|
|
# Medical Codes
|
|
procedure_codes = models.JSONField(
|
|
default=list,
|
|
help_text='CPT/HCPCS procedure codes'
|
|
)
|
|
diagnosis_codes = models.JSONField(
|
|
default=list,
|
|
help_text='ICD-10 diagnosis codes'
|
|
)
|
|
|
|
# Clinical Information
|
|
clinical_justification = models.TextField(
|
|
help_text='Clinical justification for service'
|
|
)
|
|
medical_necessity = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Medical necessity statement'
|
|
)
|
|
alternative_treatments_tried = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Alternative treatments attempted'
|
|
)
|
|
|
|
# Requested Services
|
|
requested_quantity = models.PositiveIntegerField(
|
|
default=1,
|
|
help_text='Quantity requested'
|
|
)
|
|
requested_visits = models.PositiveIntegerField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Number of visits requested'
|
|
)
|
|
requested_units = models.PositiveIntegerField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Number of units requested'
|
|
)
|
|
service_start_date = models.DateField(
|
|
help_text='Requested service start date'
|
|
)
|
|
service_end_date = models.DateField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Requested service end date'
|
|
)
|
|
|
|
# Status & Priority
|
|
status = models.CharField(
|
|
max_length=30,
|
|
choices=ApprovalStatus.choices,
|
|
default=ApprovalStatus.DRAFT,
|
|
help_text='Current approval status'
|
|
)
|
|
priority = models.CharField(
|
|
max_length=20,
|
|
choices=Priority.choices,
|
|
default=Priority.ROUTINE,
|
|
help_text='Request priority'
|
|
)
|
|
|
|
# Submission Details
|
|
submission_method = models.CharField(
|
|
max_length=20,
|
|
choices=SubmissionMethod.choices,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Method used to submit request'
|
|
)
|
|
submitted_date = models.DateTimeField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Date and time submitted to insurance'
|
|
)
|
|
submitted_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='submitted_approvals',
|
|
help_text='User who submitted the request'
|
|
)
|
|
|
|
# Insurance Response
|
|
decision_date = models.DateTimeField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Date insurance made decision'
|
|
)
|
|
authorization_number = models.CharField(
|
|
max_length=100,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Insurance authorization number'
|
|
)
|
|
reference_number = models.CharField(
|
|
max_length=100,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Insurance reference number'
|
|
)
|
|
|
|
# Approved Details
|
|
approved_quantity = models.PositiveIntegerField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Approved quantity'
|
|
)
|
|
approved_visits = models.PositiveIntegerField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Approved number of visits'
|
|
)
|
|
approved_units = models.PositiveIntegerField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Approved number of units'
|
|
)
|
|
approved_amount = models.DecimalField(
|
|
max_digits=12,
|
|
decimal_places=2,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Approved dollar amount'
|
|
)
|
|
|
|
# Validity Period
|
|
effective_date = models.DateField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Authorization effective date'
|
|
)
|
|
expiration_date = models.DateField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Authorization expiration date'
|
|
)
|
|
|
|
# Denial Information
|
|
denial_reason = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Reason for denial'
|
|
)
|
|
denial_code = models.CharField(
|
|
max_length=50,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Insurance denial code'
|
|
)
|
|
|
|
# Appeal Information
|
|
appeal_date = models.DateTimeField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Date appeal was filed'
|
|
)
|
|
appeal_reason = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Reason for appeal'
|
|
)
|
|
appeal_deadline = models.DateField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Deadline to file appeal'
|
|
)
|
|
|
|
# Assignment & Tracking
|
|
assigned_to = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='assigned_approvals',
|
|
help_text='Staff member assigned to this request'
|
|
)
|
|
requesting_provider = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.CASCADE,
|
|
related_name='requested_approvals',
|
|
help_text='Provider requesting the approval'
|
|
)
|
|
|
|
# Communication Log
|
|
last_contact_date = models.DateTimeField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Last contact with insurance'
|
|
)
|
|
last_contact_method = models.CharField(
|
|
max_length=20,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Method of last contact'
|
|
)
|
|
last_contact_notes = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Notes from last contact'
|
|
)
|
|
|
|
# Flags
|
|
is_urgent = models.BooleanField(
|
|
default=False,
|
|
help_text='Urgent request'
|
|
)
|
|
is_expedited = models.BooleanField(
|
|
default=False,
|
|
help_text='Expedited processing requested'
|
|
)
|
|
requires_peer_review = models.BooleanField(
|
|
default=False,
|
|
help_text='Requires peer-to-peer review'
|
|
)
|
|
|
|
# Notes
|
|
internal_notes = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Internal staff notes'
|
|
)
|
|
insurance_notes = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Notes from insurance company'
|
|
)
|
|
|
|
# Metadata
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
created_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='created_approvals',
|
|
help_text='User who created the request'
|
|
)
|
|
|
|
class Meta:
|
|
db_table = 'insurance_approvals_request'
|
|
verbose_name = 'Insurance Approval Request'
|
|
verbose_name_plural = 'Insurance Approval Requests'
|
|
ordering = ['-created_at']
|
|
indexes = [
|
|
models.Index(fields=['tenant', 'status']),
|
|
models.Index(fields=['patient', 'status']),
|
|
models.Index(fields=['insurance_info', 'status']),
|
|
models.Index(fields=['approval_number']),
|
|
models.Index(fields=['authorization_number']),
|
|
models.Index(fields=['expiration_date']),
|
|
models.Index(fields=['assigned_to', 'status']),
|
|
models.Index(fields=['content_type', 'object_id']),
|
|
models.Index(fields=['priority', 'status']),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.approval_number} - {self.patient.get_full_name()} - {self.get_request_type_display()}"
|
|
|
|
def save(self, *args, **kwargs):
|
|
"""Generate approval number if not provided."""
|
|
if not self.approval_number:
|
|
today = timezone.now().date()
|
|
last_approval = InsuranceApprovalRequest.objects.filter(
|
|
tenant=self.tenant,
|
|
created_at__date=today
|
|
).order_by('-id').first()
|
|
|
|
if last_approval:
|
|
last_num = int(last_approval.approval_number.split('-')[-1])
|
|
self.approval_number = f"AUTH-{today.strftime('%Y%m%d')}-{last_num + 1:04d}"
|
|
else:
|
|
self.approval_number = f"AUTH-{today.strftime('%Y%m%d')}-0001"
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
@property
|
|
def is_approved(self):
|
|
"""Check if request is approved."""
|
|
return self.status in ['APPROVED', 'PARTIALLY_APPROVED', 'APPEAL_APPROVED']
|
|
|
|
@property
|
|
def is_denied(self):
|
|
"""Check if request is denied."""
|
|
return self.status in ['DENIED', 'APPEAL_DENIED']
|
|
|
|
@property
|
|
def is_expired(self):
|
|
"""Check if authorization is expired."""
|
|
if self.expiration_date:
|
|
return timezone.now().date() > self.expiration_date
|
|
return False
|
|
|
|
@property
|
|
def days_until_expiry(self):
|
|
"""Calculate days until expiration."""
|
|
if self.expiration_date:
|
|
return (self.expiration_date - timezone.now().date()).days
|
|
return None
|
|
|
|
@property
|
|
def is_expiring_soon(self):
|
|
"""Check if expiring within 30 days."""
|
|
days = self.days_until_expiry
|
|
return days is not None and 0 < days <= 30
|
|
|
|
@property
|
|
def can_appeal(self):
|
|
"""Check if request can be appealed."""
|
|
if not self.is_denied:
|
|
return False
|
|
if not self.appeal_deadline:
|
|
return True
|
|
return timezone.now().date() <= self.appeal_deadline
|
|
|
|
@property
|
|
def turnaround_time_days(self):
|
|
"""Calculate turnaround time in days."""
|
|
if self.submitted_date and self.decision_date:
|
|
return (self.decision_date - self.submitted_date).days
|
|
return None
|
|
|
|
|
|
class ApprovalDocument(models.Model):
|
|
"""Supporting documents for approval requests."""
|
|
|
|
class DocumentType(models.TextChoices):
|
|
MEDICAL_RECORDS = 'MEDICAL_RECORDS', 'Medical Records'
|
|
LAB_RESULTS = 'LAB_RESULTS', 'Lab Results'
|
|
IMAGING_REPORTS = 'IMAGING_REPORTS', 'Imaging Reports'
|
|
CLINICAL_NOTES = 'CLINICAL_NOTES', 'Clinical Notes'
|
|
PRESCRIPTION = 'PRESCRIPTION', 'Prescription'
|
|
LETTER_OF_MEDICAL_NECESSITY = 'LETTER_OF_MEDICAL_NECESSITY', 'Letter of Medical Necessity'
|
|
PRIOR_AUTH_FORM = 'PRIOR_AUTH_FORM', 'Prior Authorization Form'
|
|
INSURANCE_CARD = 'INSURANCE_CARD', 'Insurance Card'
|
|
CONSENT_FORM = 'CONSENT_FORM', 'Consent Form'
|
|
APPEAL_LETTER = 'APPEAL_LETTER', 'Appeal Letter'
|
|
PEER_REVIEW = 'PEER_REVIEW', 'Peer Review Documentation'
|
|
OTHER = 'OTHER', 'Other'
|
|
|
|
approval_request = models.ForeignKey(
|
|
InsuranceApprovalRequest,
|
|
on_delete=models.CASCADE,
|
|
related_name='documents',
|
|
help_text='Related approval request'
|
|
)
|
|
|
|
document_id = models.UUIDField(
|
|
default=uuid.uuid4,
|
|
unique=True,
|
|
editable=False,
|
|
help_text='Unique document identifier'
|
|
)
|
|
document_type = models.CharField(
|
|
max_length=30,
|
|
choices=DocumentType.choices,
|
|
help_text='Type of document'
|
|
)
|
|
title = models.CharField(
|
|
max_length=200,
|
|
help_text='Document title'
|
|
)
|
|
description = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Document description'
|
|
)
|
|
|
|
file = models.FileField(
|
|
upload_to='approval_documents/%Y/%m/',
|
|
help_text='Document file'
|
|
)
|
|
file_size = models.PositiveIntegerField(
|
|
help_text='File size in bytes'
|
|
)
|
|
mime_type = models.CharField(
|
|
max_length=100,
|
|
help_text='MIME type'
|
|
)
|
|
|
|
uploaded_at = models.DateTimeField(auto_now_add=True)
|
|
uploaded_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='uploaded_approval_documents',
|
|
help_text='User who uploaded the document'
|
|
)
|
|
|
|
class Meta:
|
|
db_table = 'insurance_approvals_document'
|
|
verbose_name = 'Approval Document'
|
|
verbose_name_plural = 'Approval Documents'
|
|
ordering = ['-uploaded_at']
|
|
indexes = [
|
|
models.Index(fields=['approval_request', 'document_type']),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.title} - {self.approval_request.approval_number}"
|
|
|
|
@property
|
|
def file_size_mb(self):
|
|
"""Get file size in MB."""
|
|
return round(self.file_size / (1024 * 1024), 2)
|
|
|
|
|
|
class ApprovalStatusHistory(models.Model):
|
|
"""Audit trail for approval status changes."""
|
|
|
|
approval_request = models.ForeignKey(
|
|
InsuranceApprovalRequest,
|
|
on_delete=models.CASCADE,
|
|
related_name='status_history',
|
|
help_text='Related approval request'
|
|
)
|
|
|
|
from_status = models.CharField(
|
|
max_length=30,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Previous status'
|
|
)
|
|
to_status = models.CharField(
|
|
max_length=30,
|
|
help_text='New status'
|
|
)
|
|
|
|
reason = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Reason for status change'
|
|
)
|
|
notes = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Additional notes'
|
|
)
|
|
|
|
changed_at = models.DateTimeField(auto_now_add=True)
|
|
changed_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='approval_status_changes',
|
|
help_text='User who made the change'
|
|
)
|
|
|
|
class Meta:
|
|
db_table = 'insurance_approvals_status_history'
|
|
verbose_name = 'Approval Status History'
|
|
verbose_name_plural = 'Approval Status Histories'
|
|
ordering = ['-changed_at']
|
|
indexes = [
|
|
models.Index(fields=['approval_request', 'changed_at']),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.approval_request.approval_number}: {self.from_status} → {self.to_status}"
|
|
|
|
|
|
class ApprovalCommunicationLog(models.Model):
|
|
"""Log of all communications with insurance company."""
|
|
|
|
class CommunicationType(models.TextChoices):
|
|
PHONE_CALL = 'PHONE_CALL', 'Phone Call'
|
|
FAX_SENT = 'FAX_SENT', 'Fax Sent'
|
|
FAX_RECEIVED = 'FAX_RECEIVED', 'Fax Received'
|
|
EMAIL_SENT = 'EMAIL_SENT', 'Email Sent'
|
|
EMAIL_RECEIVED = 'EMAIL_RECEIVED', 'Email Received'
|
|
PORTAL_MESSAGE = 'PORTAL_MESSAGE', 'Portal Message'
|
|
MAIL_SENT = 'MAIL_SENT', 'Mail Sent'
|
|
MAIL_RECEIVED = 'MAIL_RECEIVED', 'Mail Received'
|
|
IN_PERSON = 'IN_PERSON', 'In Person'
|
|
|
|
approval_request = models.ForeignKey(
|
|
InsuranceApprovalRequest,
|
|
on_delete=models.CASCADE,
|
|
related_name='communications',
|
|
help_text='Related approval request'
|
|
)
|
|
|
|
communication_id = models.UUIDField(
|
|
default=uuid.uuid4,
|
|
unique=True,
|
|
editable=False,
|
|
help_text='Unique communication identifier'
|
|
)
|
|
communication_type = models.CharField(
|
|
max_length=20,
|
|
choices=CommunicationType.choices,
|
|
help_text='Type of communication'
|
|
)
|
|
|
|
contact_person = models.CharField(
|
|
max_length=200,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Insurance contact person'
|
|
)
|
|
contact_number = models.CharField(
|
|
max_length=50,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Contact phone/fax number'
|
|
)
|
|
|
|
subject = models.CharField(
|
|
max_length=200,
|
|
help_text='Communication subject'
|
|
)
|
|
message = models.TextField(
|
|
help_text='Message content'
|
|
)
|
|
response = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Response received'
|
|
)
|
|
|
|
outcome = models.CharField(
|
|
max_length=200,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Communication outcome'
|
|
)
|
|
follow_up_required = models.BooleanField(
|
|
default=False,
|
|
help_text='Follow-up required'
|
|
)
|
|
follow_up_date = models.DateField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Follow-up date'
|
|
)
|
|
|
|
communicated_at = models.DateTimeField(auto_now_add=True)
|
|
communicated_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='approval_communications',
|
|
help_text='User who made the communication'
|
|
)
|
|
|
|
class Meta:
|
|
db_table = 'insurance_approvals_communication_log'
|
|
verbose_name = 'Approval Communication Log'
|
|
verbose_name_plural = 'Approval Communication Logs'
|
|
ordering = ['-communicated_at']
|
|
indexes = [
|
|
models.Index(fields=['approval_request', 'communicated_at']),
|
|
models.Index(fields=['follow_up_required', 'follow_up_date']),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f"{self.approval_request.approval_number} - {self.get_communication_type_display()} - {self.communicated_at.date()}"
|
|
|
|
|
|
class ApprovalTemplate(models.Model):
|
|
"""Templates for common approval requests."""
|
|
|
|
tenant = models.ForeignKey(
|
|
'core.Tenant',
|
|
on_delete=models.CASCADE,
|
|
related_name='approval_templates',
|
|
help_text='Organization tenant'
|
|
)
|
|
|
|
template_id = models.UUIDField(
|
|
default=uuid.uuid4,
|
|
unique=True,
|
|
editable=False,
|
|
help_text='Unique template identifier'
|
|
)
|
|
name = models.CharField(
|
|
max_length=200,
|
|
help_text='Template name'
|
|
)
|
|
description = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Template description'
|
|
)
|
|
|
|
request_type = models.CharField(
|
|
max_length=20,
|
|
help_text='Type of request this template is for'
|
|
)
|
|
insurance_company = models.CharField(
|
|
max_length=200,
|
|
blank=True,
|
|
null=True,
|
|
help_text='Specific insurance company (optional)'
|
|
)
|
|
|
|
# Template content
|
|
clinical_justification_template = models.TextField(
|
|
help_text='Template for clinical justification'
|
|
)
|
|
medical_necessity_template = models.TextField(
|
|
blank=True,
|
|
null=True,
|
|
help_text='Template for medical necessity statement'
|
|
)
|
|
required_documents = models.JSONField(
|
|
default=list,
|
|
help_text='List of required document types'
|
|
)
|
|
required_codes = models.JSONField(
|
|
default=dict,
|
|
help_text='Required procedure/diagnosis codes'
|
|
)
|
|
|
|
is_active = models.BooleanField(
|
|
default=True,
|
|
help_text='Template is active'
|
|
)
|
|
usage_count = models.PositiveIntegerField(
|
|
default=0,
|
|
help_text='Number of times template has been used'
|
|
)
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
created_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='created_approval_templates',
|
|
help_text='User who created the template'
|
|
)
|
|
|
|
class Meta:
|
|
db_table = 'insurance_approvals_template'
|
|
verbose_name = 'Approval Template'
|
|
verbose_name_plural = 'Approval Templates'
|
|
ordering = ['name']
|
|
indexes = [
|
|
models.Index(fields=['tenant', 'is_active']),
|
|
models.Index(fields=['request_type']),
|
|
]
|
|
unique_together = ['tenant', 'name']
|
|
|
|
def __str__(self):
|
|
return f"{self.name} ({self.request_type})"
|