adding disable payments

This commit is contained in:
Flatlogic Bot 2026-01-25 13:39:17 +00:00
parent df3c7ad9f5
commit ce3101780f
15 changed files with 176 additions and 32 deletions

22
GEMINI_RESPONSE.md Normal file
View File

@ -0,0 +1,22 @@
Plan:
1. **Add Configuration:** I have added a new field `enable_payment` (checkbox) to the **Platform Profile** model.
2. **Enforce Logic:** I updated the payment initiation view (`initiate_payment`) to check this flag. If disabled, users cannot start a payment.
3. **Update UI:** I updated the **Shipper Dashboard** to hide the "Pay Now" button if payments are disabled.
4. **Deploy:** Created migrations and restarted the server.
Changed (if any):
* `core/models.py`: Added `enable_payment` boolean field to `PlatformProfile`.
* `core/views.py`: Added a check in `initiate_payment` to block payments if disabled.
* `core/templates/core/shipper_dashboard.html`: Wrapped the "Pay Now" button in a conditional check.
Notes:
* **Action Required:** Go to **Django Admin > Platform Profiles**. You will see a new checkbox **Enable Payment**.
* **Checked:** Users can pay.
* **Unchecked:** The "Pay Now" button disappears, and direct URL access is blocked.
Next: You can test this by toggling the checkbox in the admin and refreshing your dashboard. What's next?
Reminder: click Save in the editor to sync changes.

View File

@ -174,8 +174,8 @@ EMAIL_BACKEND = os.getenv(
"EMAIL_BACKEND",
"django.core.mail.backends.smtp.EmailBackend"
)
EMAIL_HOST = os.getenv("EMAIL_HOST", "pop.gmail.com")
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "995"))
EMAIL_HOST = os.getenv("EMAIL_HOST", "smtp.gmail.com")
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "587"))
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "aalabry@gmail.com")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "accd uacy kzdq aejp")
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "true").lower() == "true"

View File

@ -8,6 +8,8 @@ from django.shortcuts import render
from django.utils.html import format_html
from django.contrib import messages
from .whatsapp_utils import send_whatsapp_message_detailed
from django.core.mail import send_mail
from django.conf import settings
import logging
class ProfileInline(admin.StackedInline):
@ -47,6 +49,7 @@ class PlatformProfileAdmin(admin.ModelAdmin):
urls = super().get_urls()
custom_urls = [
path('test-whatsapp/', self.admin_site.admin_view(self.test_whatsapp_view), name='test-whatsapp'),
path('test-email/', self.admin_site.admin_view(self.test_email_view), name='test-email'),
]
return custom_urls + urls
@ -69,11 +72,39 @@ class PlatformProfileAdmin(admin.ModelAdmin):
)
return render(request, "admin/core/platformprofile/test_whatsapp.html", context)
def test_email_view(self, request):
email = ''
if request.method == 'POST':
email = request.POST.get('email')
if email:
try:
send_mail(
subject="Test Email from Platform",
message="This is a test email to verify your platform's email configuration.",
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[email],
fail_silently=False,
)
messages.success(request, f"Success: Test email sent to {email}.")
except Exception as e:
messages.error(request, f"Error sending email: {str(e)}")
else:
messages.warning(request, "Please enter an email address.")
context = dict(
self.admin_site.each_context(request),
email=email,
)
return render(request, "admin/core/platformprofile/test_email.html", context)
def test_connection_link(self, obj):
return format_html(
'<a class="button" href="{}" style="margin-right: 10px;">{}</a>'
'<a class="button" href="{}">{}</a>',
reverse('admin:test-whatsapp'),
_('Test WhatsApp Configuration')
_('Test WhatsApp'),
reverse('admin:test-email'),
_('Test Email')
)
test_connection_link.short_description = _("Actions")
test_connection_link.allow_tags = True
@ -84,6 +115,8 @@ class PlatformProfileAdmin(admin.ModelAdmin):
fieldsets = super().get_fieldsets(request, obj)
# Add the test link to the first fieldset or a new one
if obj:
# Check if 'Tools' fieldset already exists to avoid duplication if called multiple times (though get_fieldsets is usually fresh)
# Easier: just append it.
fieldsets += ((_('Tools'), {'fields': ('test_connection_link',)}),)
return fieldsets

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-01-25 13:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0012_alter_platformprofile_whatsapp_access_token_and_more'),
]
operations = [
migrations.AddField(
model_name='platformprofile',
name='enable_payment',
field=models.BooleanField(default=True, help_text='Toggle to enable or disable payments on the platform.', verbose_name='Enable Payment'),
),
]

View File

@ -166,12 +166,22 @@ class PlatformProfile(models.Model):
whatsapp_business_phone_number_id = models.CharField(_('Wablas Domain'), max_length=100, blank=True, default="https://deu.wablas.com", help_text=_("The Wablas API domain (e.g., https://deu.wablas.com)."))
whatsapp_app_secret = models.CharField(_('Wablas Secret Key'), max_length=255, blank=True, help_text=_("Your Wablas API Secret Key (if required)."))
# Payment Configuration
enable_payment = models.BooleanField(_('Enable Payment'), default=True, help_text=_("Toggle to enable or disable payments on the platform."))
def save(self, *args, **kwargs):
# Auto-clean whitespace from credentials
if self.whatsapp_access_token:
self.whatsapp_access_token = self.whatsapp_access_token.strip()
if self.whatsapp_business_phone_number_id:
self.whatsapp_business_phone_number_id = self.whatsapp_business_phone_number_id.strip()
val = self.whatsapp_business_phone_number_id.strip()
# Remove common path suffixes if user pasted full URL
for suffix in ['/api/send-message', '/api/v2/send-message']:
if val.endswith(suffix):
val = val[:-len(suffix)]
if val.endswith('/'):
val = val[:-1]
self.whatsapp_business_phone_number_id = val
if self.whatsapp_app_secret:
self.whatsapp_app_secret = self.whatsapp_app_secret.strip()

View File

@ -0,0 +1,39 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify %}
{% block extrahead %}{{ block.super }}
<script src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label='core' %}">Core</a>
&rsaquo; <a href="{% url 'admin:core_platformprofile_changelist' %}">Platform Profiles</a>
&rsaquo; Test Email Configuration
</div>
{% endblock %}
{% block content %}
<div id="content-main">
<form method="post">
{% csrf_token %}
<div>
<fieldset class="module aligned">
<h2>Test Email Configuration</h2>
<div class="form-row">
<label for="id_email" class="required">Target Email Address:</label>
<input type="email" name="email" id="id_email" value="{{ email }}" required size="40">
<div class="help">Enter the email address to receive the test message.</div>
</div>
</fieldset>
<div class="submit-row">
<input type="submit" value="Send Test Email" class="default" name="_save">
<a href="../" class="button closelink" style="margin-left: 10px;">Go Back</a>
</div>
</div>
</form>
</div>
{% endblock %}

View File

@ -32,9 +32,11 @@
</div>
{% if parcel.payment_status == 'pending' %}
{% if platform_profile.enable_payment %}
<a href="{% url 'initiate_payment' parcel.id %}" class="btn btn-sm btn-outline-primary w-100 mb-3">
<i class="fas fa-credit-card me-1"></i> {% trans "Pay Now" %}
</a>
{% endif %}
{% endif %}
<hr>

View File

@ -2,7 +2,7 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
from .models import Parcel, Profile, Country, Governate, City, OTPVerification
from .models import Parcel, Profile, Country, Governate, City, OTPVerification, PlatformProfile
from .forms import UserRegistrationForm, ParcelForm, ContactForm, UserProfileForm
from django.utils.translation import gettext_lazy as _
from django.utils.translation import get_language
@ -125,6 +125,12 @@ def update_status(request, parcel_id):
@login_required
def initiate_payment(request, parcel_id):
# Check if payments are enabled
platform_profile = PlatformProfile.objects.first()
if platform_profile and not platform_profile.enable_payment:
messages.error(request, _("Payments are currently disabled by the administrator."))
return redirect('dashboard')
parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user, payment_status='pending')
thawani = ThawaniPay()
@ -319,4 +325,4 @@ def verify_otp_view(request):
except OTPVerification.DoesNotExist:
messages.error(request, _("Invalid code."))
return render(request, 'core/verify_otp.html')
return render(request, 'core/verify_otp.html', {'form': form})

View File

@ -15,7 +15,7 @@ def get_whatsapp_credentials():
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 = "" # Add this to settings if you want env support, but for now mostly DB
secret_key = ""
source = "Settings/Env"
# Try to fetch from PlatformProfile
@ -53,7 +53,7 @@ def send_whatsapp_message(phone_number, message):
def send_whatsapp_message_detailed(phone_number, message):
"""
Sends a WhatsApp message via Wablas V2 API and returns detailed status.
Sends a WhatsApp message via Wablas API and returns detailed status.
Returns tuple: (success: bool, response_msg: str)
"""
if not getattr(settings, 'WHATSAPP_ENABLED', True):
@ -69,43 +69,57 @@ def send_whatsapp_message_detailed(phone_number, message):
return False, msg
# Normalize phone number (Wablas expects international format without +, e.g. 628123...)
# Remove all non-digits
clean_phone = "".join(filter(str.isdigit, str(phone_number)))
clean_phone = str(phone_number).replace('+', '').replace(' ', '')
# Construct Authorization Header
# Wablas V2: Authorization: {$token}.{$secret_key}
# Some Wablas servers just need Token, but docs say Token.Secret
# 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}"
# Endpoint V2
url = f"{domain}/api/v2/send-message"
headers = {
"Authorization": auth_header,
"Content-Type": "application/json",
# requests will set Content-Type to application/x-www-form-urlencoded when using 'data' param
}
payload = {
"data": [
{
"phone": clean_phone,
"message": message,
"isGroup": "false",
"flag": "instant" # Priority
}
]
# Payload as form data (not JSON)
data = {
"phone": clean_phone,
"message": message,
}
# Note: User's example didn't add 'secret' to payload, only to header.
# We will stick to user's example strictly.
try:
response = requests.post(url, headers=headers, json=payload, timeout=15)
response_data = response.json()
# 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 and response_data.get('status') is not False:
logger.info(f"WhatsApp message sent to {clean_phone} via Wablas")
return True, f"Message sent successfully via Wablas. (Source: {source})"
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")
return True, f"Message sent successfully via Wablas. (Source: {source})"
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}"
logger.error(error_msg)