283 lines
11 KiB
Python
283 lines
11 KiB
Python
"""
|
|
Survey Delivery Service - Sends surveys to patients via SMS/Email
|
|
|
|
This service handles:
|
|
- Generating secure survey URLs
|
|
- Sending SMS with survey links
|
|
- Sending emails with survey links
|
|
- Tracking delivery status
|
|
|
|
Uses NotificationService for all delivery operations.
|
|
"""
|
|
from django.conf import settings
|
|
from django.utils import timezone
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SurveyDeliveryService:
|
|
"""Service for delivering surveys to patients"""
|
|
|
|
@staticmethod
|
|
def generate_survey_url(survey_instance) -> str:
|
|
"""
|
|
Generate secure survey URL with access token.
|
|
|
|
Args:
|
|
survey_instance: SurveyInstance object
|
|
|
|
Returns:
|
|
Full survey URL
|
|
"""
|
|
base_url = getattr(settings, 'SURVEY_BASE_URL', 'http://localhost:8000')
|
|
survey_path = survey_instance.get_survey_url()
|
|
return f"{base_url}{survey_path}"
|
|
|
|
@staticmethod
|
|
def generate_sms_message(recipient_name: str, survey_url: str, hospital_name: str = None, is_staff: bool = False) -> str:
|
|
"""
|
|
Generate SMS message with survey link.
|
|
|
|
Args:
|
|
recipient_name: Recipient's first name (patient or staff)
|
|
survey_url: Survey link
|
|
hospital_name: Optional hospital name
|
|
is_staff: Whether recipient is staff member
|
|
|
|
Returns:
|
|
SMS message text
|
|
"""
|
|
message = f"Dear {recipient_name},\n\n"
|
|
|
|
if hospital_name:
|
|
message += f"Thank you for being part of {hospital_name}. "
|
|
|
|
if is_staff:
|
|
message += "We value your feedback! Please take a moment to complete our staff experience survey:\n\n"
|
|
else:
|
|
message += "We value your feedback! Please take a moment to complete our patient experience survey:\n\n"
|
|
|
|
message += f"{survey_url}\n\n"
|
|
message += "This survey will take approximately 2-3 minutes.\n"
|
|
message += "Thank you for helping us improve our services!"
|
|
|
|
return message
|
|
|
|
@staticmethod
|
|
def generate_email_message(recipient_name: str, survey_url: str, hospital_name: str = None, is_staff: bool = False) -> str:
|
|
"""
|
|
Generate email message with survey link.
|
|
|
|
Args:
|
|
recipient_name: Recipient's first name (patient or staff)
|
|
survey_url: Survey link
|
|
hospital_name: Optional hospital name
|
|
is_staff: Whether recipient is staff member
|
|
|
|
Returns:
|
|
Email message text
|
|
"""
|
|
message = f"Dear {recipient_name},\n\n"
|
|
|
|
if hospital_name:
|
|
message += f"Thank you for being part of {hospital_name}.\n\n"
|
|
else:
|
|
message += "Thank you for being part of our hospital.\n\n"
|
|
|
|
if is_staff:
|
|
message += "We value your feedback and would appreciate it if you could take a moment to complete our staff experience survey.\n\n"
|
|
message += "Your feedback helps us improve our services and create a better work environment.\n\n"
|
|
else:
|
|
message += "We value your feedback and would appreciate it if you could take a moment to complete our patient experience survey.\n\n"
|
|
message += "Your feedback helps us improve our services and provide better care for all our patients.\n\n"
|
|
|
|
message += f"Survey Link: {survey_url}\n\n"
|
|
message += "This survey will take approximately 2-3 minutes to complete.\n\n"
|
|
message += "If you have any questions or concerns, please don't hesitate to contact us.\n\n"
|
|
message += "Thank you for helping us improve our services!\n\n"
|
|
|
|
if is_staff:
|
|
message += "Best regards,\n"
|
|
message += "Hospital Administration Team"
|
|
else:
|
|
message += "Best regards,\n"
|
|
message += "Patient Experience Team"
|
|
|
|
return message
|
|
|
|
@staticmethod
|
|
def send_survey_sms(survey_instance) -> bool:
|
|
"""
|
|
Send survey via SMS using NotificationService API.
|
|
|
|
Args:
|
|
survey_instance: SurveyInstance object
|
|
|
|
Returns:
|
|
True if sent successfully, False otherwise
|
|
"""
|
|
if not survey_instance.recipient_phone:
|
|
logger.warning(f"No phone number for survey {survey_instance.id}")
|
|
return False
|
|
|
|
try:
|
|
# Generate survey URL and message
|
|
survey_url = SurveyDeliveryService.generate_survey_url(survey_instance)
|
|
recipient_name = survey_instance.get_recipient_name().split()[0] # First name only
|
|
is_staff = survey_instance.staff is not None
|
|
hospital_name = survey_instance.hospital.name
|
|
message = SurveyDeliveryService.generate_sms_message(
|
|
recipient_name, survey_url, hospital_name, is_staff
|
|
)
|
|
|
|
# Use NotificationService for delivery (supports API backend)
|
|
from apps.notifications.services import NotificationService
|
|
|
|
# Build metadata
|
|
metadata = {
|
|
'survey_id': str(survey_instance.id),
|
|
'hospital_id': str(survey_instance.hospital.id),
|
|
'is_staff_survey': is_staff
|
|
}
|
|
|
|
if survey_instance.patient:
|
|
metadata['patient_id'] = str(survey_instance.patient.id)
|
|
if survey_instance.staff:
|
|
metadata['staff_id'] = str(survey_instance.staff.id)
|
|
|
|
notification_log = NotificationService.send_sms_via_api(
|
|
message=message,
|
|
phone=survey_instance.recipient_phone,
|
|
related_object=survey_instance,
|
|
metadata=metadata
|
|
)
|
|
|
|
# Update survey instance based on notification status
|
|
if notification_log and notification_log.status == 'sent':
|
|
from apps.surveys.models import SurveyStatus
|
|
survey_instance.status = SurveyStatus.SENT
|
|
survey_instance.sent_at = notification_log.sent_at
|
|
survey_instance.save(update_fields=['status', 'sent_at'])
|
|
logger.info(f"Survey SMS sent successfully to {survey_instance.recipient_phone}")
|
|
return True
|
|
else:
|
|
logger.warning(f"Survey SMS delivery failed for {survey_instance.id}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error sending SMS for survey {survey_instance.id}: {str(e)}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def send_survey_email(survey_instance) -> bool:
|
|
"""
|
|
Send survey via Email using NotificationService API.
|
|
|
|
Args:
|
|
survey_instance: SurveyInstance object
|
|
|
|
Returns:
|
|
True if sent successfully, False otherwise
|
|
"""
|
|
if not survey_instance.recipient_email:
|
|
logger.warning(f"No email address for survey {survey_instance.id}")
|
|
return False
|
|
|
|
try:
|
|
# Generate survey URL and message
|
|
survey_url = SurveyDeliveryService.generate_survey_url(survey_instance)
|
|
recipient_name = survey_instance.get_recipient_name().split()[0] # First name only
|
|
is_staff = survey_instance.staff is not None
|
|
hospital_name = survey_instance.hospital.name
|
|
message = SurveyDeliveryService.generate_email_message(
|
|
recipient_name, survey_url, hospital_name, is_staff
|
|
)
|
|
|
|
# Use NotificationService for delivery (supports API backend)
|
|
from apps.notifications.services import NotificationService
|
|
|
|
# Build metadata
|
|
metadata = {
|
|
'survey_id': str(survey_instance.id),
|
|
'hospital_id': str(survey_instance.hospital.id),
|
|
'is_staff_survey': is_staff
|
|
}
|
|
|
|
if survey_instance.patient:
|
|
metadata['patient_id'] = str(survey_instance.patient.id)
|
|
if survey_instance.staff:
|
|
metadata['staff_id'] = str(survey_instance.staff.id)
|
|
|
|
# Set email subject
|
|
if is_staff:
|
|
subject = f'Staff Experience Survey - {survey_instance.hospital.name}'
|
|
else:
|
|
subject = f'Patient Experience Survey - {survey_instance.hospital.name}'
|
|
|
|
notification_log = NotificationService.send_email_via_api(
|
|
message=message,
|
|
email=survey_instance.recipient_email,
|
|
subject=subject,
|
|
html_message=None, # Plain text for now
|
|
related_object=survey_instance,
|
|
metadata=metadata
|
|
)
|
|
|
|
# Update survey instance based on notification status
|
|
if notification_log and notification_log.status == 'sent':
|
|
from apps.surveys.models import SurveyStatus
|
|
survey_instance.status = SurveyStatus.SENT
|
|
survey_instance.sent_at = notification_log.sent_at
|
|
survey_instance.save(update_fields=['status', 'sent_at'])
|
|
logger.info(f"Survey email sent successfully to {survey_instance.recipient_email}")
|
|
return True
|
|
else:
|
|
logger.warning(f"Survey email delivery failed for {survey_instance.id}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error sending email for survey {survey_instance.id}: {str(e)}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def deliver_survey(survey_instance) -> bool:
|
|
"""
|
|
Deliver survey based on configured delivery channel.
|
|
|
|
Args:
|
|
survey_instance: SurveyInstance object
|
|
|
|
Returns:
|
|
True if delivered successfully, False otherwise
|
|
"""
|
|
# Normalize delivery channel to lowercase for comparison
|
|
delivery_channel = (survey_instance.delivery_channel or '').lower()
|
|
|
|
# Get recipient (patient or staff)
|
|
recipient = survey_instance.get_recipient()
|
|
|
|
# Ensure contact info is set
|
|
if delivery_channel == 'sms':
|
|
if recipient:
|
|
survey_instance.recipient_phone = survey_instance.recipient_phone or recipient.phone
|
|
elif delivery_channel == 'email':
|
|
if recipient:
|
|
survey_instance.recipient_email = survey_instance.recipient_email or getattr(recipient, 'email', None)
|
|
|
|
# Save contact info
|
|
survey_instance.save()
|
|
|
|
# Send based on channel
|
|
if delivery_channel == 'sms':
|
|
return SurveyDeliveryService.send_survey_sms(survey_instance)
|
|
elif delivery_channel == 'email':
|
|
return SurveyDeliveryService.send_survey_email(survey_instance)
|
|
elif delivery_channel == 'whatsapp':
|
|
# TODO: Implement WhatsApp delivery
|
|
logger.warning(f"WhatsApp delivery not yet implemented for survey {survey_instance.id}")
|
|
return False
|
|
else:
|
|
logger.error(f"Unknown delivery channel: {survey_instance.delivery_channel}")
|
|
return False
|