This commit is contained in:
Flatlogic Bot 2026-01-24 06:19:14 +00:00
parent 9561e00531
commit 3b66669105
9 changed files with 202 additions and 1 deletions

View File

@ -166,3 +166,25 @@ class RenewSubscriptionForm(forms.Form):
widget=forms.Select(attrs={'class': 'form-select'}),
label=_('Subscription Plan')
)
class AppSettingForm(forms.ModelForm):
class Meta:
model = AppSetting
fields = '__all__'
widgets = {
'app_name': forms.TextInput(attrs={'class': 'form-control'}),
'logo': forms.FileInput(attrs={'class': 'form-control'}),
'slogan': forms.TextInput(attrs={'class': 'form-control'}),
'registration_number': forms.TextInput(attrs={'class': 'form-control'}),
'tax_number': forms.TextInput(attrs={'class': 'form-control'}),
'contact_phone': forms.TextInput(attrs={'class': 'form-control'}),
'contact_email': forms.EmailInput(attrs={'class': 'form-control'}),
'contact_address': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
'terms_of_service': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
'privacy_policy': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
'subscription_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'shipper_monthly_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
'shipper_annual_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
'truck_owner_monthly_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
'truck_owner_annual_fee': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}),
}

View File

@ -355,6 +355,19 @@
</div>
</a>
</div>
<div class="col-md-4">
<a href="{% url 'admin_app_settings' %}" class="card border-0 shadow-sm p-3 text-decoration-none text-dark h-100 hover-card">
<div class="d-flex align-items-center">
<div class="rounded-circle bg-light p-3 me-3 text-danger">
<i class="fa-solid fa-sliders"></i>
</div>
<div>
<h6 class="mb-0 fw-bold">{% trans 'Application Settings' %}</h6>
<small class="text-muted">{% trans 'Control fees, logo, and legal text' %}</small>
</div>
</div>
</a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,145 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0">{% trans "Application Settings" %}</h2>
<a href="{% url 'dashboard' %}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> {% trans "Back to Dashboard" %}
</a>
</div>
<form method="post" enctype="multipart/form-data" class="card shadow-sm border-0">
{% csrf_token %}
<div class="card-body p-4">
<h5 class="card-title mb-4 border-bottom pb-2">{% trans "General Information" %}</h5>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">{{ form.app_name.label }}</label>
{{ form.app_name }}
{% if form.app_name.errors %}<div class="text-danger small">{{ form.app_name.errors }}</div>{% endif %}
</div>
<div class="col-md-6">
<label class="form-label">{{ form.slogan.label }}</label>
{{ form.slogan }}
{% if form.slogan.errors %}<div class="text-danger small">{{ form.slogan.errors }}</div>{% endif %}
</div>
<div class="col-md-6">
<label class="form-label">{{ form.logo.label }}</label>
{{ form.logo }}
{% if form.logo.errors %}<div class="text-danger small">{{ form.logo.errors }}</div>{% endif %}
{% if form.instance.logo %}
<div class="mt-2">
<img src="{{ form.instance.logo.url }}" alt="Logo" class="img-thumbnail" style="height: 50px;">
</div>
{% endif %}
</div>
</div>
<h5 class="card-title mt-5 mb-4 border-bottom pb-2">{% trans "Contact & Legal" %}</h5>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">{{ form.registration_number.label }}</label>
{{ form.registration_number }}
</div>
<div class="col-md-6">
<label class="form-label">{{ form.tax_number.label }}</label>
{{ form.tax_number }}
</div>
<div class="col-md-6">
<label class="form-label">{{ form.contact_phone.label }}</label>
{{ form.contact_phone }}
</div>
<div class="col-md-6">
<label class="form-label">{{ form.contact_email.label }}</label>
{{ form.contact_email }}
</div>
<div class="col-12">
<label class="form-label">{{ form.contact_address.label }}</label>
{{ form.contact_address }}
</div>
</div>
<h5 class="card-title mt-5 mb-4 border-bottom pb-2">{% trans "Subscription Fees" %}</h5>
<div class="mb-3">
<div class="form-check form-switch">
{{ form.subscription_enabled }}
<label class="form-check-label" for="{{ form.subscription_enabled.id_for_label }}">
{{ form.subscription_enabled.label }}
</label>
</div>
</div>
<div id="fees-section" {% if not form.instance.subscription_enabled %}style="display:none;"{% endif %}>
<div class="row g-4">
<div class="col-md-6">
<div class="p-3 bg-light rounded">
<h6 class="fw-bold mb-3">{% trans "Shipper Fees" %}</h6>
<div class="mb-3">
<label class="form-label small">{{ form.shipper_monthly_fee.label }}</label>
{{ form.shipper_monthly_fee }}
</div>
<div class="mb-0">
<label class="form-label small">{{ form.shipper_annual_fee.label }}</label>
{{ form.shipper_annual_fee }}
</div>
</div>
</div>
<div class="col-md-6">
<div class="p-3 bg-light rounded">
<h6 class="fw-bold mb-3">{% trans "Truck Owner Fees" %}</h6>
<div class="mb-3">
<label class="form-label small">{{ form.truck_owner_monthly_fee.label }}</label>
{{ form.truck_owner_monthly_fee }}
</div>
<div class="mb-0">
<label class="form-label small">{{ form.truck_owner_annual_fee.label }}</label>
{{ form.truck_owner_annual_fee }}
</div>
</div>
</div>
</div>
</div>
<h5 class="card-title mt-5 mb-4 border-bottom pb-2">{% trans "Policies" %}</h5>
<div class="row g-3">
<div class="col-12">
<label class="form-label">{{ form.terms_of_service.label }}</label>
{{ form.terms_of_service }}
</div>
<div class="col-12">
<label class="form-label">{{ form.privacy_policy.label }}</label>
{{ form.privacy_policy }}
</div>
</div>
</div>
<div class="card-footer p-4 bg-white border-top-0">
<button type="submit" class="btn btn-primary px-5 py-2">
{% trans "Save All Changes" %}
</button>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const subEnabled = document.getElementById('{{ form.subscription_enabled.id_for_label }}');
const feesSection = document.getElementById('fees-section');
if (subEnabled) {
subEnabled.addEventListener('change', function() {
if (this.checked) {
feesSection.style.display = 'block';
} else {
feesSection.style.display = 'none';
}
});
}
});
</script>
{% endblock %}

