This commit is contained in:
Flatlogic Bot 2026-01-23 12:04:14 +00:00
parent 64a133dbcf
commit 1654496646
11 changed files with 133 additions and 2 deletions

Binary file not shown.

View File

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Profile, Truck, Shipment, Bid, Message
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
@ -28,3 +28,13 @@ class BidAdmin(admin.ModelAdmin):
class MessageAdmin(admin.ModelAdmin):
list_display = ('shipment', 'sender', 'timestamp')
search_fields = ('content', 'sender__username')
@admin.register(WhatsAppConfig)
class WhatsAppConfigAdmin(admin.ModelAdmin):
list_display = ('__str__', 'is_active')
def has_add_permission(self, request):
# Only allow one configuration record
if self.model.objects.exists():
return False
return super().has_add_permission(request)

View File

@ -0,0 +1,26 @@
# Generated by Django 5.2.7 on 2026-01-23 12:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0005_truck_registration_expiry_date'),
]
operations = [
migrations.CreateModel(
name='WhatsAppConfig',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('api_token', models.CharField(max_length=255, verbose_name='Wablas API Token')),
('secret_key', models.CharField(blank=True, max_length=255, null=True, verbose_name='Wablas Secret Key')),
('is_active', models.BooleanField(default=True, verbose_name='Is Active')),
],
options={
'verbose_name': 'WhatsApp Configuration',
'verbose_name_plural': 'WhatsApp Configuration',
},
),
]

View File

@ -122,6 +122,18 @@ class Message(models.Model):
def __str__(self):
return f"From {self.sender.username} at {self.timestamp}"
class WhatsAppConfig(models.Model):
api_token = models.CharField(_('Wablas API Token'), max_length=255)
secret_key = models.CharField(_('Wablas Secret Key'), max_length=255, blank=True, null=True)
is_active = models.BooleanField(_('Is Active'), default=True)
class Meta:
verbose_name = _('WhatsApp Configuration')
verbose_name_plural = _('WhatsApp Configuration')
def __str__(self):
return str(_("WhatsApp Configuration"))
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:

View File

@ -8,6 +8,7 @@ from django.contrib import messages
from django.utils.translation import gettext as _
from django.db.models import Q
from django.contrib.auth.models import User
from .whatsapp import send_whatsapp_message
def home(request):
"""Render the landing screen for MASAR CARGO."""
@ -113,6 +114,13 @@ def approve_truck(request, truck_id):
truck = get_object_or_404(Truck, id=truck_id)
truck.is_approved = True
truck.save()
# Notify Truck Owner via WhatsApp
owner_phone = getattr(truck.owner.profile, 'phone_number', None)
if owner_phone:
msg = f"Your truck ({truck.plate_no}) has been approved! You can now place bids on shipments."
send_whatsapp_message(owner_phone, msg)
messages.success(request, _("Truck approved successfully!"))
return redirect('dashboard')
@ -173,6 +181,13 @@ def place_bid(request, shipment_id):
bid.truck_owner = request.user
bid.shipment = shipment
bid.save()
# Notify Shipper via WhatsApp
shipper_phone = getattr(shipment.shipper.profile, 'phone_number', None)
if shipper_phone:
msg = f"New bid placed on your shipment from {shipment.origin} to {shipment.destination}! Amount: {bid.amount}"
send_whatsapp_message(shipper_phone, msg)
messages.success(request, _("Bid placed successfully!"))
return redirect('marketplace')
else:
@ -211,5 +226,11 @@ def accept_bid(request, bid_id):
bid.shipment.assigned_truck = bid.truck
bid.shipment.save()
# Notify Truck Owner via WhatsApp
owner_phone = getattr(bid.truck_owner.profile, 'phone_number', None)
if owner_phone:
msg = f"Congratulations! Your bid for the shipment from {bid.shipment.origin} to {bid.shipment.destination} has been accepted."
send_whatsapp_message(owner_phone, msg)
messages.success(request, _("Bid accepted! Shipment is now in progress."))
return redirect('shipment_detail', shipment_id=bid.shipment.id)
return redirect('shipment_detail', shipment_id=bid.shipment.id)

62
core/whatsapp.py Normal file
View File

@ -0,0 +1,62 @@
import requests
import logging
from django.conf import settings
from .models import WhatsAppConfig
logger = logging.getLogger(__name__)
def send_whatsapp_message(phone, message):
"""
Sends a WhatsApp message using the Wablas API.
"""
try:
config = WhatsAppConfig.objects.filter(is_active=True).first()
except Exception as e:
logger.error(f"Error fetching WhatsApp configuration: {e}")
config = None
if not config or not config.api_token:
# Fallback to settings for backward compatibility or if DB entry is missing
token = getattr(settings, 'WABLAS_API_TOKEN', None)
secret_key = getattr(settings, 'WABLAS_SECRET_KEY', None)
else:
token = config.api_token
secret_key = config.secret_key
if not token:
logger.warning("Wablas API credentials not configured.")
return False
url = "https://deu.wablas.com/api/send-message"
# Headers logic based on whether secret key exists
auth_header = token
if secret_key:
auth_header = f"{token}.{secret_key}"
headers = {
"Authorization": auth_header,
"Content-Type": "application/x-www-form-urlencoded"
}
# Normalize phone number
phone = str(phone).replace('+', '').replace(' ', '')
data = {
"phone": phone,
"message": message,
}
try:
response = requests.post(url, headers=headers, data=data, timeout=10)
response_json = response.json()
if response.status_code == 200 and response_json.get('status') == True:
logger.info(f"WhatsApp message sent to {phone}")
return True
else:
logger.error(f"Failed to send WhatsApp message to {phone}: {response.text}")
return False
except Exception as e:
logger.exception(f"Exception while sending WhatsApp message: {str(e)}")
return False