editing registeration
This commit is contained in:
parent
5f2219fc0f
commit
9d123496e2
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
|
||||
from .models import Profile, Parcel, Country, Governate, City, PlatformProfile, Testimonial, DriverRating
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.urls import path, reverse
|
||||
from django.shortcuts import render
|
||||
@ -18,9 +18,25 @@ class ProfileInline(admin.StackedInline):
|
||||
model = Profile
|
||||
can_delete = False
|
||||
verbose_name_plural = _('Profiles')
|
||||
fieldsets = (
|
||||
(None, {'fields': ('role', 'is_approved', 'phone_number', 'profile_picture', 'address')}),
|
||||
(_('Driver Info'), {'fields': ('license_front_image', 'license_back_image', 'car_plate_number'), 'classes': ('collapse',)}),
|
||||
(_('Location'), {'fields': ('country', 'governate', 'city'), 'classes': ('collapse',)}),
|
||||
)
|
||||
|
||||
class CustomUserAdmin(UserAdmin):
|
||||
inlines = (ProfileInline,)
|
||||
list_display = ('username', 'email', 'get_role', 'get_approval_status', 'is_active', 'is_staff')
|
||||
list_filter = ('is_active', 'is_staff', 'profile__role', 'profile__is_approved')
|
||||
|
||||
def get_role(self, obj):
|
||||
return obj.profile.get_role_display()
|
||||
get_role.short_description = _('Role')
|
||||
|
||||
def get_approval_status(self, obj):
|
||||
return obj.profile.is_approved
|
||||
get_approval_status.short_description = _('Approved')
|
||||
get_approval_status.boolean = True
|
||||
|
||||
def get_inline_instances(self, request, obj=None):
|
||||
if not obj:
|
||||
@ -171,6 +187,4 @@ admin.site.register(Governate)
|
||||
admin.site.register(City)
|
||||
admin.site.register(PlatformProfile, PlatformProfileAdmin)
|
||||
admin.site.register(Testimonial, TestimonialAdmin)
|
||||
|
||||
# Set custom admin index template - using default 'admin/index.html' which we have overridden
|
||||
# admin.site.index_template = 'admin/dashboard.html'
|
||||
admin.site.register(DriverRating)
|
||||
18
core/migrations/0020_profile_is_approved.py
Normal file
18
core/migrations/0020_profile_is_approved.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-28 00:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0019_profile_car_plate_number_profile_license_back_image_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='profile',
|
||||
name='is_approved',
|
||||
field=models.BooleanField(default=False, help_text='Designates whether this user is approved to use the platform (mainly for drivers).', verbose_name='Approved'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@ -82,6 +82,9 @@ class Profile(models.Model):
|
||||
governate = models.ForeignKey(Governate, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Governate'))
|
||||
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('City'))
|
||||
|
||||
# Approval Status
|
||||
is_approved = models.BooleanField(_('Approved'), default=False, help_text=_("Designates whether this user is approved to use the platform (mainly for drivers)."))
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.username} - {self.get_role_display()}"
|
||||
|
||||
@ -275,4 +278,4 @@ class DriverRating(models.Model):
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Driver Rating')
|
||||
verbose_name_plural = _('Driver Ratings')
|
||||
verbose_name_plural = _('Driver Ratings')
|
||||
@ -10,6 +10,16 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if not is_approved %}
|
||||
<div class="alert alert-warning shadow-sm border-0 d-flex align-items-center mb-4" role="alert" style="border-radius: 12px;">
|
||||
<i class="bi bi-hourglass-split fs-3 me-3 text-warning"></i>
|
||||
<div>
|
||||
<h5 class="alert-heading mb-1">{% trans "Account Pending Approval" %}</h5>
|
||||
<p class="mb-0 text-muted">{% trans "Your driver account is currently under review by our administrators. You will be notified once your documents are verified and your account is approved to accept shipments." %}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<ul class="nav nav-pills mb-4" id="pills-tab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="pills-available-tab" data-bs-toggle="pill" data-bs-target="#pills-available" type="button" role="tab">{% trans "Available Shipments" %}</button>
|
||||
@ -29,132 +39,143 @@
|
||||
<!-- Available Shipments -->
|
||||
<div class="tab-pane fade show active" id="pills-available" role="tabpanel">
|
||||
|
||||
<!-- Toolbar -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="mb-0 text-muted">{% trans "Browse Shipments" %}</h5>
|
||||
<div class="btn-group" role="group" aria-label="View toggle">
|
||||
<button type="button" class="btn btn-outline-primary active" id="btn-grid-view">
|
||||
<i class="bi bi-grid"></i> {% trans "Grid" %}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" id="btn-list-view">
|
||||
<i class="bi bi-list"></i> {% trans "List" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if available_parcels %}
|
||||
|
||||
<!-- Grid View -->
|
||||
<div id="view-grid" class="row g-4">
|
||||
{% for parcel in available_parcels %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card border-0 shadow-sm h-100" style="border-radius: 15px;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ parcel.description|truncatechars:30 }}</h5>
|
||||
<p class="card-text mb-1 small"><strong>{% trans "Pickup" %}:</strong> {{ parcel.pickup_governate.name }} / {{ parcel.pickup_city.name }}</p>
|
||||
<p class="card-text mb-3 small"><strong>{% trans "Delivery" %}:</strong> {{ parcel.delivery_governate.name }} / {{ parcel.delivery_city.name }}</p>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="text-muted small"><strong>{% trans "Weight" %}:</strong> {{ parcel.weight }} kg</span>
|
||||
</div>
|
||||
|
||||
<!-- Bid/Price Highlight -->
|
||||
<div class="bg-light p-2 rounded text-center mb-3 border border-primary border-opacity-25">
|
||||
<small class="text-uppercase text-muted fw-bold" style="font-size: 0.7rem;">{% trans "Shipper's Offer (Bid)" %}</small>
|
||||
<div class="text-primary fw-bold fs-4">{{ parcel.price }} <span class="fs-6">OMR</span></div>
|
||||
</div>
|
||||
|
||||
<form action="{% url 'accept_parcel' parcel.id %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-masarx-primary w-100">{% trans "Accept Shipment" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% if is_approved %}
|
||||
<!-- Toolbar -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="mb-0 text-muted">{% trans "Browse Shipments" %}</h5>
|
||||
<div class="btn-group" role="group" aria-label="View toggle">
|
||||
<button type="button" class="btn btn-outline-primary active" id="btn-grid-view">
|
||||
<i class="bi bi-grid"></i> {% trans "Grid" %}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" id="btn-list-view">
|
||||
<i class="bi bi-list"></i> {% trans "List" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- List View (Initially Hidden) -->
|
||||
<div id="view-list" class="d-none">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
{% if available_parcels %}
|
||||
|
||||
<!-- Grid View -->
|
||||
<div id="view-grid" class="row g-4">
|
||||
{% for parcel in available_parcels %}
|
||||
<div class="card border-0 shadow-sm rounded-3">
|
||||
<div class="card-body p-3">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8 mb-3 mb-md-0">
|
||||
<h5 class="card-title mb-2">{{ parcel.description|truncatechars:80 }}</h5>
|
||||
<div class="d-flex flex-wrap gap-3 text-muted small">
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<i class="bi bi-geo-alt-fill text-primary"></i>
|
||||
<strong>{% trans "From" %}:</strong> {{ parcel.pickup_governate.name }} / {{ parcel.pickup_city.name }}
|
||||
</span>
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<i class="bi bi-geo-alt-fill text-danger"></i>
|
||||
<strong>{% trans "To" %}:</strong> {{ parcel.delivery_governate.name }} / {{ parcel.delivery_city.name }}
|
||||
</span>
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<i class="bi bi-box-seam"></i> {{ parcel.weight }} kg
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card border-0 shadow-sm h-100" style="border-radius: 15px;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ parcel.description|truncatechars:30 }}</h5>
|
||||
<p class="card-text mb-1 small"><strong>{% trans "Pickup" %}:</strong> {{ parcel.pickup_governate.name }} / {{ parcel.pickup_city.name }}</p>
|
||||
<p class="card-text mb-3 small"><strong>{% trans "Delivery" %}:</strong> {{ parcel.delivery_governate.name }} / {{ parcel.delivery_city.name }}</p>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="text-muted small"><strong>{% trans "Weight" %}:</strong> {{ parcel.weight }} kg</span>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<div class="d-flex flex-column align-items-md-end gap-2">
|
||||
<div class="text-primary fw-bold fs-5">{{ parcel.price }} OMR</div>
|
||||
<form action="{% url 'accept_parcel' parcel.id %}" method="POST" class="w-100 w-md-auto">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-masarx-primary btn-sm w-100">{% trans "Accept" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Bid/Price Highlight -->
|
||||
<div class="bg-light p-2 rounded text-center mb-3 border border-primary border-opacity-25">
|
||||
<small class="text-uppercase text-muted fw-bold" style="font-size: 0.7rem;">{% trans "Shipper's Offer (Bid)" %}</small>
|
||||
<div class="text-primary fw-bold fs-4">{{ parcel.price }} <span class="fs-6">OMR</span></div>
|
||||
</div>
|
||||
|
||||
<form action="{% url 'accept_parcel' parcel.id %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-masarx-primary w-100">{% trans "Accept Shipment" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if available_parcels.has_other_pages %}
|
||||
<nav aria-label="Page navigation" class="mt-5">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if available_parcels.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ available_parcels.previous_page_number }}" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link" aria-hidden="true">«</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
<!-- List View (Initially Hidden) -->
|
||||
<div id="view-list" class="d-none">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
{% for parcel in available_parcels %}
|
||||
<div class="card border-0 shadow-sm rounded-3">
|
||||
<div class="card-body p-3">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8 mb-3 mb-md-0">
|
||||
<h5 class="card-title mb-2">{{ parcel.description|truncatechars:80 }}</h5>
|
||||
<div class="d-flex flex-wrap gap-3 text-muted small">
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<i class="bi bi-geo-alt-fill text-primary"></i>
|
||||
<strong>{% trans "From" %}:</strong> {{ parcel.pickup_governate.name }} / {{ parcel.pickup_city.name }}
|
||||
</span>
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<i class="bi bi-geo-alt-fill text-danger"></i>
|
||||
<strong>{% trans "To" %}:</strong> {{ parcel.delivery_governate.name }} / {{ parcel.delivery_city.name }}
|
||||
</span>
|
||||
<span class="d-flex align-items-center gap-1">
|
||||
<i class="bi bi-box-seam"></i> {{ parcel.weight }} kg
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<div class="d-flex flex-column align-items-md-end gap-2">
|
||||
<div class="text-primary fw-bold fs-5">{{ parcel.price }} OMR</div>
|
||||
<form action="{% url 'accept_parcel' parcel.id %}" method="POST" class="w-100 w-md-auto">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-masarx-primary btn-sm w-100">{% trans "Accept" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for i in available_parcels.paginator.page_range %}
|
||||
{% if available_parcels.number == i %}
|
||||
<li class="page-item active"><span class="page-link">{{ i }}</span></li>
|
||||
<!-- Pagination -->
|
||||
{% if available_parcels.has_other_pages %}
|
||||
<nav aria-label="Page navigation" class="mt-5">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if available_parcels.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ available_parcels.previous_page_number }}" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link" aria-hidden="true">«</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if available_parcels.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ available_parcels.next_page_number }}" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link" aria-hidden="true">»</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% for i in available_parcels.paginator.page_range %}
|
||||
{% if available_parcels.number == i %}
|
||||
<li class="page-item active"><span class="page-link">{{ i }}</span></li>
|
||||
{% else %}
|
||||
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if available_parcels.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ available_parcels.next_page_number }}" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link" aria-hidden="true">»</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<p class="text-center py-5">{% trans "No shipments available at the moment." %}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% else %}
|
||||
<p class="text-center py-5">{% trans "No shipments available at the moment." %}</p>
|
||||
<!-- Not Approved State for Tab Pane -->
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-lock-fill display-4 text-muted mb-3"></i>
|
||||
<h4 class="text-muted">{% trans "Access Restricted" %}</h4>
|
||||
<p class="text-muted">{% trans "Please wait for administrator approval to view available shipments." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- My Deliveries (Active) -->
|
||||
@ -318,4 +339,4 @@
|
||||
if (listViewBtn) listViewBtn.addEventListener('click', () => setView('list'));
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@ -173,6 +173,20 @@
|
||||
<div class="value">
|
||||
<strong>{{ parcel.shipper.first_name }} {{ parcel.shipper.last_name }}</strong><br>
|
||||
{{ parcel.shipper.profile.address }}<br>
|
||||
|
||||
{% if parcel.shipper.profile.city %}
|
||||
{{ parcel.shipper.profile.city.name_en }} / <span class="ar-text">{{ parcel.shipper.profile.city.name_ar }}</span><br>
|
||||
{% endif %}
|
||||
|
||||
{% if parcel.shipper.profile.governate %}
|
||||
{{ parcel.shipper.profile.governate.name_en }} / <span class="ar-text">{{ parcel.shipper.profile.governate.name_ar }}</span><br>
|
||||
{% endif %}
|
||||
|
||||
{% if parcel.shipper.profile.country %}
|
||||
{{ parcel.shipper.profile.country.name_en }} / <span class="ar-text">{{ parcel.shipper.profile.country.name_ar }}</span><br>
|
||||
{% endif %}
|
||||
|
||||
<br>
|
||||
{{ parcel.shipper.email }}<br>
|
||||
{{ parcel.shipper.profile.phone_number }}
|
||||
</div>
|
||||
@ -195,7 +209,7 @@
|
||||
<span class="ar ar-text">الوزن</span>
|
||||
</th>
|
||||
<th class="text-right">
|
||||
Amount (OMR)
|
||||
Amount
|
||||
<span class="ar ar-text">المبلغ</span>
|
||||
</th>
|
||||
</tr>
|
||||
@ -208,7 +222,7 @@
|
||||
</td>
|
||||
<td>{{ parcel.tracking_number }}</td>
|
||||
<td>{{ parcel.weight }} kg</td>
|
||||
<td class="text-right">{{ parcel.price }}</td>
|
||||
<td class="text-right">{{ parcel.price }} OMR / <span class="ar-text">ر.ع.</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@ -216,7 +230,7 @@
|
||||
<td colspan="3" class="text-right">
|
||||
TOTAL / الإجمالي
|
||||
</td>
|
||||
<td class="text-right">{{ parcel.price }} OMR</td>
|
||||
<td class="text-right">{{ parcel.price }} OMR / <span class="ar-text">ر.ع.</span></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
@ -208,7 +208,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<h3>COD / الدفع</h3>
|
||||
<p class="bold">{{ parcel.price }} OMR</p>
|
||||
<p class="bold">{{ parcel.price }} OMR / <span class="ar-text">ر.ع.</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -88,6 +88,11 @@ def register_shipper(request):
|
||||
user.is_active = False
|
||||
user.save()
|
||||
|
||||
# Auto-approve Shippers
|
||||
if hasattr(user, 'profile'):
|
||||
user.profile.is_approved = True
|
||||
user.profile.save()
|
||||
|
||||
# Generate OTP
|
||||
code = ''.join(random.choices(string.digits, k=6))
|
||||
OTPVerification.objects.create(user=user, code=code, purpose='registration')
|
||||
@ -124,6 +129,12 @@ def register_driver(request):
|
||||
user = form.save(commit=True)
|
||||
user.is_active = False
|
||||
user.save()
|
||||
|
||||
# Drivers are NOT approved by default (model default is False)
|
||||
# We can rely on the default, but explicit is fine too if we want to be sure
|
||||
if hasattr(user, 'profile'):
|
||||
user.profile.is_approved = False
|
||||
user.profile.save()
|
||||
|
||||
# Generate OTP
|
||||
code = ''.join(random.choices(string.digits, k=6))
|
||||
@ -236,6 +247,12 @@ def dashboard(request):
|
||||
else:
|
||||
available_parcels_list = Parcel.objects.filter(status='pending').order_by('-created_at')
|
||||
|
||||
# Check Approval Status
|
||||
if not profile.is_approved:
|
||||
messages.warning(request, _("Your account is pending approval. You cannot accept shipments yet."))
|
||||
# Empty list if not approved
|
||||
available_parcels_list = Parcel.objects.none()
|
||||
|
||||
# Pagination for Available Shipments
|
||||
page = request.GET.get('page', 1)
|
||||
paginator = Paginator(available_parcels_list, 9) # Show 9 parcels per page
|
||||
@ -260,7 +277,8 @@ def dashboard(request):
|
||||
'available_parcels': available_parcels,
|
||||
'my_parcels': my_parcels,
|
||||
'completed_parcels': completed_parcels,
|
||||
'cancelled_parcels': cancelled_parcels
|
||||
'cancelled_parcels': cancelled_parcels,
|
||||
'is_approved': profile.is_approved # Pass to template
|
||||
})
|
||||
|
||||
@login_required
|
||||
@ -292,6 +310,11 @@ def accept_parcel(request, parcel_id):
|
||||
if profile.role != 'car_owner':
|
||||
messages.error(request, _("Only car owners can accept shipments."))
|
||||
return redirect('dashboard')
|
||||
|
||||
# Check Approval
|
||||
if not profile.is_approved:
|
||||
messages.error(request, _("Your account is pending approval. You cannot accept shipments yet."))
|
||||
return redirect('dashboard')
|
||||
|
||||
platform_profile = PlatformProfile.objects.first()
|
||||
payments_enabled = platform_profile.enable_payment if platform_profile else True
|
||||
@ -877,6 +900,10 @@ def update_parcel_status_ajax(request):
|
||||
if payments_enabled and parcel.payment_status != 'paid':
|
||||
return JsonResponse({'success': False, 'error': _('Payment pending')})
|
||||
|
||||
# Check Approval for Driver via AJAX
|
||||
if not request.user.profile.is_approved:
|
||||
return JsonResponse({'success': False, 'error': _('Account pending approval')})
|
||||
|
||||
parcel.carrier = request.user
|
||||
parcel.status = 'picked_up' # Or 'assigned'? Logic says 'picked_up' in accept_parcel
|
||||
parcel.save()
|
||||
@ -928,4 +955,4 @@ def cancel_parcel(request, parcel_id):
|
||||
parcel.save()
|
||||
messages.success(request, _("Shipment cancelled successfully."))
|
||||
|
||||
return redirect('dashboard')
|
||||
return redirect('dashboard')
|
||||
Binary file not shown.
@ -1393,3 +1393,92 @@ msgstr "رقم التتبع"
|
||||
|
||||
msgid "Cancelled Shipments"
|
||||
msgstr "الشحنات الملغاة"
|
||||
|
||||
msgid "Grid"
|
||||
msgstr "شبكة"
|
||||
|
||||
msgid "List"
|
||||
msgstr "قائمة"
|
||||
|
||||
msgid "Scan Parcel"
|
||||
msgstr "مسح الطرد"
|
||||
|
||||
msgid "Account Pending Approval"
|
||||
msgstr "الحساب قيد الانتظار"
|
||||
|
||||
msgid ""
|
||||
"Your driver account is currently under review by our administrators. You "
|
||||
"will be notified once your documents are verified and your account is "
|
||||
"approved to accept shipments."
|
||||
msgstr ""
|
||||
"حساب السائق الخاص بك قيد المراجعة حالياً من قبل المشرفين. سيتم إشعارك "
|
||||
"بمجرد التحقق من مستنداتك والموافقة على حسابك لقبول الشحنات."
|
||||
|
||||
msgid "Welcome to masarX"
|
||||
msgstr "مرحباً بك في مسارX"
|
||||
|
||||
msgid "Choose how you want to join us today."
|
||||
msgstr "اختر كيف تريد الانضمام إلينا اليوم."
|
||||
|
||||
msgid "I am a Shipper"
|
||||
msgstr "أنا شاحن"
|
||||
|
||||
msgid "I want to send parcels and track my shipments easily."
|
||||
msgstr "أريد إرسال الطرود وتتبع شحناتي بسهولة."
|
||||
|
||||
msgid "Register as Shipper"
|
||||
msgstr "التسجيل كشاحن"
|
||||
|
||||
msgid "I am a Car Owner"
|
||||
msgstr "أنا صاحب سيارة"
|
||||
|
||||
msgid "I want to deliver parcels and earn money on my own schedule."
|
||||
msgstr "أريد توصيل الطرود وكسب المال وفق جدولي الخاص."
|
||||
|
||||
msgid "Register as Car Owner"
|
||||
msgstr "التسجيل كصاحب سيارة"
|
||||
|
||||
msgid "Car Owner Registration"
|
||||
msgstr "تسجيل صاحب سيارة"
|
||||
|
||||
msgid "Take photo with Webcam"
|
||||
msgstr "التقاط صورة بالكاميرا"
|
||||
|
||||
msgid ""
|
||||
"Please provide clear photos of your license (front and back) and car plate "
|
||||
"number for verification."
|
||||
msgstr ""
|
||||
"يرجى تقديم صور واضحة لرخصتك (الأمام والخلف) ورقم لوحة السيارة للتحقق."
|
||||
|
||||
msgid "Submit Application"
|
||||
msgstr "تقديم الطلب"
|
||||
|
||||
msgid "Take Photo"
|
||||
msgstr "التقاط صورة"
|
||||
|
||||
msgid "Could not access webcam. Please check permissions."
|
||||
msgstr "تعذر الوصول إلى الكاميرا. يرجى التحقق من الأذونات."
|
||||
|
||||
msgid "Photo captured!"
|
||||
msgstr "تم التقاط الصورة!"
|
||||
|
||||
msgid "Back"
|
||||
msgstr "عودة"
|
||||
|
||||
msgid "License Front Image"
|
||||
msgstr "صورة الرخصة (الأمام)"
|
||||
|
||||
msgid "License Back Image"
|
||||
msgstr "صورة الرخصة (الخلف)"
|
||||
|
||||
msgid "Car Plate Number"
|
||||
msgstr "رقم لوحة السيارة"
|
||||
|
||||
msgid "Approved"
|
||||
msgstr "موافق عليه"
|
||||
|
||||
msgid ""
|
||||
"Designates whether this user is approved to use the platform (mainly for "
|
||||
"drivers)."
|
||||
|
||||
msgstr "يحدد ما إذا كان هذا المستخدم معتمداً لاستخدام المنصة (بشكل رئيسي للسائقين)."
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user