adding whats config

This commit is contained in:
Flatlogic Bot 2026-01-25 12:05:49 +00:00
parent 0bccc28caf
commit 1e836a1d9d
9 changed files with 87 additions and 12 deletions

View File

@ -34,9 +34,24 @@ class ParcelAdmin(admin.ModelAdmin):
@admin.register(PlatformProfile) @admin.register(PlatformProfile)
class PlatformProfileAdmin(admin.ModelAdmin): class PlatformProfileAdmin(admin.ModelAdmin):
list_display = ('name', 'phone_number', 'registration_number') list_display = ('name', 'phone_number', 'registration_number')
fieldsets = (
(None, {
'fields': ('name', 'logo', 'slogan')
}),
('Contact Information', {
'fields': ('address', 'phone_number', 'registration_number', 'vat_number')
}),
('Legal', {
'fields': ('privacy_policy', 'terms_conditions')
}),
('WhatsApp Configuration', {
'fields': ('whatsapp_access_token', 'whatsapp_business_phone_number_id'),
'description': 'Enter your Meta WhatsApp Business API credentials here. These will override the system defaults.'
}),
)
def has_add_permission(self, request): def has_add_permission(self, request):
# Allow adding only if no instance exists # Allow adding only if no instance exists
if self.model.objects.exists(): if self.model.objects.exists():
return False return False
return super().has_add_permission(request) return super().has_add_permission(request)

View File

@ -0,0 +1,23 @@
# Generated by Django 5.2.7 on 2026-01-25 12:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0009_profile_address_profile_profile_picture_and_more'),
]
operations = [
migrations.AddField(
model_name='platformprofile',
name='whatsapp_access_token',
field=models.TextField(blank=True, help_text='Permanent or temporary access token from Meta Business.', verbose_name='WhatsApp Access Token'),
),
migrations.AddField(
model_name='platformprofile',
name='whatsapp_business_phone_number_id',
field=models.CharField(blank=True, help_text='The Phone Number ID from WhatsApp API setup.', max_length=100, verbose_name='WhatsApp Phone Number ID'),
),
]

View File

@ -159,6 +159,10 @@ class PlatformProfile(models.Model):
vat_number = models.CharField(_('VAT Number'), max_length=100, blank=True) vat_number = models.CharField(_('VAT Number'), max_length=100, blank=True)
privacy_policy = models.TextField(_('Privacy Policy'), blank=True) privacy_policy = models.TextField(_('Privacy Policy'), blank=True)
terms_conditions = models.TextField(_('Terms and Conditions'), blank=True) terms_conditions = models.TextField(_('Terms and Conditions'), blank=True)
# WhatsApp Configuration
whatsapp_access_token = models.TextField(_('WhatsApp Access Token'), blank=True, help_text=_("Permanent or temporary access token from Meta Business."))
whatsapp_business_phone_number_id = models.CharField(_('WhatsApp Phone Number ID'), max_length=100, blank=True, help_text=_("The Phone Number ID from WhatsApp API setup."))
def __str__(self): def __str__(self):
return self.name return self.name
@ -180,4 +184,4 @@ class OTPVerification(models.Model):
def is_valid(self): def is_valid(self):
# OTP valid for 10 minutes # OTP valid for 10 minutes
return self.created_at >= timezone.now() - timezone.timedelta(minutes=10) return self.created_at >= timezone.now() - timezone.timedelta(minutes=10)

View File

