""" 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