diff --git a/backend/test_whatsapp_send.py b/backend/test_whatsapp_send.py new file mode 100644 index 0000000..8eb8044 --- /dev/null +++ b/backend/test_whatsapp_send.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +""" +Test script to send WhatsApp message via template +Usage: python test_whatsapp_send.py +""" + +import asyncio +import os +import sys +import logging +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +# Configure logging +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# Import after logging is configured +from database import SessionLocal +from whatsapp import WhatsAppService + + +async def test_send_whatsapp(): + """Test sending a WhatsApp message using hina_invitation template""" + + db = SessionLocal() + + try: + # Initialize WhatsApp service + service = WhatsAppService(db=db) + + # Phone number to test (Israeli format) + phone = "0504370045" + + # Template parameters for hina_invitation + params = { + "contact_name": "דוד", + "event_date": "17/05", + "event_date_day": "17", + "venue": "אולם הגן", + "location": "ירושלים", + "reception_time": "18:30", + "ceremony_time": "19:00", + "dinner_time": "20:00", + "bride_name": "ורד", + "groom_name": "דביר", + "event_id": "f3122a7d-1d7c-4cc1-955d-1c6b7358bd25" + } + + print("\n" + "="*80) + print("TESTING WHATSAPP MESSAGE SEND") + print("="*80) + print(f"Phone: {phone}") + print(f"Template: hina_invitation") + print(f"Parameters: {params}") + print("="*80 + "\n") + + # Send the message + logger.info(f"Attempting to send WhatsApp message to {phone}") + result = await service.send_by_template_key( + template_key="wedding_invitation_by_vered", + to_phone=phone, + params=params + ) + + print("\n" + "="*80) + print("SUCCESS!") + print("="*80) + print(f"Result: {result}") + print("="*80 + "\n") + + return result + + except Exception as e: + print("\n" + "="*80) + print("ERROR!") + print("="*80) + print(f"Error: {str(e)}") + import traceback + traceback.print_exc() + print("="*80 + "\n") + raise + + finally: + db.close() + + +if __name__ == "__main__": + asyncio.run(test_send_whatsapp()) diff --git a/backend/whatsapp.py b/backend/whatsapp.py index 410a5c2..7ec439b 100644 --- a/backend/whatsapp.py +++ b/backend/whatsapp.py @@ -3,7 +3,6 @@ WhatsApp Cloud API Service Handles sending WhatsApp messages via Meta's API """ import os -import ssl import httpx import certifi import re @@ -15,32 +14,19 @@ from datetime import datetime logger = logging.getLogger(__name__) -def create_http_client() -> httpx.AsyncClient: +async def create_http_client() -> httpx.AsyncClient: """ - Create an httpx client with robust SSL configuration. - Tries to use system certificates first, falls back to certifi. + Create an httpx client with proper certificate verification. + Uses certifi for CA bundle and lets httpx handle SSL/TLS negotiation. """ - try: - # Try using system SSL context with certifi certificates - ssl_context = ssl.create_default_context(cafile=certifi.where()) - # Enable hostname checking but allow some TLS flexibility - ssl_context.check_hostname = True - ssl_context.verify_mode = ssl.CERT_REQUIRED - # Use more compatible TLS versions - ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2 - - return httpx.AsyncClient(verify=ssl_context, timeout=30.0) - except Exception as e: - logger.warning(f"[WhatsApp] Failed to create SSL context with certifi: {e}. Trying default SSL.") - try: - # Fallback to default SSL context - ssl_context = ssl.create_default_context() - ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2 - return httpx.AsyncClient(verify=ssl_context, timeout=30.0) - except Exception as e2: - logger.error(f"[WhatsApp] Failed to create SSL context: {e2}. Using basic client.") - # Last resort fallback - httpx will use its own SSL handling - return httpx.AsyncClient(timeout=30.0) + # Let httpx use certifi's CA bundle - simpler and more reliable + return httpx.AsyncClient( + verify=certifi.where(), + timeout=httpx.Timeout(30.0, connect=10.0), + http2=False, # Disable HTTP/2 to avoid compatibility issues + limits=httpx.Limits(max_keepalive_connections=5, max_connections=10) + ) + class WhatsAppError(Exception): @@ -195,7 +181,7 @@ class WhatsAppService: url = f"{self.base_url}/{self.phone_number_id}/messages" try: - async with create_http_client() as client: + async with await create_http_client() as client: response = await client.post( url, json=payload, @@ -325,7 +311,7 @@ class WhatsAppService: print("=" * 80 + "\n") try: - async with create_http_client() as client: + async with await create_http_client() as client: response = await client.post( url, json=payload, @@ -588,7 +574,7 @@ class WhatsAppService: url = f"{self.base_url}/{self.phone_number_id}/messages" try: - async with create_http_client() as client: + async with await create_http_client() as client: response = await client.post( url, json=payload,