View File

@ -28,4 +28,5 @@ urlpatterns = [
path("receipt/<str:receipt_number>/", views.transaction_receipt, name="transaction_receipt"),
path("admin/financials/", views.admin_financials, name="admin_financials"),
path("admin/refund/<str:receipt_number>/", views.issue_refund, name="issue_refund"),
path("admin/settings/", views.admin_app_settings, name="admin_app_settings"),
]

View File

@ -4,7 +4,10 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate, logout
from django.utils import timezone
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection, Transaction
from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm
from .forms import (
TruckForm, ShipmentForm, BidForm, UserRegistrationForm,
OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm, AppSettingForm
)
from django.contrib import messages
from django.utils.translation import gettext as _
from django.db.models import Q
@ -583,3 +586,20 @@ def issue_refund(request, receipt_number):
messages.success(request, _("Refund issued successfully! Receipt: %(receipt)s") % {'receipt': refund.receipt_number})
return redirect('admin_financials')
@login_required
def admin_app_settings(request):
if not (request.user.profile.role == 'ADMIN' or request.user.is_superuser):
return redirect('dashboard')
settings_obj = AppSetting.objects.first()
if request.method == 'POST':
form = AppSettingForm(request.POST, request.FILES, instance=settings_obj)
if form.is_valid():
form.save()
messages.success(request, _("Application settings updated successfully."))
return redirect('admin_app_settings')
else:
form = AppSettingForm(instance=settings_obj)
return render(request, 'core/app_settings.html', {'form': form})