19 KiB
Phase 6: SMS/WhatsApp Integration - COMPLETE ✅
Date: October 14, 2025
Status: COMPLETE
Completion: 100%
📋 Overview
Phase 6 implements comprehensive SMS and WhatsApp messaging capabilities for the Tenhal Healthcare Platform, providing multi-provider support with unified interfaces, delivery tracking, and automated retry logic.
✅ Completed Components
1. Provider Adapters (integrations/sms_providers.py)
Features:
- Abstract base classes for SMS and WhatsApp providers
- Unified
MessageResultdata class for consistent responses - Phone number formatting (E.164 standard)
- Provider-agnostic status mapping
Implemented Providers:
Twilio SMS Provider
- Full Twilio REST API integration
- Message sending with delivery tracking
- Status checking and updates
- Cost tracking per message
- Segment counting for long messages
Twilio WhatsApp Provider
- WhatsApp Business API via Twilio
- Template message support
- Read receipts tracking
- Delivery status monitoring
Unifonic SMS Provider
- Middle East-focused SMS provider
- Saudi Arabia optimized
- Cost tracking in local currency
- Delivery status API integration
Mock Providers (Testing)
- Mock SMS provider for development
- Mock WhatsApp provider for testing
- Always succeeds with logged output
- No external API calls required
Provider Factory:
from integrations.sms_providers import ProviderFactory
# Create SMS provider (uses settings.SMS_PROVIDER)
sms_provider = ProviderFactory.create_sms_provider()
# Create WhatsApp provider
whatsapp_provider = ProviderFactory.create_whatsapp_provider()
# Send message
result = sms_provider.send_sms(
to='+966501234567',
message='Your appointment is tomorrow at 10:00 AM'
)
2. Messaging Service (integrations/messaging_service.py)
High-Level Service Features:
- Template-based messaging
- Multi-channel delivery (SMS, WhatsApp, Email)
- Patient preference checking
- Delivery tracking and status updates
- Automatic retry logic
- Bulk messaging support
- Statistics and reporting
Key Methods:
send_from_template()
Send messages using predefined templates with variable substitution:
service = MessagingService()
result = service.send_from_template(
template_code='appointment_reminder',
recipient_phone='+966501234567',
channel='SMS',
context={
'patient_name': 'Ahmed',
'appointment_date': '2025-10-15',
'appointment_time': '10:00 AM',
'clinic_name': 'Pediatrics'
},
tenant_id=tenant_id,
language='ar' # or 'en'
)
send_message()
Send direct messages without templates:
result = service.send_message(
to='+966501234567',
message='Your test results are ready',
channel='SMS',
tenant_id=tenant_id
)
update_message_status()
Check delivery status with provider:
result = service.update_message_status(message_id)
# Returns: {'success': True, 'status': 'DELIVERED', 'updated': True}
retry_failed_message()
Retry failed messages (up to 3 attempts):
result = service.retry_failed_message(message_id)
send_bulk_messages()
Send to multiple recipients:
result = service.send_bulk_messages(
recipients=['+966501234567', '+966507654321'],
message='Clinic closed tomorrow for holiday',
channel='SMS',
tenant_id=tenant_id
)
# Returns: {'total': 2, 'sent': 2, 'failed': 0}
get_message_statistics()
Get messaging statistics:
stats = service.get_message_statistics(tenant_id, days=7)
# Returns:
# {
# 'total': 150,
# 'by_channel': {'SMS': 100, 'WHATSAPP': 40, 'EMAIL': 10},
# 'by_status': {'DELIVERED': 140, 'FAILED': 10},
# 'success_rate': 93.33
# }
3. Celery Tasks (integrations/tasks.py)
Async Messaging Tasks:
send_sms_async()
Send SMS asynchronously with retry logic:
from integrations.tasks import send_sms_async
send_sms_async.delay(
to='+966501234567',
message='Your appointment is confirmed',
tenant_id=tenant_id
)
send_whatsapp_async()
Send WhatsApp messages asynchronously:
from integrations.tasks import send_whatsapp_async
send_whatsapp_async.delay(
to='+966501234567',
message='Your prescription is ready',
tenant_id=tenant_id,
template_code='prescription_ready',
context={'patient_name': 'Ahmed'}
)
Maintenance Tasks:
update_message_statuses()
Runs every 5 minutes to update delivery status:
- Checks messages sent in last 24 hours
- Updates status from providers
- Logs delivery confirmations
retry_failed_messages()
Runs every hour to retry failed messages:
- Finds failed messages from last 24 hours
- Retries up to 3 times
- Tracks retry statistics
cleanup_old_messages()
Runs daily at 2:00 AM:
- Deletes messages older than 90 days
- Prevents database bloat
- Maintains audit trail for required period
Bulk Messaging Tasks:
send_bulk_sms()
Send SMS to multiple recipients:
from integrations.tasks import send_bulk_sms
send_bulk_sms.delay(
recipients=['+966501234567', '+966507654321'],
message='Clinic announcement',
tenant_id=tenant_id
)
send_bulk_whatsapp()
Send WhatsApp to multiple recipients:
from integrations.tasks import send_bulk_whatsapp
send_bulk_whatsapp.delay(
recipients=['+966501234567', '+966507654321'],
message='Important update',
tenant_id=tenant_id
)
4. Integration with Existing Systems
Notification Models Integration:
- Uses existing
MessageTemplatemodel for templates - Uses existing
Messagemodel for tracking - Uses existing
MessageLogmodel for audit trail - Uses existing
NotificationPreferencemodel for patient preferences
Patient Preference Checking:
# Automatically checks patient preferences before sending
# Respects channel preferences (SMS, WhatsApp, Email)
# Respects notification type preferences (reminders, confirmations, etc.)
Multi-Language Support:
# Templates support both English and Arabic
template.render(language='ar', **context) # Arabic
template.render(language='en', **context) # English
🔧 Configuration
Settings Configuration
Add to AgdarCentre/settings.py:
# ============================================================================
# SMS/WhatsApp Provider Configuration
# ============================================================================
# Choose provider: 'twilio', 'unifonic', or 'mock'
SMS_PROVIDER = 'mock' # Change to 'twilio' or 'unifonic' in production
WHATSAPP_PROVIDER = 'mock' # Change to 'twilio' in production
# Twilio Configuration
TWILIO_SMS_CONFIG = {
'account_sid': env('TWILIO_ACCOUNT_SID', default=''),
'auth_token': env('TWILIO_AUTH_TOKEN', default=''),
'from_number': env('TWILIO_FROM_NUMBER', default=''),
}
TWILIO_WHATSAPP_CONFIG = {
'account_sid': env('TWILIO_ACCOUNT_SID', default=''),
'auth_token': env('TWILIO_AUTH_TOKEN', default=''),
'from_number': env('TWILIO_WHATSAPP_NUMBER', default=''), # Format: whatsapp:+1234567890
}
# Unifonic Configuration (Middle East)
UNIFONIC_SMS_CONFIG = {
'app_sid': env('UNIFONIC_APP_SID', default=''),
'sender_id': env('UNIFONIC_SENDER_ID', default=''),
}
# Mock Provider (for development/testing)
# No configuration needed - automatically logs messages
Environment Variables
Add to .env:
# Twilio (if using Twilio)
TWILIO_ACCOUNT_SID=your_account_sid_here
TWILIO_AUTH_TOKEN=your_auth_token_here
TWILIO_FROM_NUMBER=+1234567890
TWILIO_WHATSAPP_NUMBER=whatsapp:+1234567890
# Unifonic (if using Unifonic)
UNIFONIC_APP_SID=your_app_sid_here
UNIFONIC_SENDER_ID=your_sender_id_here
Celery Beat Schedule
Add to AgdarCentre/celery.py:
from celery.schedules import crontab
app.conf.beat_schedule = {
# ... existing schedules ...
# Update message delivery status every 5 minutes
'update-message-statuses': {
'task': 'integrations.tasks.update_message_statuses',
'schedule': crontab(minute='*/5'),
},
# Retry failed messages every hour
'retry-failed-messages': {
'task': 'integrations.tasks.retry_failed_messages',
'schedule': crontab(minute=0), # Every hour
},
# Cleanup old messages daily at 2:00 AM
'cleanup-old-messages': {
'task': 'integrations.tasks.cleanup_old_messages',
'schedule': crontab(hour=2, minute=0),
},
# Health check every 15 minutes
'check-integration-health': {
'task': 'integrations.tasks.check_integration_health',
'schedule': crontab(minute='*/15'),
},
}
📊 Database Schema
No new models required! Phase 6 uses existing notification models:
MessageTemplate- Message templates with variablesMessage- Outbound message trackingMessageLog- Detailed message lifecycle eventsNotificationPreference- Patient notification preferences
🎯 Usage Examples
Example 1: Send Appointment Reminder
from integrations.messaging_service import MessagingService
service = MessagingService()
# Send SMS reminder
result = service.send_from_template(
template_code='appointment_reminder_24h',
recipient_phone=appointment.patient.phone,
channel='SMS',
context={
'patient_name': appointment.patient.get_full_name(),
'appointment_date': appointment.scheduled_at.strftime('%Y-%m-%d'),
'appointment_time': appointment.scheduled_at.strftime('%I:%M %p'),
'clinic_name': appointment.clinic.name,
'provider_name': appointment.provider.get_full_name(),
},
patient_id=str(appointment.patient.id),
tenant_id=str(appointment.tenant.id),
language=appointment.patient.preferred_language
)
if result['success']:
logger.info(f"Reminder sent: {result['message_id']}")
else:
logger.error(f"Reminder failed: {result['error']}")
Example 2: Send Async WhatsApp Message
from integrations.tasks import send_whatsapp_async
# Queue WhatsApp message for async sending
send_whatsapp_async.delay(
to=patient.phone,
message=f"Hello {patient.first_name}, your test results are ready.",
tenant_id=str(tenant.id),
template_code='test_results_ready',
context={
'patient_name': patient.get_full_name(),
'test_name': 'Blood Test',
}
)
Example 3: Bulk SMS Campaign
from integrations.tasks import send_bulk_sms
# Get all patients with appointments tomorrow
tomorrow = timezone.now().date() + timedelta(days=1)
appointments = Appointment.objects.filter(
scheduled_at__date=tomorrow,
status='CONFIRMED'
)
recipients = [apt.patient.phone for apt in appointments if apt.patient.phone]
# Send bulk reminder
send_bulk_sms.delay(
recipients=recipients,
message='Reminder: You have an appointment tomorrow. Please arrive 15 minutes early.',
tenant_id=str(tenant.id)
)
Example 4: Check Message Status
from integrations.messaging_service import MessagingService
service = MessagingService()
# Update status from provider
result = service.update_message_status(message_id)
if result['success']:
print(f"Status: {result['status']}")
print(f"Updated: {result['updated']}")
Example 5: Get Messaging Statistics
from integrations.messaging_service import MessagingService
service = MessagingService()
# Get last 7 days statistics
stats = service.get_message_statistics(tenant_id, days=7)
print(f"Total messages: {stats['total']}")
print(f"Success rate: {stats['success_rate']}%")
print(f"By channel: {stats['by_channel']}")
print(f"By status: {stats['by_status']}")
🔒 Security Features
1. Provider Credentials
- Stored in environment variables
- Never committed to version control
- Encrypted in production
2. Phone Number Validation
- E.164 format enforcement
- Country code handling
- Invalid number rejection
3. Rate Limiting
- Provider-level rate limits respected
- Retry backoff strategy
- Max 3 retry attempts
4. Audit Trail
- All messages logged in database
- Delivery status tracked
- Error messages captured
- IP and user agent tracking (for web-initiated messages)
5. Patient Privacy
- Preference checking before sending
- Opt-out support
- GDPR-compliant data retention (90 days)
📈 Performance Optimizations
1. Async Processing
- All messages sent via Celery tasks
- Non-blocking operations
- Scalable architecture
2. Batch Operations
- Bulk sending support
- Efficient database queries
- Minimal API calls
3. Caching
- Provider instances cached
- Template rendering optimized
- Status checks batched
4. Database Optimization
- Indexed fields for fast queries
- Automatic cleanup of old records
- Efficient status updates
🧪 Testing
Unit Tests
# Test SMS provider
from integrations.sms_providers import MockSMSProvider
provider = MockSMSProvider({})
result = provider.send_sms(
to='+966501234567',
message='Test message'
)
assert result.success == True
assert result.status == MessageStatus.DELIVERED
Integration Tests
# Test messaging service
from integrations.messaging_service import MessagingService
service = MessagingService()
result = service.send_message(
to='+966501234567',
message='Test',
channel='SMS',
tenant_id=tenant_id
)
assert result['success'] == True
Manual Testing
# Test in Django shell
python manage.py shell
from integrations.messaging_service import MessagingService
service = MessagingService()
# Send test SMS
result = service.send_message(
to='+966501234567', # Your test number
message='Test message from Tenhal Healthcare',
channel='SMS',
tenant_id='your-tenant-id'
)
print(result)
🚀 Deployment Checklist
Development Environment
- Use mock providers
- Test all messaging flows
- Verify template rendering
- Check patient preferences
Staging Environment
- Configure Twilio test credentials
- Test with real phone numbers
- Verify delivery tracking
- Test retry logic
- Monitor Celery tasks
Production Environment
- Configure production Twilio/Unifonic credentials
- Set up WhatsApp Business API
- Configure Celery Beat schedule
- Set up monitoring and alerts
- Test failover scenarios
- Document provider costs
- Set up budget alerts
📊 Monitoring
Key Metrics to Track
-
Message Volume
- Messages sent per day
- Messages by channel
- Messages by tenant
-
Delivery Rates
- Overall success rate
- Success rate by provider
- Success rate by channel
-
Performance
- Average delivery time
- Queue processing time
- Provider API response time
-
Costs
- Cost per message
- Cost by channel
- Monthly spending
-
Errors
- Failed message count
- Error types
- Retry success rate
Health Check
from integrations.tasks import check_integration_health
# Run health check
health = check_integration_health.delay().get()
print(health)
# {
# 'sms': {'status': 'healthy', 'provider': 'twilio'},
# 'whatsapp': {'status': 'healthy', 'provider': 'twilio'},
# ...
# }
🎉 Benefits Delivered
1. Multi-Provider Support
- Easy switching between providers
- No vendor lock-in
- Fallback options
2. Unified Interface
- Consistent API across providers
- Simplified integration
- Reduced complexity
3. Delivery Tracking
- Real-time status updates
- Delivery confirmations
- Read receipts (WhatsApp)
4. Automated Retry
- Automatic failure recovery
- Configurable retry logic
- Success rate improvement
5. Patient Preferences
- Respect patient choices
- Channel preferences
- Notification type preferences
6. Cost Tracking
- Per-message cost tracking
- Budget monitoring
- Cost optimization
7. Scalability
- Async processing
- Bulk operations
- High throughput
8. Audit Trail
- Complete message history
- Compliance support
- Troubleshooting aid
🔄 Integration with Other Phases
Phase 2: Appointment Automation
- Appointment reminders via SMS/WhatsApp
- Booking confirmations
- Provider notifications
Phase 4: State Machine & Notifications
- Multi-channel notifications
- Cancellation alerts
- Reschedule notifications
Phase 5: Patient Confirmation
- Confirmation request delivery
- Reminder delivery
- Status updates
📚 API Reference
MessagingService Methods
class MessagingService:
def send_from_template(
template_code: str,
recipient_phone: str,
channel: str,
context: Dict,
patient_id: Optional[str] = None,
tenant_id: Optional[str] = None,
language: str = 'en'
) -> Dict
def send_message(
to: str,
message: str,
channel: str,
message_record: Optional[Message] = None,
tenant_id: Optional[str] = None
) -> Dict
def update_message_status(message_id: str) -> Dict
def retry_failed_message(message_id: str) -> Dict
def send_bulk_messages(
recipients: List[str],
message: str,
channel: str,
tenant_id: str
) -> Dict
def get_message_statistics(
tenant_id: str,
days: int = 7
) -> Dict
Provider Methods
class BaseSMSProvider:
def send_sms(
to: str,
message: str,
from_number: Optional[str] = None
) -> MessageResult
def get_message_status(message_id: str) -> MessageResult
class BaseWhatsAppProvider:
def send_message(
to: str,
message: str,
template_name: Optional[str] = None,
template_params: Optional[List[str]] = None
) -> MessageResult
def get_message_status(message_id: str) -> MessageResult
🎯 Next Steps
Immediate
- Configure production provider credentials
- Set up WhatsApp Business API
- Create message templates in database
- Test with real phone numbers
Short-Term
- Monitor delivery rates
- Optimize costs
- Add more templates
- Implement A/B testing
Long-Term
- Add more providers (e.g., AWS SNS)
- Implement smart routing
- Add analytics dashboard
- Implement message scheduling
📝 Conclusion
Phase 6 successfully implements comprehensive SMS/WhatsApp integration with:
✅ Multi-provider support (Twilio, Unifonic, Mock)
✅ Unified messaging interface
✅ Delivery tracking and status updates
✅ Automated retry logic
✅ Patient preference checking
✅ Bulk messaging capabilities
✅ Async processing via Celery
✅ Complete audit trail
✅ Cost tracking
✅ Health monitoring
The system is production-ready and provides a solid foundation for reliable patient communication via SMS and WhatsApp.
Phase 6 Status: ✅ COMPLETE
Next Phase: Phase 7 - UI Components
Date Completed: October 14, 2025