@ -1,29 +1,54 @@
import requests import requests
import logging import logging
from django.conf import settings from django.conf import settings
from .models import PlatformProfile
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_whatsapp_credentials():
"""
Retrieves WhatsApp credentials from PlatformProfile (preferred) or settings.
Returns tuple: (api_key, phone_id)
"""
# Default to settings
api_key = settings.WHATSAPP_API_KEY
phone_id = settings.WHATSAPP_PHONE_ID
# Try to fetch from PlatformProfile
try:
profile = PlatformProfile.objects.first()
if profile:
if profile.whatsapp_access_token:
api_key = profile.whatsapp_access_token
if profile.whatsapp_business_phone_number_id:
phone_id = profile.whatsapp_business_phone_number_id
except Exception as e:
logger.warning(f"Failed to fetch PlatformProfile for WhatsApp config: {e}")
return api_key, phone_id
def send_whatsapp_message(phone_number, message): def send_whatsapp_message(phone_number, message):
""" """
Sends a WhatsApp message using the configured gateway. Sends a WhatsApp message using the configured gateway.
This implementation assumes Meta WhatsApp Business API (Graph API). This implementation assumes Meta WhatsApp Business API (Graph API).
""" """
if not settings.WHATSAPP_ENABLED: if not settings.WHATSAPP_ENABLED:
logger.info("WhatsApp notifications are disabled.") logger.info("WhatsApp notifications are disabled by settings.")
return False return False
if not settings.WHATSAPP_API_KEY or not settings.WHATSAPP_PHONE_ID: api_key, phone_id = get_whatsapp_credentials()
logger.warning("WhatsApp API configuration is missing.")
if not api_key or not phone_id:
logger.warning("WhatsApp API configuration is missing (checked PlatformProfile and settings).")
return False return False
# Normalize phone number (ensure it has country code and no +) # Normalize phone number (ensure it has country code and no +)
clean_phone = "".join(filter(str.isdigit, str(phone_number))) clean_phone = "".join(filter(str.isdigit, str(phone_number)))
url = f"https://graph.facebook.com/v17.0/{settings.WHATSAPP_PHONE_ID}/messages" url = f"https://graph.facebook.com/v17.0/{phone_id}/messages"
headers = { headers = {
"Authorization": f"Bearer {settings.WHATSAPP_API_KEY}", "Authorization": f"Bearer {api_key}",
"Content-Type": "application/json", "Content-Type": "application/json",
} }
@ -58,7 +83,9 @@ Tracking Number: {parcel.tracking_number}
Status: {parcel.get_status_display()} Status: {parcel.get_status_display()}
Please proceed to payment to make it visible to drivers.""" Please proceed to payment to make it visible to drivers."""
return send_whatsapp_message(parcel.shipper.profile.phone_number, message) if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
return send_whatsapp_message(parcel.shipper.profile.phone_number, message)
return False
def notify_payment_received(parcel): def notify_payment_received(parcel):
"""Notifies the shipper and receiver about successful payment.""" """Notifies the shipper and receiver about successful payment."""
@ -66,7 +93,9 @@ def notify_payment_received(parcel):
shipper_name = parcel.shipper.get_full_name() or parcel.shipper.username shipper_name = parcel.shipper.get_full_name() or parcel.shipper.username
shipper_msg = f"""Payment successful for shipment {parcel.tracking_number}. shipper_msg = f"""Payment successful for shipment {parcel.tracking_number}.
Your shipment is now visible to available drivers.""" Your shipment is now visible to available drivers."""
send_whatsapp_message(parcel.shipper.profile.phone_number, shipper_msg)
if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
send_whatsapp_message(parcel.shipper.profile.phone_number, shipper_msg)
# Notify Receiver # Notify Receiver
receiver_msg = f"""Hello {parcel.receiver_name}, receiver_msg = f"""Hello {parcel.receiver_name},
@ -81,12 +110,16 @@ def notify_driver_assigned(parcel):
driver_name = parcel.carrier.get_full_name() or parcel.carrier.username driver_name = parcel.carrier.get_full_name() or parcel.carrier.username
msg = f"""Shipment {parcel.tracking_number} has been picked up by {driver_name}. msg = f"""Shipment {parcel.tracking_number} has been picked up by {driver_name}.
Status: {parcel.get_status_display()}""" Status: {parcel.get_status_display()}"""
send_whatsapp_message(parcel.shipper.profile.phone_number, msg)
if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
send_whatsapp_message(parcel.shipper.profile.phone_number, msg)
send_whatsapp_message(parcel.receiver_phone, msg) send_whatsapp_message(parcel.receiver_phone, msg)
def notify_status_change(parcel): def notify_status_change(parcel):
"""Notifies parties about general status updates (In Transit, Delivered).""" """Notifies parties about general status updates (In Transit, Delivered)."""
msg = f"""Update for shipment {parcel.tracking_number}: msg = f"""Update for shipment {parcel.tracking_number}:
New Status: {parcel.get_status_display()}""" New Status: {parcel.get_status_display()}"""
send_whatsapp_message(parcel.shipper.profile.phone_number, msg)
send_whatsapp_message(parcel.receiver_phone, msg) if hasattr(parcel.shipper, 'profile') and parcel.shipper.profile.phone_number:
send_whatsapp_message(parcel.shipper.profile.phone_number, msg)
send_whatsapp_message(parcel.receiver_phone, msg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB