269 lines
9.8 KiB
Python
269 lines
9.8 KiB
Python
|
|
from django.core.mail import send_mail
|
|||
|
|
from django.conf import settings
|
|||
|
|
from django.template.loader import render_to_string
|
|||
|
|
import logging
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
def send_booking_notification_email(booking_id):
|
|||
|
|
"""
|
|||
|
|
Send email to admin when a new therapy booking is submitted
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
from .models import TherapyBooking
|
|||
|
|
booking = TherapyBooking.objects.get(id=booking_id)
|
|||
|
|
|
|||
|
|
subject = f"New Therapy Booking Request - {booking.full_name}"
|
|||
|
|
|
|||
|
|
html_message = render_to_string('emails/booking_notification.html', {
|
|||
|
|
'booking': booking,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
plain_message = f"""
|
|||
|
|
New Therapy Booking Request Received!
|
|||
|
|
|
|||
|
|
Client: {booking.full_name}
|
|||
|
|
Email: {booking.email}
|
|||
|
|
Phone: {booking.phone}
|
|||
|
|
Appointment Type: {booking.get_appointment_type_display()}
|
|||
|
|
Preferred Date: {booking.preferred_date}
|
|||
|
|
Preferred Time: {booking.preferred_time}
|
|||
|
|
|
|||
|
|
Additional Message:
|
|||
|
|
{booking.additional_message or 'No additional message provided.'}
|
|||
|
|
|
|||
|
|
Please review this booking in the admin dashboard.
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
# Send to admin email
|
|||
|
|
admin_email = settings.ADMIN_EMAIL or settings.DEFAULT_FROM_EMAIL
|
|||
|
|
|
|||
|
|
send_mail(
|
|||
|
|
subject=subject,
|
|||
|
|
message=plain_message,
|
|||
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|||
|
|
recipient_list=[admin_email],
|
|||
|
|
html_message=html_message,
|
|||
|
|
fail_silently=True, # Don't crash if email fails
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
logger.info(f"Booking notification email sent for booking {booking_id}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Failed to send booking notification email: {str(e)}")
|
|||
|
|
|
|||
|
|
def send_booking_confirmation_email(booking_id):
|
|||
|
|
try:
|
|||
|
|
from .models import TherapyBooking
|
|||
|
|
booking = TherapyBooking.objects.get(id=booking_id)
|
|||
|
|
|
|||
|
|
logger.info(f"Attempting to send confirmation email for booking {booking_id} to {booking.email}")
|
|||
|
|
|
|||
|
|
subject = f"✅ Appointment Confirmed - {booking.get_appointment_type_display()} - {booking.confirmed_datetime.strftime('%b %d')}"
|
|||
|
|
|
|||
|
|
html_message = render_to_string('emails/booking_confirmed.html', {
|
|||
|
|
'booking': booking,
|
|||
|
|
'payment_url': f"https://attunehearttherapy.com/payment/{booking.id}",
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# Get appointment duration
|
|||
|
|
duration = get_appointment_duration(booking.appointment_type)
|
|||
|
|
|
|||
|
|
# Format datetime for plain text
|
|||
|
|
formatted_datetime = booking.confirmed_datetime.strftime('%A, %B %d, %Y at %I:%M %p')
|
|||
|
|
|
|||
|
|
# Build plain text message dynamically
|
|||
|
|
plain_message_parts = [
|
|||
|
|
f"APPOINTMENT CONFIRMED - Attune Heart Therapy",
|
|||
|
|
f"",
|
|||
|
|
f"Dear {booking.full_name},",
|
|||
|
|
f"",
|
|||
|
|
f"We're delighted to confirm your {booking.get_appointment_type_display()} appointment.",
|
|||
|
|
f"",
|
|||
|
|
f"APPOINTMENT DETAILS:",
|
|||
|
|
f"- Type: {booking.get_appointment_type_display()}",
|
|||
|
|
f"- Date & Time: {formatted_datetime}",
|
|||
|
|
f"- Duration: {duration}",
|
|||
|
|
f"- Therapist: {booking.assigned_therapist.get_full_name() if booking.assigned_therapist else 'To be assigned'}",
|
|||
|
|
f"- Payment Status: {booking.get_payment_status_display()}",
|
|||
|
|
f"",
|
|||
|
|
f"JOIN YOUR SESSION:",
|
|||
|
|
f"Video Meeting Link: {booking.jitsi_meet_url}",
|
|||
|
|
f"",
|
|||
|
|
f"Please join 5-10 minutes before your scheduled time to test your audio and video.",
|
|||
|
|
f"",
|
|||
|
|
f"PREPARATION TIPS:",
|
|||
|
|
f"• Test your camera, microphone, and internet connection",
|
|||
|
|
f"• Find a quiet, private space",
|
|||
|
|
f"• Use Chrome, Firefox, or Safari for best experience",
|
|||
|
|
f"• Have a glass of water nearby",
|
|||
|
|
f""
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
# Add payment information if not paid
|
|||
|
|
if booking.payment_status != 'paid':
|
|||
|
|
plain_message_parts.extend([
|
|||
|
|
f"PAYMENT INFORMATION:",
|
|||
|
|
f"Your session fee of ${booking.amount} is pending. Please complete your payment before the session.",
|
|||
|
|
f""
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
plain_message_parts.extend([
|
|||
|
|
f"NEED TO RESCHEDULE?",
|
|||
|
|
f"Please contact us at least 24 hours in advance at (954) 807-3027.",
|
|||
|
|
f"",
|
|||
|
|
f"We look forward to supporting you on your healing journey!",
|
|||
|
|
f"",
|
|||
|
|
f"Warm regards,",
|
|||
|
|
f"The Attune Heart Therapy Team",
|
|||
|
|
f"",
|
|||
|
|
f"Contact Information:",
|
|||
|
|
f"📞 (954) 807-3027",
|
|||
|
|
f"✉️ hello@attunehearttherapy.com",
|
|||
|
|
f"🌐 attunehearttherapy.com",
|
|||
|
|
f"",
|
|||
|
|
f"Confirmation ID: {booking.id}"
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
plain_message = "\n".join(plain_message_parts)
|
|||
|
|
|
|||
|
|
result = send_mail(
|
|||
|
|
subject=subject,
|
|||
|
|
message=plain_message,
|
|||
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|||
|
|
recipient_list=[booking.email],
|
|||
|
|
html_message=html_message,
|
|||
|
|
fail_silently=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
logger.info(f"✅ Booking confirmation email sent successfully to {booking.email}. Sendmail result: {result}")
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"❌ Failed to send booking confirmation email: {str(e)}", exc_info=True)
|
|||
|
|
return False
|
|||
|
|
def get_appointment_duration(appointment_type):
|
|||
|
|
"""Helper function to get appointment duration"""
|
|||
|
|
durations = {
|
|||
|
|
'initial-consultation': '90 minutes',
|
|||
|
|
'individual-therapy': '60 minutes',
|
|||
|
|
'family-therapy': '90 minutes',
|
|||
|
|
'couples-therapy': '75 minutes',
|
|||
|
|
'group-therapy': '90 minutes',
|
|||
|
|
'follow-up': '45 minutes',
|
|||
|
|
}
|
|||
|
|
return durations.get(appointment_type, '60 minutes')
|
|||
|
|
def get_appointment_duration(appointment_type):
|
|||
|
|
"""Helper function to get appointment duration"""
|
|||
|
|
durations = {
|
|||
|
|
'initial-consultation': '90 minutes',
|
|||
|
|
'individual-therapy': '60 minutes',
|
|||
|
|
'family-therapy': '90 minutes',
|
|||
|
|
'couples-therapy': '75 minutes',
|
|||
|
|
'group-therapy': '90 minutes',
|
|||
|
|
'follow-up': '45 minutes',
|
|||
|
|
}
|
|||
|
|
return durations.get(appointment_type, '60 minutes')
|
|||
|
|
|
|||
|
|
def send_payment_confirmation_email(booking_id):
|
|||
|
|
try:
|
|||
|
|
from .models import TherapyBooking
|
|||
|
|
booking = TherapyBooking.objects.get(id=booking_id)
|
|||
|
|
|
|||
|
|
subject = f"💳 Payment Confirmed - {booking.get_appointment_type_display()}"
|
|||
|
|
|
|||
|
|
html_message = render_to_string('emails/payment_confirmed.html', {
|
|||
|
|
'booking': booking,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
duration = get_appointment_duration(booking.appointment_type)
|
|||
|
|
payment_id = booking.stripe_payment_intent_id or str(booking.id)
|
|||
|
|
|
|||
|
|
plain_message = f"""
|
|||
|
|
PAYMENT CONFIRMED - Attune Heart Therapy
|
|||
|
|
|
|||
|
|
Dear {booking.full_name},
|
|||
|
|
|
|||
|
|
Thank you for your payment! Your {booking.get_appointment_type_display()} appointment is now fully confirmed.
|
|||
|
|
|
|||
|
|
PAYMENT DETAILS:
|
|||
|
|
- Amount Paid: ${booking.amount}
|
|||
|
|
- Payment Date: {booking.paid_at.strftime('%B %d, %Y at %I:%M %p')}
|
|||
|
|
- Payment ID: {payment_id}
|
|||
|
|
- Appointment: {booking.get_appointment_type_display()}
|
|||
|
|
|
|||
|
|
SESSION DETAILS:
|
|||
|
|
- Date & Time: {booking.confirmed_datetime.strftime('%A, %B %d, %Y at %I:%M %p')}
|
|||
|
|
- Duration: {duration}
|
|||
|
|
- Therapist: {booking.assigned_therapist.get_full_name() if booking.assigned_therapist else 'To be assigned'}
|
|||
|
|
- Video Meeting: {booking.jitsi_meet_url}
|
|||
|
|
|
|||
|
|
Please join 5-10 minutes before your scheduled time to test your audio and video.
|
|||
|
|
|
|||
|
|
This email serves as your receipt for tax purposes.
|
|||
|
|
|
|||
|
|
If you have any questions about your payment or appointment, please contact us at (954) 807-3027.
|
|||
|
|
|
|||
|
|
Thank you for trusting us with your care!
|
|||
|
|
|
|||
|
|
Warm regards,
|
|||
|
|
The Attune Heart Therapy Team
|
|||
|
|
|
|||
|
|
Contact Information:
|
|||
|
|
📞 (954) 807-3027
|
|||
|
|
✉️ hello@attunehearttherapy.com
|
|||
|
|
🌐 attunehearttherapy.com
|
|||
|
|
|
|||
|
|
Payment ID: {payment_id}
|
|||
|
|
Processed: {booking.paid_at.strftime('%Y-%m-%d %H:%M')}
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
send_mail(
|
|||
|
|
subject=subject,
|
|||
|
|
message=plain_message,
|
|||
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|||
|
|
recipient_list=[booking.email],
|
|||
|
|
html_message=html_message,
|
|||
|
|
fail_silently=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
logger.info(f"✅ Payment confirmation email sent to {booking.email}")
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"❌ Failed to send payment confirmation email: {str(e)}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def send_payment_failure_email(booking_id):
|
|||
|
|
"""
|
|||
|
|
Send payment failure email
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
from .models import TherapyBooking
|
|||
|
|
booking = TherapyBooking.objects.get(id=booking_id)
|
|||
|
|
|
|||
|
|
subject = f"Payment Issue - {booking.get_appointment_type_display()}"
|
|||
|
|
|
|||
|
|
plain_message = f"""
|
|||
|
|
Payment Issue
|
|||
|
|
|
|||
|
|
Dear {booking.full_name},
|
|||
|
|
|
|||
|
|
We encountered an issue processing your payment for the {booking.get_appointment_type_display()} appointment.
|
|||
|
|
|
|||
|
|
Please try again or contact us at (954) 807-3027 to complete your payment.
|
|||
|
|
|
|||
|
|
Best regards,
|
|||
|
|
Attune Heart Therapy Team
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
send_mail(
|
|||
|
|
subject=subject,
|
|||
|
|
message=plain_message,
|
|||
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|||
|
|
recipient_list=[booking.email],
|
|||
|
|
fail_silently=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"Failed to send payment failure email: {str(e)}")
|