Autosave: 20260128-021353
This commit is contained in:
parent
a982102796
commit
e6c45971eb
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
core/__pycache__/notifications.cpython-311.pyc
Normal file
BIN
core/__pycache__/notifications.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
from .models import Profile, Parcel, Country, Governate, City, PlatformProfile, Testimonial, DriverRating
|
||||
from .models import Profile, Parcel, Country, Governate, City, PlatformProfile, Testimonial, DriverRating, NotificationTemplate
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.urls import path, reverse
|
||||
from django.shortcuts import render
|
||||
@ -234,4 +234,30 @@ admin.site.register(Governate)
|
||||
admin.site.register(City)
|
||||
admin.site.register(PlatformProfile, PlatformProfileAdmin)
|
||||
admin.site.register(Testimonial, TestimonialAdmin)
|
||||
admin.site.register(DriverRating)
|
||||
admin.site.register(DriverRating)
|
||||
class NotificationTemplateAdmin(admin.ModelAdmin):
|
||||
list_display = ('key', 'description')
|
||||
readonly_fields = ('key', 'description', 'available_variables')
|
||||
search_fields = ('key', 'description')
|
||||
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('key', 'description', 'available_variables')
|
||||
}),
|
||||
(_('Email Content'), {
|
||||
'fields': ('subject_en', 'subject_ar', 'email_body_en', 'email_body_ar'),
|
||||
'description': _('For emails, the body is wrapped in a base template. Use HTML if needed.')
|
||||
}),
|
||||
(_('WhatsApp Content'), {
|
||||
'fields': ('whatsapp_body_en', 'whatsapp_body_ar'),
|
||||
'description': _('For WhatsApp, use plain text with newlines.')
|
||||
}),
|
||||
)
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False # Prevent adding new keys manually
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
admin.site.register(NotificationTemplate, NotificationTemplateAdmin)
|
||||
|
||||
41
core/mail.py
41
core/mail.py
@ -55,31 +55,36 @@ def send_html_email(subject, message, recipient_list, title=None, action_url=Non
|
||||
def send_contact_message(name, email, message):
|
||||
"""
|
||||
Sends a contact form message to the platform admins.
|
||||
|
||||
Args:
|
||||
name (str): Sender's name
|
||||
email (str): Sender's email
|
||||
message (str): The message content
|
||||
|
||||
Returns:
|
||||
bool: True if sent successfully, False otherwise
|
||||
"""
|
||||
try:
|
||||
subject = f"New Contact Message from {name}"
|
||||
full_message = f"You have received a new message from your website contact form.\n\n" \
|
||||
f"Name: {name}\n" \
|
||||
f"Email: {email}\n\n" \
|
||||
f"Message:\n{message}"
|
||||
from .notifications import get_notification_content
|
||||
|
||||
context = {'name': name, 'email': email, 'message': message}
|
||||
# Admin alerts default to EN
|
||||
subj, email_msg, wa_msg = get_notification_content('contact_form_admin', context, language='en')
|
||||
|
||||
recipient_list = settings.CONTACT_EMAIL_TO or [settings.DEFAULT_FROM_EMAIL]
|
||||
|
||||
# Use HTML email for contact form too, for consistency
|
||||
return send_html_email(
|
||||
subject=subject,
|
||||
message=full_message,
|
||||
# Email
|
||||
email_sent = send_html_email(
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=recipient_list,
|
||||
title="New Contact Message"
|
||||
)
|
||||
|
||||
# WhatsApp (New feature: Notify admin on WhatsApp too)
|
||||
try:
|
||||
from .models import PlatformProfile
|
||||
from .whatsapp_utils import send_whatsapp_message
|
||||
|
||||
profile = PlatformProfile.objects.first()
|
||||
if profile and profile.phone_number:
|
||||
send_whatsapp_message(profile.phone_number, wa_msg)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to send admin WhatsApp for contact form: {e}")
|
||||
|
||||
return email_sent
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send contact message: {e}")
|
||||
return False
|
||||
return False
|
||||
|
||||
Binary file not shown.
30
core/management/commands/init_notifications.py
Normal file
30
core/management/commands/init_notifications.py
Normal file
@ -0,0 +1,30 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from core.models import NotificationTemplate
|
||||
from core.notifications import DEFAULT_TEMPLATES, get_notification_content
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Initialize default notification templates'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
count = 0
|
||||
for key, default in DEFAULT_TEMPLATES.items():
|
||||
obj, created = NotificationTemplate.objects.get_or_create(
|
||||
key=key,
|
||||
defaults={
|
||||
'description': default.get('description', ''),
|
||||
'available_variables': default.get('variables', ''),
|
||||
'subject_en': default.get('subject_en', ''),
|
||||
'subject_ar': default.get('subject_ar', ''),
|
||||
'email_body_en': default.get('email_body_en', ''),
|
||||
'email_body_ar': default.get('email_body_ar', ''),
|
||||
'whatsapp_body_en': default.get('whatsapp_body_en', ''),
|
||||
'whatsapp_body_ar': default.get('whatsapp_body_ar', ''),
|
||||
}
|
||||
)
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created template: {key}'))
|
||||
count += 1
|
||||
else:
|
||||
self.stdout.write(f'Template exists: {key}')
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f'Initialized {count} new templates.'))
|
||||
32
core/migrations/0022_notificationtemplate.py
Normal file
32
core/migrations/0022_notificationtemplate.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-28 01:04
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0021_remove_platformprofile_privacy_policy_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NotificationTemplate',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('key', models.CharField(choices=[('otp_registration', 'OTP Registration'), ('otp_login', 'OTP Login'), ('otp_profile_update', 'OTP Profile Update'), ('shipment_created_shipper', 'Shipment Created (Shipper)'), ('payment_success_shipper', 'Payment Success (Shipper)'), ('shipment_visible_receiver', 'Shipment Visible (Receiver)'), ('driver_pickup_shipper', 'Driver Pickup (Shipper)'), ('driver_pickup_receiver', 'Driver Pickup (Receiver)'), ('driver_pickup_driver', 'Driver Pickup (Driver/Carrier)'), ('shipment_status_update', 'Shipment Status Update'), ('admin_alert_driver_accept', 'Admin Alert: Driver Accepted'), ('contact_form_admin', 'Contact Form (Admin)')], max_length=50, unique=True)),
|
||||
('description', models.CharField(help_text='Description of where this notification is used.', max_length=255)),
|
||||
('available_variables', models.TextField(blank=True, help_text='Comma-separated list of variables available in this template (e.g. {{ code }}, {{ name }}).')),
|
||||
('subject_en', models.CharField(blank=True, max_length=255, verbose_name='Email Subject (EN)')),
|
||||
('subject_ar', models.CharField(blank=True, max_length=255, verbose_name='Email Subject (AR)')),
|
||||
('email_body_en', models.TextField(blank=True, help_text='HTML allowed.', verbose_name='Email Body (EN)')),
|
||||
('email_body_ar', models.TextField(blank=True, help_text='HTML allowed.', verbose_name='Email Body (AR)')),
|
||||
('whatsapp_body_en', models.TextField(blank=True, verbose_name='WhatsApp Message (EN)')),
|
||||
('whatsapp_body_ar', models.TextField(blank=True, verbose_name='WhatsApp Message (AR)')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Notification Template',
|
||||
'verbose_name_plural': 'Notification Templates',
|
||||
},
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@ -294,4 +294,41 @@ class DriverRating(models.Model):
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Driver Rating')
|
||||
verbose_name_plural = _('Driver Ratings')
|
||||
verbose_name_plural = _('Driver Ratings')
|
||||
|
||||
class NotificationTemplate(models.Model):
|
||||
KEY_CHOICES = (
|
||||
('otp_registration', 'OTP Registration'),
|
||||
('otp_login', 'OTP Login'),
|
||||
('otp_profile_update', 'OTP Profile Update'),
|
||||
('shipment_created_shipper', 'Shipment Created (Shipper)'),
|
||||
('payment_success_shipper', 'Payment Success (Shipper)'),
|
||||
('shipment_visible_receiver', 'Shipment Visible (Receiver)'),
|
||||
('driver_pickup_shipper', 'Driver Pickup (Shipper)'),
|
||||
('driver_pickup_receiver', 'Driver Pickup (Receiver)'),
|
||||
('driver_pickup_driver', 'Driver Pickup (Driver/Carrier)'),
|
||||
('shipment_status_update', 'Shipment Status Update'),
|
||||
('admin_alert_driver_accept', 'Admin Alert: Driver Accepted'),
|
||||
('contact_form_admin', 'Contact Form (Admin)'),
|
||||
)
|
||||
|
||||
key = models.CharField(max_length=50, choices=KEY_CHOICES, unique=True)
|
||||
description = models.CharField(max_length=255, help_text="Description of where this notification is used.")
|
||||
available_variables = models.TextField(help_text="Comma-separated list of variables available in this template (e.g. {{ code }}, {{ name }}).", blank=True)
|
||||
|
||||
# Email
|
||||
subject_en = models.CharField(max_length=255, blank=True, verbose_name="Email Subject (EN)")
|
||||
subject_ar = models.CharField(max_length=255, blank=True, verbose_name="Email Subject (AR)")
|
||||
email_body_en = models.TextField(blank=True, verbose_name="Email Body (EN)", help_text="HTML allowed.")
|
||||
email_body_ar = models.TextField(blank=True, verbose_name="Email Body (AR)", help_text="HTML allowed.")
|
||||
|
||||
# WhatsApp
|
||||
whatsapp_body_en = models.TextField(blank=True, verbose_name="WhatsApp Message (EN)")
|
||||
whatsapp_body_ar = models.TextField(blank=True, verbose_name="WhatsApp Message (AR)")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_key_display()}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Notification Template')
|
||||
verbose_name_plural = _('Notification Templates')
|
||||
183
core/notifications.py
Normal file
183
core/notifications.py
Normal file
@ -0,0 +1,183 @@
|
||||
from django.utils.translation import get_language
|
||||
from .models import NotificationTemplate
|
||||
from django.template import Template, Context
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_TEMPLATES = {
|
||||
'otp_registration': {
|
||||
'description': 'Sent when a user registers (Email/WhatsApp)',
|
||||
'variables': '{{ code }}',
|
||||
'subject_en': 'Verification Code',
|
||||
'subject_ar': 'رمز التحقق',
|
||||
'email_body_en': 'Your Masar Verification Code is {{ code }}',
|
||||
'email_body_ar': 'رمز التحقق الخاص بك هو {{ code }}',
|
||||
'whatsapp_body_en': 'Your Masar Verification Code is {{ code }}',
|
||||
'whatsapp_body_ar': 'رمز التحقق الخاص بك هو {{ code }}',
|
||||
},
|
||||
'otp_login': {
|
||||
'description': 'Sent for 2FA Login (Email/WhatsApp)',
|
||||
'variables': '{{ code }}',
|
||||
'subject_en': 'Login OTP',
|
||||
'subject_ar': 'رمز الدخول',
|
||||
'email_body_en': 'Your Masar Login Code is {{ code }}. Do not share this code.',
|
||||
'email_body_ar': 'رمز دخول مسار هو {{ code }}. لا تشارك هذا الرمز.',
|
||||
'whatsapp_body_en': 'Your Masar Login Code is {{ code }}. Do not share this code.',
|
||||
'whatsapp_body_ar': 'رمز دخول مسار هو {{ code }}. لا تشارك هذا الرمز.',
|
||||
},
|
||||
'otp_profile_update': {
|
||||
'description': 'Sent when updating profile sensitive info',
|
||||
'variables': '{{ code }}',
|
||||
'subject_en': 'Verification Code',
|
||||
'subject_ar': 'رمز التحقق',
|
||||
'email_body_en': 'Your Masar Update Code is {{ code }}',
|
||||
'email_body_ar': 'رمز التحديث الخاص بك هو {{ code }}',
|
||||
'whatsapp_body_en': 'Your Masar Update Code is {{ code }}',
|
||||
'whatsapp_body_ar': 'رمز التحديث الخاص بك هو {{ code }}',
|
||||
},
|
||||
'shipment_created_shipper': {
|
||||
'description': 'Sent to Shipper when they create a shipment',
|
||||
'variables': '{{ name }}, {{ description }}, {{ tracking_number }}, {{ status }}',
|
||||
'subject_en': 'Shipment Request Received - {{ tracking_number }}',
|
||||
'subject_ar': 'تم استلام طلب الشحنة - {{ tracking_number }}',
|
||||
'email_body_en': "Hello {{ name }},\n\nYour shipment request for '{{ description }}' has been received.\nTracking Number: {{ tracking_number }}\nStatus: {{ status }}\n\nPlease proceed to payment to make it visible to drivers.",
|
||||
'email_body_ar': "مرحباً {{ name }}،\n\nتم استلام طلب الشحنة '{{ description }}'.\nرقم التتبع: {{ tracking_number }}\nالحالة: {{ status }}\n\nيرجى متابعة الدفع لجعلها مرئية للسائقين.",
|
||||
'whatsapp_body_en': "Hello {{ name }},\nYour shipment request for '{{ description }}' has been received.\nTracking Number: {{ tracking_number }}\nStatus: {{ status }}\nPlease proceed to payment.",
|
||||
'whatsapp_body_ar': "مرحباً {{ name }}،\nتم استلام طلب الشحنة '{{ description }}'.\nرقم التتبع: {{ tracking_number }}\nالحالة: {{ status }}\nيرجى الدفع.",
|
||||
},
|
||||
'payment_success_shipper': {
|
||||
'description': 'Sent to Shipper after payment',
|
||||
'variables': '{{ tracking_number }}',
|
||||
'subject_en': 'Payment Successful - {{ tracking_number }}',
|
||||
'subject_ar': 'تم الدفع بنجاح - {{ tracking_number }}',
|
||||
'email_body_en': 'Payment successful for shipment {{ tracking_number }}.\nYour shipment is now visible to available drivers.',
|
||||
'email_body_ar': 'تم الدفع بنجاح للشحنة {{ tracking_number }}.\nشحنتك الآن مرئية للسائقين المتاحين.',
|
||||
'whatsapp_body_en': 'Payment successful for shipment {{ tracking_number }}.\nYour shipment is now visible to available drivers.',
|
||||
'whatsapp_body_ar': 'تم الدفع بنجاح للشحنة {{ tracking_number }}.\nشحنتك الآن مرئية للسائقين المتاحين.',
|
||||
},
|
||||
'shipment_visible_receiver': {
|
||||
'description': 'Sent to Receiver when shipment is paid/ready',
|
||||
'variables': '{{ receiver_name }}, {{ shipper_name }}, {{ tracking_number }}, {{ status }}',
|
||||
'subject_en': 'Incoming Shipment - {{ tracking_number }}',
|
||||
'subject_ar': 'شحنة واردة - {{ tracking_number }}',
|
||||
'email_body_en': 'Hello {{ receiver_name }},\n\nA shipment is coming your way from {{ shipper_name }}.\nTracking Number: {{ tracking_number }}\nStatus: {{ status }}',
|
||||
'email_body_ar': 'مرحباً {{ receiver_name }}،\n\nشحنة قادمة إليك من {{ shipper_name }}.\nرقم التتبع: {{ tracking_number }}\nالحالة: {{ status }}',
|
||||
'whatsapp_body_en': 'Hello {{ receiver_name }},\nA shipment is coming your way from {{ shipper_name }}.\nTracking Number: {{ tracking_number }}\nStatus: {{ status }}',
|
||||
'whatsapp_body_ar': 'مرحباً {{ receiver_name }}،\nشحنة قادمة إليك من {{ shipper_name }}.\nرقم التتبع: {{ tracking_number }}\nالحالة: {{ status }}',
|
||||
},
|
||||
'driver_pickup_shipper': {
|
||||
'description': 'Sent to Shipper when driver picks up',
|
||||
'variables': '{{ tracking_number }}, {{ driver_name }}, {{ car_plate_number }}, {{ status }}',
|
||||
'subject_en': 'Driver Assigned - {{ tracking_number }}',
|
||||
'subject_ar': 'تم تعيين سائق - {{ tracking_number }}',
|
||||
'email_body_en': 'Shipment {{ tracking_number }} has been picked up by {{ driver_name }}.\nCar Plate: {{ car_plate_number }}\nStatus: {{ status }}',
|
||||
'email_body_ar': 'الشحنة {{ tracking_number }} تم استلامها بواسطة {{ driver_name }}.\nرقم اللوحة: {{ car_plate_number }}\nالحالة: {{ status }}',
|
||||
'whatsapp_body_en': 'Shipment {{ tracking_number }} has been picked up by {{ driver_name }}.\nCar Plate: {{ car_plate_number }}\nStatus: {{ status }}',
|
||||
'whatsapp_body_ar': 'الشحنة {{ tracking_number }} تم استلامها بواسطة {{ driver_name }}.\nرقم اللوحة: {{ car_plate_number }}\nالحالة: {{ status }}',
|
||||
},
|
||||
'driver_pickup_receiver': {
|
||||
'description': 'Sent to Receiver when driver picks up',
|
||||
'variables': '{{ tracking_number }}, {{ shipper_name }}, {{ driver_name }}, {{ car_plate_number }}',
|
||||
'subject_en': 'Shipment On The Way - {{ tracking_number }}',
|
||||
'subject_ar': 'الشحنة في الطريق - {{ tracking_number }}',
|
||||
'email_body_en': 'Shipment {{ tracking_number }} from {{ shipper_name }} is on the way (Picked up).\nDriver: {{ driver_name }}\nCar Plate: {{ car_plate_number }}',
|
||||
'email_body_ar': 'الشحنة {{ tracking_number }} من {{ shipper_name }} في الطريق (تم الاستلام).\nالسائق: {{ driver_name }}\nرقم اللوحة: {{ car_plate_number }}',
|
||||
'whatsapp_body_en': 'Shipment {{ tracking_number }} from {{ shipper_name }} is on the way (Picked up).\nDriver: {{ driver_name }}\nCar Plate: {{ car_plate_number }}',
|
||||
'whatsapp_body_ar': 'الشحنة {{ tracking_number }} من {{ shipper_name }} في الطريق (تم الاستلام).\nالسائق: {{ driver_name }}\nرقم اللوحة: {{ car_plate_number }}',
|
||||
},
|
||||
'driver_pickup_driver': {
|
||||
'description': 'Sent to Driver upon acceptance',
|
||||
'variables': '{{ tracking_number }}, {{ shipper_name }}, {{ pickup_address }}, {{ delivery_address }}, {{ price }}',
|
||||
'subject_en': 'Shipment Accepted - {{ tracking_number }}',
|
||||
'subject_ar': 'تم قبول الشحنة - {{ tracking_number }}',
|
||||
'email_body_en': 'You have successfully accepted Shipment {{ tracking_number }}.\nShipper: {{ shipper_name }}\nPickup: {{ pickup_address }}\nDelivery: {{ delivery_address }}\nPrice: {{ price }} OMR',
|
||||
'email_body_ar': 'لقد قبلت الشحنة {{ tracking_number }} بنجاح.\nالشاحن: {{ shipper_name }}\nالاستلام: {{ pickup_address }}\nالتوصيل: {{ delivery_address }}\nالسعر: {{ price }} ر.ع',
|
||||
'whatsapp_body_en': 'You have successfully accepted Shipment {{ tracking_number }}.\nShipper: {{ shipper_name }}\nPickup: {{ pickup_address }}\nDelivery: {{ delivery_address }}\nPrice/Bid: {{ price }} OMR',
|
||||
'whatsapp_body_ar': 'لقد قبلت الشحنة {{ tracking_number }} بنجاح.\nالشاحن: {{ shipper_name }}\nالاستلام: {{ pickup_address }}\nالتوصيل: {{ delivery_address }}\nالسعر: {{ price }} ر.ع',
|
||||
},
|
||||
'shipment_status_update': {
|
||||
'description': 'Sent on general status change (In Transit, Delivered)',
|
||||
'variables': '{{ tracking_number }}, {{ status }}',
|
||||
'subject_en': 'Shipment Update - {{ tracking_number }}',
|
||||
'subject_ar': 'تحديث الشحنة - {{ tracking_number }}',
|
||||
'email_body_en': 'Update for shipment {{ tracking_number }}:\nNew Status: {{ status }}',
|
||||
'email_body_ar': 'تحديث للشحنة {{ tracking_number }}:\nالحالة الجديدة: {{ status }}',
|
||||
'whatsapp_body_en': 'Update for shipment {{ tracking_number }}:\nNew Status: {{ status }}',
|
||||
'whatsapp_body_ar': 'تحديث للشحنة {{ tracking_number }}:\nالحالة الجديدة: {{ status }}',
|
||||
},
|
||||
'admin_alert_driver_accept': {
|
||||
'description': 'Sent to Admin when driver accepts shipment',
|
||||
'variables': '{{ driver_name }}, {{ car_plate_number }}, {{ tracking_number }}, {{ shipper_name }}, {{ price }}',
|
||||
'subject_en': 'Shipment Accepted ({{ tracking_number }})',
|
||||
'subject_ar': 'تم قبول الشحنة ({{ tracking_number }})',
|
||||
'email_body_en': 'Driver {{ driver_name }} ({{ car_plate_number }}) accepted shipment {{ tracking_number }} from {{ shipper_name }}.\nPrice: {{ price }} OMR',
|
||||
'email_body_ar': 'قام السائق {{ driver_name }} ({{ car_plate_number }}) بقبول الشحنة {{ tracking_number }} من {{ shipper_name }}.\nالسعر: {{ price }} ر.ع',
|
||||
'whatsapp_body_en': 'Driver {{ driver_name }} ({{ car_plate_number }}) accepted shipment {{ tracking_number }} from {{ shipper_name }}.\nPrice: {{ price }} OMR',
|
||||
'whatsapp_body_ar': 'قام السائق {{ driver_name }} ({{ car_plate_number }}) بقبول الشحنة {{ tracking_number }} من {{ shipper_name }}.\nالسعر: {{ price }} ر.ع',
|
||||
},
|
||||
'contact_form_admin': {
|
||||
'description': 'Sent to Admin when contact form is submitted',
|
||||
'variables': '{{ name }}, {{ email }}, {{ message }}',
|
||||
'subject_en': 'New Contact Message from {{ name }}',
|
||||
'subject_ar': 'رسالة جديدة من {{ name }}',
|
||||
'email_body_en': 'You have received a new message from your website contact form.\n\nName: {{ name }}\nEmail: {{ email }}\n\nMessage:\n{{ message }}',
|
||||
'email_body_ar': 'لقد تلقيت رسالة جديدة من نموذج الاتصال.\n\nالاسم: {{ name }}\nالبريد: {{ email }}\n\nالرسالة:\n{{ message }}',
|
||||
'whatsapp_body_en': 'New Message from {{ name }}:\n{{ message }}',
|
||||
'whatsapp_body_ar': 'رسالة جديدة من {{ name }}:\n{{ message }}',
|
||||
}
|
||||
}
|
||||
|
||||
def get_notification_content(key, context, language=None):
|
||||
if not language:
|
||||
language = get_language() or 'en'
|
||||
|
||||
# 1. Fetch or Create Template
|
||||
try:
|
||||
template_obj = NotificationTemplate.objects.get(key=key)
|
||||
except NotificationTemplate.DoesNotExist:
|
||||
# Create default
|
||||
default = DEFAULT_TEMPLATES.get(key)
|
||||
if default:
|
||||
template_obj = NotificationTemplate.objects.create(
|
||||
key=key,
|
||||
description=default.get('description', ''),
|
||||
available_variables=default.get('variables', ''),
|
||||
subject_en=default.get('subject_en', ''),
|
||||
subject_ar=default.get('subject_ar', ''),
|
||||
email_body_en=default.get('email_body_en', ''),
|
||||
email_body_ar=default.get('email_body_ar', ''),
|
||||
whatsapp_body_en=default.get('whatsapp_body_en', ''),
|
||||
whatsapp_body_ar=default.get('whatsapp_body_ar', ''),
|
||||
)
|
||||
else:
|
||||
# Fallback if key unknown
|
||||
return f"[{key}] Subject", f"[{key}] Body", f"[{key}] WA"
|
||||
|
||||
# 2. Select Language Fields
|
||||
# Note: If translation is missing, fallback to EN
|
||||
if language == 'ar':
|
||||
subject = template_obj.subject_ar or template_obj.subject_en
|
||||
email_body = template_obj.email_body_ar or template_obj.email_body_en
|
||||
whatsapp_body = template_obj.whatsapp_body_ar or template_obj.whatsapp_body_en
|
||||
else:
|
||||
subject = template_obj.subject_en
|
||||
email_body = template_obj.email_body_en
|
||||
whatsapp_body = template_obj.whatsapp_body_en
|
||||
|
||||
# 3. Render
|
||||
# Use Django Template engine for variable substitution
|
||||
|
||||
def render(text, ctx):
|
||||
if not text: return ""
|
||||
try:
|
||||
# Convert context to dict if it isn't already
|
||||
if not isinstance(ctx, dict):
|
||||
ctx = {}
|
||||
t = Template(text)
|
||||
return t.render(Context(ctx))
|
||||
except Exception as e:
|
||||
logger.error(f"Template rendering error for {key}: {e}")
|
||||
return text
|
||||
|
||||
return render(subject, context), render(email_body, context), render(whatsapp_body, context)
|
||||
@ -20,6 +20,7 @@ from django.db.models import Avg, Count
|
||||
from django.template.loader import render_to_string
|
||||
import random
|
||||
import string
|
||||
from .notifications import get_notification_content
|
||||
from .whatsapp_utils import (
|
||||
notify_shipment_created,
|
||||
notify_payment_received,
|
||||
@ -100,16 +101,16 @@ def register_shipper(request):
|
||||
|
||||
# Send OTP
|
||||
method = form.cleaned_data.get('verification_method', 'email')
|
||||
otp_msg = _("Your Masar Verification Code is %(code)s") % {'code': code}
|
||||
subj, email_msg, wa_msg = get_notification_content('otp_registration', {'code': code}, language=get_language())
|
||||
|
||||
if method == 'whatsapp':
|
||||
phone = user.profile.phone_number
|
||||
send_whatsapp_message(phone, otp_msg)
|
||||
send_whatsapp_message(phone, wa_msg)
|
||||
messages.info(request, _("Verification code sent to WhatsApp."))
|
||||
else:
|
||||
send_html_email(
|
||||
subject=_('Verification Code'),
|
||||
message=otp_msg,
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=[user.email],
|
||||
title=_('Welcome to Masar!'),
|
||||
request=request
|
||||
@ -143,16 +144,16 @@ def register_driver(request):
|
||||
|
||||
# Send OTP
|
||||
method = form.cleaned_data.get('verification_method', 'email')
|
||||
otp_msg = _("Your Masar Verification Code is %(code)s") % {'code': code}
|
||||
subj, email_msg, wa_msg = get_notification_content('otp_registration', {'code': code}, language=get_language())
|
||||
|
||||
if method == 'whatsapp':
|
||||
phone = user.profile.phone_number
|
||||
send_whatsapp_message(phone, otp_msg)
|
||||
send_whatsapp_message(phone, wa_msg)
|
||||
messages.info(request, _("Verification code sent to WhatsApp."))
|
||||
else:
|
||||
send_html_email(
|
||||
subject=_('Verification Code'),
|
||||
message=otp_msg,
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=[user.email],
|
||||
title=_('Welcome to Masar!'),
|
||||
request=request
|
||||
@ -489,22 +490,22 @@ def edit_profile(request):
|
||||
|
||||
# 4. Send OTP
|
||||
method = data.get('otp_method', 'email')
|
||||
otp_msg = _("Your Masar Update Code is %(code)s") % {'code': code}
|
||||
subj, email_msg, wa_msg = get_notification_content('otp_profile_update', {'code': code}, language=get_language())
|
||||
|
||||
if method == 'whatsapp':
|
||||
# Use current phone if available, else new phone
|
||||
phone = request.user.profile.phone_number or data['phone_number']
|
||||
send_whatsapp_message(phone, otp_msg)
|
||||
send_whatsapp_message(phone, wa_msg)
|
||||
messages.info(request, _("Verification code sent to WhatsApp."))
|
||||
else:
|
||||
# Default to email
|
||||
# Send to the NEW email address (from the form), not the old one
|
||||
target_email = data['email']
|
||||
send_html_email(
|
||||
subject=_('Verification Code'),
|
||||
message=otp_msg,
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=[target_email],
|
||||
title=_('Profile Update Verification'),
|
||||
title=subj,
|
||||
request=request
|
||||
)
|
||||
messages.info(request, _("Verification code sent to email."))
|
||||
@ -641,20 +642,21 @@ def request_login_otp(request):
|
||||
|
||||
# Generate OTP
|
||||
code = ''.join(random.choices(string.digits, k=6))
|
||||
subj, email_msg, wa_msg = get_notification_content('otp_login', {'code': code}, language=get_language())
|
||||
OTPVerification.objects.create(user=user, code=code, purpose='login')
|
||||
|
||||
# Send OTP
|
||||
otp_msg = _("Your Masar Login Code is %(code)s. Do not share this code.") % {'code': code}
|
||||
subj, email_msg, wa_msg = get_notification_content('otp_login', {'code': code}, language=get_language())
|
||||
|
||||
try:
|
||||
if method == 'whatsapp':
|
||||
phone = user.profile.phone_number
|
||||
send_whatsapp_message(phone, otp_msg)
|
||||
send_whatsapp_message(phone, wa_msg)
|
||||
message_sent = _("OTP sent to your WhatsApp.")
|
||||
else:
|
||||
send_html_email(
|
||||
subject=_('Login OTP'),
|
||||
message=otp_msg,
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=[user.email],
|
||||
title=_('Login Verification'),
|
||||
request=request
|
||||
@ -983,6 +985,7 @@ def select_2fa_method(request):
|
||||
if request.method == 'POST':
|
||||
method = request.POST.get('method')
|
||||
code = ''.join(random.choices(string.digits, k=6))
|
||||
subj, email_msg, wa_msg = get_notification_content('otp_login', {'code': code}, language=get_language())
|
||||
|
||||
# Invalidate old login OTPs
|
||||
OTPVerification.objects.filter(user=user, purpose='login').delete()
|
||||
@ -993,7 +996,7 @@ def select_2fa_method(request):
|
||||
try:
|
||||
send_html_email(
|
||||
subject=_("Your Login OTP"),
|
||||
message=f"Your verification code is: {code}",
|
||||
message=email_msg,
|
||||
recipient_list=[user.email],
|
||||
title=_("Login Verification")
|
||||
)
|
||||
@ -1006,7 +1009,7 @@ def select_2fa_method(request):
|
||||
|
||||
elif method == 'whatsapp':
|
||||
if hasattr(user, 'profile') and user.profile.phone_number:
|
||||
if send_whatsapp_message(user.profile.phone_number, f"Your login verification code is: {code}"):
|
||||
if send_whatsapp_message(user.profile.phone_number, wa_msg):
|
||||
messages.success(request, _("OTP sent to your WhatsApp."))
|
||||
return redirect('verify_2fa_otp')
|
||||
else:
|
||||
|
||||
@ -6,6 +6,7 @@ from django.core.mail import send_mail
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from .models import PlatformProfile
|
||||
from .mail import send_html_email
|
||||
from .notifications import get_notification_content
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -16,7 +17,6 @@ def get_whatsapp_credentials():
|
||||
"""
|
||||
# Defaults
|
||||
api_token = settings.WHATSAPP_API_KEY if hasattr(settings, 'WHATSAPP_API_KEY') else ""
|
||||
# We repurpose Phone ID as Domain in settings if needed, or default to Wablas DEU
|
||||
domain = "https://deu.wablas.com"
|
||||
secret_key = ""
|
||||
source = "Settings/Env"
|
||||
@ -25,19 +25,15 @@ def get_whatsapp_credentials():
|
||||
try:
|
||||
profile = PlatformProfile.objects.first()
|
||||
if profile:
|
||||
# Check for token override
|
||||
if profile.whatsapp_access_token:
|
||||
api_token = profile.whatsapp_access_token.strip()
|
||||
source = "Database (PlatformProfile)"
|
||||
|
||||
# Check for secret key override
|
||||
if profile.whatsapp_app_secret:
|
||||
secret_key = profile.whatsapp_app_secret.strip()
|
||||
|
||||
# Check for domain override
|
||||
if profile.whatsapp_business_phone_number_id:
|
||||
domain = profile.whatsapp_business_phone_number_id.strip()
|
||||
# Ensure no trailing slash
|
||||
if domain.endswith('/'):
|
||||
domain = domain[:-1]
|
||||
|
||||
@ -71,28 +67,21 @@ def send_whatsapp_message_detailed(phone_number, message):
|
||||
logger.warning(msg)
|
||||
return False, msg
|
||||
|
||||
# Normalize phone number (Wablas expects international format without +, e.g. 628123...)
|
||||
clean_phone = str(phone_number).replace('+', '').replace(' ', '')
|
||||
|
||||
# Endpoint: /api/send-message (Simple Text)
|
||||
# Ensure domain has schema
|
||||
if not domain.startswith('http'):
|
||||
domain = f"https://{domain}"
|
||||
|
||||
# Using the exact endpoint provided in user example
|
||||
url = f"{domain}/api/send-message"
|
||||
|
||||
# Header construction logic from user example
|
||||
auth_header = api_token
|
||||
if secret_key:
|
||||
auth_header = f"{api_token}.{secret_key}"
|
||||
|
||||
headers = {
|
||||
"Authorization": auth_header,
|
||||
# requests will set Content-Type to application/x-www-form-urlencoded when using 'data' param
|
||||
}
|
||||
|
||||
# Payload as form data (not JSON)
|
||||
data = {
|
||||
"phone": clean_phone,
|
||||
"message": message,
|
||||
@ -100,18 +89,14 @@ def send_whatsapp_message_detailed(phone_number, message):
|
||||
|
||||
try:
|
||||
logger.info(f"Attempting to send WhatsApp message to {clean_phone} via {url}")
|
||||
# Use data=data for form-urlencoded
|
||||
response = requests.post(url, headers=headers, data=data, timeout=15)
|
||||
|
||||
# Handle non-JSON response (HTML error pages)
|
||||
try:
|
||||
response_data = response.json()
|
||||
except ValueError:
|
||||
response_data = response.text
|
||||
|
||||
# Wablas success usually has status: true
|
||||
if response.status_code == 200:
|
||||
# Check for logical success in JSON
|
||||
if isinstance(response_data, dict):
|
||||
if response_data.get('status') is True:
|
||||
logger.info(f"WhatsApp message sent to {clean_phone} via Wablas")
|
||||
@ -119,7 +104,6 @@ def send_whatsapp_message_detailed(phone_number, message):
|
||||
else:
|
||||
return False, f"Wablas API Logic Error (Source: {source}): {response_data}"
|
||||
else:
|
||||
# If text, assume success if 200 OK? Or inspect text.
|
||||
return True, f"Message sent (Raw Response). (Source: {source})"
|
||||
else:
|
||||
error_msg = f"Wablas API error (Source: {source}): {response.status_code} - {response_data}"
|
||||
@ -130,14 +114,19 @@ def send_whatsapp_message_detailed(phone_number, message):
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
def notify_admin(subject, message):
|
||||
"""Notifies the admin via Email and WhatsApp (if configured in PlatformProfile)."""
|
||||
def notify_admin_alert(key, context):
|
||||
"""Notifies the admin via Email and WhatsApp using a template key."""
|
||||
# 1. Get Template Content (Admin likely prefers EN, or system default?)
|
||||
# Let's force EN for admin alerts for now, or check generic language setting?
|
||||
# Usually admin alerts are in EN or the default site language.
|
||||
subject, email_body, whatsapp_body = get_notification_content(key, context, language='en')
|
||||
|
||||
# Email
|
||||
try:
|
||||
if hasattr(settings, 'CONTACT_EMAIL_TO') and settings.CONTACT_EMAIL_TO:
|
||||
send_html_email(
|
||||
subject=f"Admin Alert: {subject}",
|
||||
message=message,
|
||||
message=email_body,
|
||||
recipient_list=settings.CONTACT_EMAIL_TO,
|
||||
title="Admin Alert"
|
||||
)
|
||||
@ -148,146 +137,141 @@ def notify_admin(subject, message):
|
||||
try:
|
||||
profile = PlatformProfile.objects.first()
|
||||
if profile and profile.phone_number:
|
||||
# Assuming profile.phone_number is a valid WhatsApp number for Admin alerts
|
||||
send_whatsapp_message(profile.phone_number, f"ADMIN ALERT: {subject}\n{message}")
|
||||
send_whatsapp_message(profile.phone_number, f"ADMIN ALERT: {subject}\n{whatsapp_body}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def notify_shipment_created(parcel):
|
||||
"""Notifies the shipper that the shipment request was received via WhatsApp and Email."""
|
||||
shipper_name = parcel.shipper.get_full_name() or parcel.shipper.username
|
||||
message = f"""Hello {shipper_name},
|
||||
|
||||
Your shipment request for '{parcel.description}' has been received.
|
||||
Tracking Number: {parcel.tracking_number}
|
||||
Status: {parcel.get_status_display()}
|
||||
|
||||
Please proceed to payment to make it visible to drivers."""
|
||||
context = {
|
||||
'name': shipper_name,
|
||||
'description': parcel.description,
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'status': parcel.get_status_display()
|
||||
}
|
||||
|
||||
# Render for Shipper (check user language preference? For now assume session/request unavailable so maybe default or EN,
|
||||
# OR we need a user language profile field. The user didn't ask for user-pref language yet, just bilingual templates.
|
||||
# I'll default to EN unless I can guess.)
|
||||
# Actually, if I can't determine, EN is safe.
|
||||
# Future improvement: Add language to User Profile.
|
||||
|
||||
subj, email_msg, wa_msg = get_notification_content('shipment_created_shipper', context)
|
||||
|
||||
# WhatsApp
|
||||
if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, message)
|
||||
else:
|
||||
logger.warning(f"No phone number found for shipper {shipper_name}, skipping WhatsApp.")
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, wa_msg)
|
||||
|
||||
# Email
|
||||
if parcel.shipper.email:
|
||||
try:
|
||||
send_html_email(
|
||||
subject='Shipment Request Received - ' + parcel.tracking_number,
|
||||
message=message,
|
||||
recipient_list=[parcel.shipper.email],
|
||||
title='Shipment Request Received'
|
||||
)
|
||||
logger.info(f"Shipment created email sent to {parcel.shipper.email}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send shipment created email to {parcel.shipper.email}: {e}")
|
||||
|
||||
send_html_email(
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=[parcel.shipper.email],
|
||||
title=subj
|
||||
)
|
||||
return True
|
||||
|
||||
def notify_payment_received(parcel):
|
||||
"""Notifies the shipper and receiver about successful payment via WhatsApp and Email."""
|
||||
# Notify Shipper
|
||||
# Shipper
|
||||
shipper_name = parcel.shipper.get_full_name() or parcel.shipper.username
|
||||
shipper_msg = f"""Payment successful for shipment {parcel.tracking_number}.
|
||||
Your shipment is now visible to available drivers."""
|
||||
context_shipper = {
|
||||
'tracking_number': parcel.tracking_number
|
||||
}
|
||||
subj, email_msg, wa_msg = get_notification_content('payment_success_shipper', context_shipper)
|
||||
|
||||
# WhatsApp Shipper
|
||||
if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, shipper_msg)
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, wa_msg)
|
||||
|
||||
# Email Shipper
|
||||
if parcel.shipper.email:
|
||||
try:
|
||||
send_html_email(
|
||||
subject='Payment Successful - ' + parcel.tracking_number,
|
||||
message=shipper_msg,
|
||||
recipient_list=[parcel.shipper.email],
|
||||
title='Payment Successful'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send payment email to {parcel.shipper.email}: {e}")
|
||||
send_html_email(
|
||||
subject=subj,
|
||||
message=email_msg,
|
||||
recipient_list=[parcel.shipper.email],
|
||||
title=subj
|
||||
)
|
||||
|
||||
# Notify Receiver
|
||||
receiver_msg = f"""Hello {parcel.receiver_name},
|
||||
|
||||
A shipment is coming your way from {shipper_name}.
|
||||
Tracking Number: {parcel.tracking_number}
|
||||
Status: {parcel.get_status_display()}"""
|
||||
send_whatsapp_message(parcel.receiver_phone, receiver_msg)
|
||||
# Receiver
|
||||
context_receiver = {
|
||||
'receiver_name': parcel.receiver_name,
|
||||
'shipper_name': shipper_name,
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'status': parcel.get_status_display()
|
||||
}
|
||||
_, _, wa_msg_rx = get_notification_content('shipment_visible_receiver', context_receiver)
|
||||
send_whatsapp_message(parcel.receiver_phone, wa_msg_rx)
|
||||
|
||||
def notify_driver_assigned(parcel):
|
||||
"""Notifies the shipper, receiver, driver, and admin that a driver has picked up the parcel."""
|
||||
driver_name = parcel.carrier.get_full_name() or parcel.carrier.username
|
||||
shipper_name = parcel.shipper.get_full_name() or parcel.shipper.username
|
||||
|
||||
# Get Car Plate
|
||||
car_plate = ""
|
||||
if hasattr(parcel.carrier, 'profile'):
|
||||
car_plate = parcel.carrier.profile.car_plate_number
|
||||
|
||||
# 1. Notify Shipper
|
||||
msg_shipper = f"""Shipment {parcel.tracking_number} has been picked up by {driver_name}.
|
||||
Status: {parcel.get_status_display()}"""
|
||||
context_shipper = {
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'driver_name': driver_name,
|
||||
'car_plate_number': car_plate,
|
||||
'status': parcel.get_status_display()
|
||||
}
|
||||
subj_s, email_s, wa_s = get_notification_content('driver_pickup_shipper', context_shipper)
|
||||
|
||||
if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, msg_shipper)
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, wa_s)
|
||||
|
||||
if parcel.shipper.email:
|
||||
try:
|
||||
send_html_email(
|
||||
subject='Driver Assigned - ' + parcel.tracking_number,
|
||||
message=msg_shipper,
|
||||
recipient_list=[parcel.shipper.email],
|
||||
title='Driver Assigned'
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
send_html_email(subject=subj_s, message=email_s, recipient_list=[parcel.shipper.email], title=subj_s)
|
||||
|
||||
# 2. Notify Receiver
|
||||
msg_receiver = f"""Shipment {parcel.tracking_number} from {shipper_name} is on the way (Picked up).
|
||||
Driver: {driver_name}"""
|
||||
send_whatsapp_message(parcel.receiver_phone, msg_receiver)
|
||||
context_receiver = {
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'shipper_name': shipper_name,
|
||||
'driver_name': driver_name,
|
||||
'car_plate_number': car_plate
|
||||
}
|
||||
_, _, wa_r = get_notification_content('driver_pickup_receiver', context_receiver)
|
||||
send_whatsapp_message(parcel.receiver_phone, wa_r)
|
||||
|
||||
# 3. Notify Driver (Confirmation)
|
||||
msg_driver = f"""You have successfully accepted Shipment {parcel.tracking_number}.
|
||||
Shipper: {shipper_name}
|
||||
Pickup: {parcel.pickup_address}
|
||||
Delivery: {parcel.delivery_address}
|
||||
Price/Bid: {parcel.price} OMR"""
|
||||
# 3. Notify Driver
|
||||
context_driver = {
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'shipper_name': shipper_name,
|
||||
'pickup_address': parcel.pickup_address,
|
||||
'delivery_address': parcel.delivery_address,
|
||||
'price': parcel.price
|
||||
}
|
||||
subj_d, email_d, wa_d = get_notification_content('driver_pickup_driver', context_driver)
|
||||
|
||||
if hasattr(parcel.carrier, 'profile') and parcel.carrier.profile.phone_number:
|
||||
send_whatsapp_message(parcel.carrier.profile.phone_number, msg_driver)
|
||||
send_whatsapp_message(parcel.carrier.profile.phone_number, wa_d)
|
||||
|
||||
if parcel.carrier.email:
|
||||
try:
|
||||
send_html_email(
|
||||
subject='Shipment Accepted - ' + parcel.tracking_number,
|
||||
message=msg_driver,
|
||||
recipient_list=[parcel.carrier.email],
|
||||
title='Shipment Accepted'
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
send_html_email(subject=subj_d, message=email_d, recipient_list=[parcel.carrier.email], title=subj_d)
|
||||
|
||||
# 4. Notify Admin
|
||||
notify_admin(
|
||||
subject=f"Shipment Accepted ({parcel.tracking_number})",
|
||||
message=f"Driver {driver_name} accepted shipment {parcel.tracking_number} from {shipper_name}.\nPrice: {parcel.price} OMR"
|
||||
)
|
||||
context_admin = {
|
||||
'driver_name': driver_name,
|
||||
'car_plate_number': car_plate,
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'shipper_name': shipper_name,
|
||||
'price': parcel.price
|
||||
}
|
||||
notify_admin_alert('admin_alert_driver_accept', context_admin)
|
||||
|
||||
def notify_status_change(parcel):
|
||||
"""Notifies parties about general status updates (In Transit, Delivered)."""
|
||||
msg = f"""Update for shipment {parcel.tracking_number}:
|
||||
New Status: {parcel.get_status_display()}"""
|
||||
context = {
|
||||
'tracking_number': parcel.tracking_number,
|
||||
'status': parcel.get_status_display()
|
||||
}
|
||||
subj, email_msg, wa_msg = get_notification_content('shipment_status_update', context)
|
||||
|
||||
if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, msg)
|
||||
send_whatsapp_message(parcel.shipper.profile.phone_number, wa_msg)
|
||||
|
||||
if parcel.shipper.email:
|
||||
try:
|
||||
send_html_email(
|
||||
subject='Shipment Update - ' + parcel.tracking_number,
|
||||
message=msg,
|
||||
recipient_list=[parcel.shipper.email],
|
||||
title='Shipment Update'
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
send_html_email(subject=subj, message=email_msg, recipient_list=[parcel.shipper.email], title=subj)
|
||||
|
||||
send_whatsapp_message(parcel.receiver_phone, msg)
|
||||
send_whatsapp_message(parcel.receiver_phone, wa_msg)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user