HH/apps/callcenter/models.py
2026-02-25 04:47:05 +03:00

230 lines
8.2 KiB
Python

"""
Call Center models - Call center interaction tracking and ratings
This module implements call center tracking that:
- Records call center interactions
- Tracks agent performance
- Monitors wait times and satisfaction
- Creates PX actions for low ratings
"""
from django.db import models
from apps.core.models import TimeStampedModel, UUIDModel
class CallCenterInteraction(UUIDModel, TimeStampedModel):
"""
Call center interaction - tracks calls with patients.
Low ratings trigger PX action creation.
"""
# Patient information
patient = models.ForeignKey(
'organizations.Patient',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='call_center_interactions'
)
# Caller information (if not a patient)
caller_name = models.CharField(max_length=200, blank=True)
caller_phone = models.CharField(max_length=20, blank=True)
caller_relationship = models.CharField(
max_length=50,
choices=[
('patient', 'Patient'),
('family', 'Family Member'),
('other', 'Other'),
],
default='patient'
)
# Organization
hospital = models.ForeignKey(
'organizations.Hospital',
on_delete=models.CASCADE,
related_name='call_center_interactions'
)
department = models.ForeignKey(
'organizations.Department',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='call_center_interactions'
)
# Agent information
agent = models.ForeignKey(
'accounts.User',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='call_center_interactions'
)
# Call details
call_type = models.CharField(
max_length=50,
choices=[
('inquiry', 'Inquiry'),
('complaint', 'Complaint'),
('appointment', 'Appointment'),
('follow_up', 'Follow-up'),
('feedback', 'Feedback'),
('other', 'Other'),
],
db_index=True
)
subject = models.CharField(max_length=500)
notes = models.TextField(blank=True)
# Metrics
wait_time_seconds = models.IntegerField(
null=True,
blank=True,
help_text="Time caller waited before agent answered"
)
call_duration_seconds = models.IntegerField(
null=True,
blank=True,
help_text="Total call duration"
)
# Rating (1-5 scale)
satisfaction_rating = models.IntegerField(
null=True,
blank=True,
help_text="Caller satisfaction rating (1-5)"
)
is_low_rating = models.BooleanField(
default=False,
db_index=True,
help_text="True if rating below threshold (< 3)"
)
# Resolution
resolved = models.BooleanField(default=False)
resolution_notes = models.TextField(blank=True)
# Timestamps
call_started_at = models.DateTimeField(auto_now_add=True)
call_ended_at = models.DateTimeField(null=True, blank=True)
# Metadata
metadata = models.JSONField(default=dict, blank=True)
class Meta:
ordering = ['-call_started_at']
indexes = [
models.Index(fields=['hospital', '-call_started_at']),
models.Index(fields=['agent', '-call_started_at']),
models.Index(fields=['is_low_rating', '-call_started_at']),
]
def __str__(self):
caller = self.patient.get_full_name() if self.patient else self.caller_name
return f"{caller} - {self.call_type} ({self.call_started_at.strftime('%Y-%m-%d %H:%M')})"
def save(self, *args, **kwargs):
"""Check if rating is low"""
if self.satisfaction_rating and self.satisfaction_rating < 3:
self.is_low_rating = True
super().save(*args, **kwargs)
class CallRecord(UUIDModel, TimeStampedModel):
"""
Call Record - Tracks call center recordings imported from CSV.
Stores all call metadata from the call recording system including:
- Call details (start, end, duration)
- Caller information
- Department and extension
- Recording file information
- Inbound/Outbound call details
"""
# Core identifiers
media_id = models.UUIDField(unique=True, db_index=True, help_text="Unique media ID from recording system")
media_type = models.CharField(max_length=50, default="Calls", help_text="Type of media (e.g., Calls)")
chain = models.CharField(max_length=255, blank=True, help_text="Chain identifier")
evaluated = models.BooleanField(default=False, help_text="Whether the call has been evaluated")
# Call timing
call_start = models.DateTimeField(help_text="Call start time")
call_end = models.DateTimeField(null=True, blank=True, help_text="Call end time")
call_length = models.CharField(max_length=20, blank=True, help_text="Call length as HH:MM:SS")
call_duration_seconds = models.IntegerField(null=True, blank=True, help_text="Call duration in seconds")
# Caller information
first_name = models.CharField(max_length=100, blank=True, help_text="Caller first name")
last_name = models.CharField(max_length=100, blank=True, help_text="Caller last name")
# Department information
extension = models.CharField(max_length=20, blank=True, help_text="Extension number")
department = models.CharField(max_length=255, blank=True, help_text="Department name")
location = models.CharField(max_length=255, blank=True, help_text="Location")
# Inbound call details
inbound_id = models.CharField(max_length=50, blank=True, help_text="Inbound call ID")
inbound_name = models.CharField(max_length=255, blank=True, help_text="Inbound caller name/number")
dnis = models.CharField(max_length=50, blank=True, help_text="Dialed Number Identification Service")
# Outbound call details
outbound_id = models.CharField(max_length=50, blank=True, help_text="Outbound call ID")
outbound_name = models.CharField(max_length=255, blank=True, help_text="Outbound caller name/number")
# Flag information
flag_name = models.CharField(max_length=100, blank=True, help_text="Flag name")
flag_value = models.CharField(max_length=100, blank=True, help_text="Flag value")
# Recording file information
file_location = models.CharField(max_length=500, blank=True, help_text="File system location")
file_name = models.CharField(max_length=500, blank=True, help_text="Recording file name")
file_hash = models.CharField(max_length=64, blank=True, help_text="File hash for integrity")
# Additional metadata
external_ref = models.CharField(max_length=100, blank=True, help_text="External reference number")
transfer_from = models.CharField(max_length=255, blank=True, help_text="Transfer source")
recorded_by = models.CharField(max_length=255, blank=True, help_text="Recording system/user")
time_zone = models.CharField(max_length=50, default="03:00:00", help_text="Time zone offset")
recording_server_name = models.CharField(max_length=100, blank=True, help_text="Recording server name")
# Hospital link (for multi-hospital systems)
hospital = models.ForeignKey(
'organizations.Hospital',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='call_records'
)
class Meta:
ordering = ['-call_start']
indexes = [
models.Index(fields=['-call_start']),
models.Index(fields=['media_id']),
models.Index(fields=['department']),
models.Index(fields=['evaluated']),
models.Index(fields=['hospital', '-call_start']),
]
def __str__(self):
return f"{self.first_name} {self.last_name} - {self.call_start.strftime('%Y-%m-%d %H:%M')}"
@property
def caller_full_name(self):
"""Get full caller name"""
return f"{self.first_name} {self.last_name}".strip()
@property
def is_inbound(self):
"""Check if call is inbound"""
return bool(self.inbound_id or self.inbound_name)
@property
def is_outbound(self):
"""Check if call is outbound"""
return bool(self.outbound_id or self.outbound_name)