Autosave: 20260126-125014

This commit is contained in:
Flatlogic Bot 2026-01-26 12:50:14 +00:00
parent 6943d83b2c
commit 59561573fc
26 changed files with 432 additions and 48 deletions

View File

@ -254,9 +254,9 @@ class ParcelForm(forms.ModelForm):
self.fields['receiver_phone_code'].queryset = Country.objects.exclude(phone_code='').order_by(name_field)
self.fields['receiver_phone_code'].label_from_instance = lambda obj: f"{obj.phone_code} ({obj.name})"
# Default Country logic
# Default Country logic (Oman) - Only if not editing
oman = Country.objects.filter(name_en='Oman').first()
if oman:
if not self.instance.pk and oman:
self.fields['receiver_phone_code'].initial = oman
self.fields['pickup_country'].initial = oman
self.fields['delivery_country'].initial = oman
@ -283,6 +283,8 @@ class ParcelForm(forms.ModelForm):
self.fields['pickup_governate'].queryset = Governate.objects.filter(country_id=country_id).order_by(name_field)
except (ValueError, TypeError):
pass
elif self.instance.pk and self.instance.pickup_country:
self.fields['pickup_governate'].queryset = Governate.objects.filter(country=self.instance.pickup_country).order_by(name_field)
elif oman:
self.fields['pickup_governate'].queryset = Governate.objects.filter(country=oman).order_by(name_field)
@ -292,6 +294,8 @@ class ParcelForm(forms.ModelForm):
self.fields['pickup_city'].queryset = City.objects.filter(governate_id=gov_id).order_by(name_field)
except (ValueError, TypeError):
pass
elif self.instance.pk and self.instance.pickup_governate:
self.fields['pickup_city'].queryset = City.objects.filter(governate_id=self.instance.pickup_governate.id).order_by(name_field)
# Delivery
self.fields['delivery_governate'].queryset = Governate.objects.none()
@ -303,6 +307,8 @@ class ParcelForm(forms.ModelForm):
self.fields['delivery_governate'].queryset = Governate.objects.filter(country_id=country_id).order_by(name_field)
except (ValueError, TypeError):
pass
elif self.instance.pk and self.instance.delivery_country:
self.fields['delivery_governate'].queryset = Governate.objects.filter(country=self.instance.delivery_country).order_by(name_field)
elif oman:
self.fields['delivery_governate'].queryset = Governate.objects.filter(country=oman).order_by(name_field)
@ -312,6 +318,8 @@ class ParcelForm(forms.ModelForm):
self.fields['delivery_city'].queryset = City.objects.filter(governate_id=gov_id).order_by(name_field)
except (ValueError, TypeError):
pass
elif self.instance.pk and self.instance.delivery_governate:
self.fields['delivery_city'].queryset = City.objects.filter(governate_id=self.instance.delivery_governate.id).order_by(name_field)
def clean(self):
cleaned_data = super().clean()

View File

@ -7,7 +7,7 @@
<div class="container mt-5">
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Home" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Home" %}
</a>
</div>
<h1>{{ article.title }}</h1>

View File

@ -11,7 +11,7 @@
<!-- Back to Home -->
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Home" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Home" %}
</a>
</div>

View File

@ -0,0 +1,205 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<!-- Back to Dashboard -->
<div class="mb-4">
<a href="{% url 'dashboard' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Dashboard" %}
</a>
</div>
<div class="card border-0 shadow-sm p-4" style="border-radius: 20px;">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0">{% trans "Edit Shipment" %}</h2>
<span class="badge bg-warning text-dark">{{ parcel.tracking_number }}</span>
</div>
<form method="POST">
{% csrf_token %}
<div class="row g-3">
<!-- General Info -->
<div class="col-12">
<label class="form-label" for="{{ form.description.id_for_label }}">{{ form.description.label }}</label>
{{ form.description }}
{% if form.description.errors %}
<div class="text-danger small">{{ form.description.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.weight.id_for_label }}">{{ form.weight.label }}</label>
{{ form.weight }}
{% if form.weight.errors %}
<div class="text-danger small">{{ form.weight.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.price.id_for_label }}">{{ form.price.label }}</label>
{{ form.price }}
{% if form.price.errors %}
<div class="text-danger small">{{ form.price.errors }}</div>
{% endif %}
</div>
<!-- Pickup Details -->
<div class="col-12 mt-4">
<h4 class="mb-3 text-secondary border-bottom pb-2">{% trans "Pickup Details" %}</h4>
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.pickup_country.id_for_label }}">{{ form.pickup_country.label }}</label>
{{ form.pickup_country }}
{% if form.pickup_country.errors %}
<div class="text-danger small">{{ form.pickup_country.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.pickup_governate.id_for_label }}">{{ form.pickup_governate.label }}</label>
{{ form.pickup_governate }}
{% if form.pickup_governate.errors %}
<div class="text-danger small">{{ form.pickup_governate.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.pickup_city.id_for_label }}">{{ form.pickup_city.label }}</label>
{{ form.pickup_city }}
{% if form.pickup_city.errors %}
<div class="text-danger small">{{ form.pickup_city.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.pickup_address.id_for_label }}">{{ form.pickup_address.label }}</label>
{{ form.pickup_address }}
{% if form.pickup_address.errors %}
<div class="text-danger small">{{ form.pickup_address.errors }}</div>
{% endif %}
</div>
<!-- Delivery Details -->
<div class="col-12 mt-4">
<h4 class="mb-3 text-secondary border-bottom pb-2">{% trans "Delivery Details" %}</h4>
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.delivery_country.id_for_label }}">{{ form.delivery_country.label }}</label>
{{ form.delivery_country }}
{% if form.delivery_country.errors %}
<div class="text-danger small">{{ form.delivery_country.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.delivery_governate.id_for_label }}">{{ form.delivery_governate.label }}</label>
{{ form.delivery_governate }}
{% if form.delivery_governate.errors %}
<div class="text-danger small">{{ form.delivery_governate.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.delivery_city.id_for_label }}">{{ form.delivery_city.label }}</label>
{{ form.delivery_city }}
{% if form.delivery_city.errors %}
<div class="text-danger small">{{ form.delivery_city.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.delivery_address.id_for_label }}">{{ form.delivery_address.label }}</label>
{{ form.delivery_address }}
{% if form.delivery_address.errors %}
<div class="text-danger small">{{ form.delivery_address.errors }}</div>
{% endif %}
</div>
<!-- Receiver Details -->
<div class="col-12 mt-4">
<h4 class="mb-3 text-secondary border-bottom pb-2">{% trans "Receiver Details" %}</h4>
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.receiver_name.id_for_label }}">{{ form.receiver_name.label }}</label>
{{ form.receiver_name }}
{% if form.receiver_name.errors %}
<div class="text-danger small">{{ form.receiver_name.errors }}</div>
{% endif %}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.receiver_phone.id_for_label }}">{{ form.receiver_phone.label }}</label>
<div class="d-flex gap-2">
<div class="flex-shrink-0" style="width: 140px;">
{{ form.receiver_phone_code }}
</div>
<div class="flex-grow-1">
{{ form.receiver_phone }}
</div>
</div>
{% if form.receiver_phone_code.errors %}
<div class="text-danger small">{{ form.receiver_phone_code.errors }}</div>
{% endif %}
{% if form.receiver_phone.errors %}
<div class="text-danger small">{{ form.receiver_phone.errors }}</div>
{% endif %}
</div>
<div class="col-12 mt-4 d-flex gap-2">
<a href="{% url 'dashboard' %}" class="btn btn-outline-secondary w-50 py-3">{% trans "Cancel" %}</a>
<button type="submit" class="btn btn-masarx-primary w-50 py-3">{% trans "Update Shipment" %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
function setupDependentDropdowns(countryId, governateId, cityId) {
const countrySelect = document.getElementById(countryId);
const governateSelect = document.getElementById(governateId);
const citySelect = document.getElementById(cityId);
if (!countrySelect || !governateSelect || !citySelect) return;
countrySelect.addEventListener('change', function() {
const val = this.value;
governateSelect.innerHTML = '<option value="">{% trans "Select Governate" %}</option>';
citySelect.innerHTML = '<option value="">{% trans "Select City" %}</option>';
if (val) {
fetch(`{% url 'get_governates' %}?country_id=${val}`)
.then(response => response.json())
.then(data => {
data.forEach(item => {
const option = document.createElement('option');
option.value = item.id;
option.textContent = item.name;
governateSelect.appendChild(option);
});
});
}
});
governateSelect.addEventListener('change', function() {
const val = this.value;
citySelect.innerHTML = '<option value="">{% trans "Select City" %}</option>';
if (val) {
fetch(`{% url 'get_cities' %}?governate_id=${val}`)
.then(response => response.json())
.then(data => {
data.forEach(item => {
const option = document.createElement('option');
option.value = item.id;
option.textContent = item.name;
citySelect.appendChild(option);
});
});
}
});
}
setupDependentDropdowns('id_pickup_country', 'id_pickup_governate', 'id_pickup_city');
setupDependentDropdowns('id_delivery_country', 'id_delivery_governate', 'id_delivery_city');
});
</script>
{% endblock %}

View File

@ -11,7 +11,7 @@
<!-- Back to Profile -->
<div class="mb-4">
<a href="{% url 'profile' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Profile" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Profile" %}
</a>
</div>

View File

@ -4,14 +4,15 @@
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Invoice {{ parcel.tracking_number }}</title>
<title>{% trans "Invoice" %} {{ parcel.tracking_number }}</title>
<style>
@page {
size: A4;
margin: 2cm;
}
body {
font-family: sans-serif;
/* Prioritize Noto Sans for Arabic support */
font-family: 'Noto Sans', 'Noto Sans Arabic', 'DejaVu Sans', sans-serif;
font-size: 14px;
color: #333;
line-height: 1.4;
@ -113,7 +114,11 @@
}
.paid { color: #0f9d58; border: 1px solid #0f9d58; }
.pending { color: #f4b400; border: 1px solid #f4b400; }
.ar-text { direction: rtl; unicode-bidi: embed; }
.ar-text {
font-family: 'Noto Sans', 'Noto Sans Arabic', 'DejaVu Sans', sans-serif;
direction: rtl;
unicode-bidi: embed;
}
</style>
</head>
<body>
@ -225,4 +230,4 @@
</div>
</body>
</html>
</html>

View File

@ -3,109 +3,147 @@
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Label {{ parcel.tracking_number }}</title>
<title>{% trans "Label" %} {{ parcel.tracking_number }}</title>
<style>
@page {
size: 100mm 150mm;
margin: 0;
}
* {
box-sizing: border-box;
}
body {
font-family: sans-serif; /* WeasyPrint uses system fonts. Ensure Arabic font is available. */
/* Prioritize Noto Sans for Arabic support */
font-family: 'Noto Sans', 'Noto Sans Arabic', 'DejaVu Sans', sans-serif;
margin: 0;
padding: 5mm;
font-size: 12px;
padding: 0;
width: 100mm;
height: 150mm;
color: #000;
font-size: 10px; /* Reduced base font size */
overflow: hidden; /* Prevent spillover */
}
.container {
width: 94mm;
height: 144mm; /* Reduced height to be safely inside 150mm */
margin: 3mm auto; /* 3mm top/bottom margin */
border: 2px solid #000;
height: 138mm;
display: flex;
flex-direction: column;
page-break-inside: avoid;
background: #fff;
overflow: hidden;
}
.header {
border-bottom: 2px solid #000;
padding: 5px;
padding: 3px;
text-align: center;
height: 20mm;
height: 18mm; /* Reduced */
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.header img {
max-height: 15mm;
max-width: 80mm;
max-height: 100%;
max-width: 90%;
object-fit: contain;
}
.header h1 {
margin: 0;
font-size: 16px; /* Reduced */
}
.big-code {
font-size: 20px;
font-size: 16px; /* Reduced */
font-weight: bold;
text-align: center;
padding: 8px;
padding: 4px;
border-bottom: 2px solid #000;
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
flex-shrink: 0;
height: 10mm;
}
.address-box {
border-bottom: 1px solid #000;
padding: 8px;
padding: 5px;
flex-grow: 1;
overflow: hidden;
font-size: 10px; /* Reduced */
}
.main-info {
display: flex;
border-bottom: 2px solid #000;
flex-shrink: 0;
height: 14mm; /* Reduced */
}
.section {
padding: 8px;
padding: 2px;
flex: 1;
border-right: 1px solid #000;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
.section:last-child {
border-right: none;
}
.qr-code {
text-align: center;
padding: 10px;
padding: 3px;
border-bottom: 2px solid #000;
flex-shrink: 0;
height: 30mm; /* Reduced */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.qr-code img {
width: 30mm;
height: 30mm;
width: 22mm; /* Reduced */
height: 22mm;
}
.tracking-number {
font-size: 16px;
font-size: 12px;
font-weight: bold;
margin-top: 5px;
margin-top: 2px;
font-family: monospace;
}
.footer {
padding: 5px;
padding: 3px;
text-align: center;
font-size: 9px;
font-size: 8px; /* Reduced */
flex-shrink: 0;
height: 8mm;
display: flex;
flex-direction: column;
justify-content: center;
}
h3 {
margin: 0 0 5px 0;
font-size: 10px;
margin: 0 0 2px 0;
font-size: 9px;
text-transform: uppercase;
color: #333;
border-bottom: 1px dotted #ccc;
padding-bottom: 2px;
padding-bottom: 1px;
display: flex;
justify-content: space-between;
}
h3 span.ar { font-weight: normal; }
p { margin: 0 0 2px 0; line-height: 1.2; }
.bold { font-weight: bold; font-size: 13px; }
p { margin: 0 0 1px 0; line-height: 1.1; }
.bold { font-weight: bold; font-size: 11px; }
.dual-text {
display: flex;
flex-direction: row;
gap: 5px;
}
.ar-text {
font-family: sans-serif;
font-family: 'Noto Sans', 'Noto Sans Arabic', 'DejaVu Sans', sans-serif;
direction: rtl;
}
</style>

View File

@ -36,7 +36,7 @@
<div class="text-center mt-4">
<a href="{% url 'login' %}" class="text-decoration-none text-muted">
<i class="bi bi-arrow-left me-1"></i> {% trans "Back to Login" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-1"></i> {% trans "Back to Login" %}
</a>
</div>
</div>

View File

@ -5,7 +5,7 @@
<div class="container py-5">
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Home" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Home" %}
</a>
</div>
<h1>{% trans "Privacy Policy" %}</h1>

View File

@ -11,7 +11,7 @@
<!-- Back to Dashboard -->
<div class="mb-4">
<a href="{% url 'dashboard' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Dashboard" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Dashboard" %}
</a>
</div>

View File

@ -5,6 +5,13 @@
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<!-- Back to Dashboard -->
<div class="mb-4">
<a href="{% url 'dashboard' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Dashboard" %}
</a>
</div>
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-5">
<div class="text-center mb-4">

View File

@ -11,7 +11,7 @@
<!-- Back to Home -->
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Home" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Home" %}
</a>
</div>

View File

@ -25,7 +25,7 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0">{% trans "Scan Parcel QR" %}</h1>
<a href="{% url 'dashboard' %}" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left"></i> {% trans "Back to Dashboard" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %}"></i> {% trans "Back to Dashboard" %}
</a>
</div>

View File

@ -9,7 +9,7 @@
<!-- Back to Dashboard -->
<div class="mb-4">
<a href="{% url 'dashboard' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Dashboard" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Dashboard" %}
</a>
</div>

View File

@ -61,6 +61,17 @@
</span>
</div>
{% if parcel.status == 'pending' %}
<div class="d-flex gap-2 mb-2">
<a href="{% url 'edit_parcel' parcel.id %}" class="btn btn-sm btn-outline-info w-100" title="{% trans 'Edit Shipment' %}">
<i class="fas fa-edit me-1"></i> {% trans "Edit" %}
</a>
<a href="{% url 'cancel_parcel' parcel.id %}" class="btn btn-sm btn-outline-danger w-100" title="{% trans 'Cancel Shipment' %}" onclick="return confirm('{% trans "Are you sure you want to cancel this shipment?" %}');">
<i class="fas fa-times me-1"></i> {% trans "Cancel" %}
</a>
</div>
{% endif %}
{% if parcel.payment_status == 'pending' %}
{% if payments_enabled %}
<a href="{% url 'initiate_payment' parcel.id %}" class="btn btn-sm btn-outline-primary w-100 mb-2">
@ -126,6 +137,15 @@
</div>
<div class="d-flex gap-2 w-100 justify-content-md-end">
{% if parcel.status == 'pending' %}
<a href="{% url 'edit_parcel' parcel.id %}" class="btn btn-sm btn-outline-info" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<a href="{% url 'cancel_parcel' parcel.id %}" class="btn btn-sm btn-outline-danger" title="{% trans 'Cancel' %}" onclick="return confirm('{% trans "Are you sure you want to cancel this shipment?" %}');">
<i class="fas fa-times"></i>
</a>
{% endif %}
<a href="{% url 'generate_parcel_label' parcel.id %}" class="btn btn-sm btn-outline-dark" target="_blank" title="{% trans 'Print Label' %}">
<i class="fas fa-print"></i>
</a>

View File

@ -5,7 +5,7 @@
<div class="container py-5">
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Home" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Home" %}
</a>
</div>
<h1>{% trans "Terms and Conditions" %}</h1>

View File

@ -7,6 +7,13 @@
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<!-- Back to Home -->
<div class="mb-4">
<a href="{% url 'index' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Home" %}
</a>
</div>
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5">
<h2 class="text-center mb-4">{% trans "Track Your Shipment" %}</h2>

View File

@ -11,7 +11,7 @@
<!-- Back to Edit Profile -->
<div class="mb-4">
<a href="{% url 'edit_profile' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Edit Profile" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Edit Profile" %}
</a>
</div>

View File

@ -11,7 +11,7 @@
<!-- Back to Register -->
<div class="mb-4">
<a href="{% url 'register' %}" class="btn btn-link text-decoration-none text-muted ps-0">
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Register" %}
<i class="bi {% if LANGUAGE_BIDI %}bi-arrow-right{% else %}bi-arrow-left{% endif %} me-2"></i>{% trans "Back to Register" %}
</a>
</div>

View File

@ -34,6 +34,8 @@ urlpatterns = [
path('dashboard/', views.dashboard, name='dashboard'),
path('scan-qr/', views.scan_qr_view, name='scan_qr'),
path('shipment-request/', views.shipment_request, name='shipment_request'),
path('parcel/<int:parcel_id>/edit/', views.edit_parcel, name='edit_parcel'),
path('parcel/<int:parcel_id>/cancel/', views.cancel_parcel, name='cancel_parcel'),
path('track/', views.track_parcel, name='track'),
path('accept-parcel/<int:parcel_id>/', views.accept_parcel, name='accept_parcel'),
path('update-status/<int:parcel_id>/', views.update_status, name='update_status'),

View File

@ -848,4 +848,36 @@ def update_parcel_status_ajax(request):
return JsonResponse({'success': True})
except Exception as e:
return JsonResponse({'success': False, 'error': str(e)})
return JsonResponse({'success': False, 'error': str(e)})
@login_required
def edit_parcel(request, parcel_id):
parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user)
if parcel.status != 'pending':
messages.error(request, _("You can only edit pending shipments."))
return redirect('dashboard')
if request.method == 'POST':
form = ParcelForm(request.POST, instance=parcel)
if form.is_valid():
form.save()
messages.success(request, _("Shipment updated successfully."))
return redirect('dashboard')
else:
form = ParcelForm(instance=parcel)
return render(request, 'core/edit_parcel.html', {'form': form, 'parcel': parcel})
@login_required
def cancel_parcel(request, parcel_id):
parcel = get_object_or_404(Parcel, id=parcel_id, shipper=request.user)
if parcel.status != 'pending':
messages.error(request, _("You can only cancel pending shipments."))
else:
parcel.status = 'cancelled'
parcel.save()
messages.success(request, _("Shipment cancelled successfully."))
return redirect('dashboard')

Binary file not shown.

View File

@ -772,7 +772,8 @@ msgstr "مرحباً،"
msgid ""
"You are receiving this email because you requested a password reset for your "
"account at"
msgstr "تتلقى هذه الرسالة لأنك طلبت إعادة تعيين كلمة المرور لحسابك في"
msgstr ""
"تتلقى هذه الرسالة لأنك طلبت إعادة تعيين كلمة المرور لحسابك في"
#: core/templates/core/emails/password_reset_email.html:11
msgid "Please click the button below to choose a new password:"
@ -879,7 +880,8 @@ msgstr "أدرج طردك"
#: core/templates/core/index.html:64
msgid ""
"Enter shipment details, weight, and delivery addresses. It's quick and easy."
msgstr "أدخل تفاصيل الشحنة والوزن وعناوين التوصيل. إنه سريع وسهل."
msgstr ""
"أدخل تفاصيل الشحنة والوزن وعناوين التوصيل. إنه سريع وسهل."
#: core/templates/core/index.html:72
msgid "Connect with Driver"
@ -888,7 +890,8 @@ msgstr "تواصل مع السائق"
#: core/templates/core/index.html:73
msgid ""
"A verified car owner near you picks up the parcel and starts the journey."
msgstr "يقوم صاحب سيارة تم التحقق منه بالقرب منك باستلام الطرد وبدء الرحلة."
msgstr ""
"يقوم صاحب سيارة تم التحقق منه بالقرب منك باستلام الطرد وبدء الرحلة."
#: core/templates/core/index.html:81
msgid "Secure Delivery"
@ -1330,3 +1333,60 @@ msgstr "لا توجد شحنات بعد. ابدأ الشحن الآن!"
msgid "Shipments"
msgstr "شحنات"
msgid "Track Shipment"
msgstr "تتبع الشحنة"
msgid "Track Your Shipment"
msgstr "تتبع شحنتك"
msgid "Enter Tracking ID (e.g. TRK123456789)"
msgstr "أدخل رقم التتبع (مثال: TRK123456789)"
msgid "Shipment Status"
msgstr "حالة الشحنة"
msgid "Order Placed"
msgstr "تم الطلب"
msgid "On the Way"
msgstr "في الطريق"
msgid "Current Status"
msgstr "الحالة الحالية"
msgid "Last Updated"
msgstr "آخر تحديث"
msgid "Enter your tracking number above to see shipment details."
msgstr "أدخل رقم التتبع أعلاه لرؤية تفاصيل الشحنة."
msgid "Label"
msgstr "الملصق"
msgid "Invoice"
msgstr "الفاتورة"
msgid "Edit"
msgstr "تعديل"
msgid "Edit Shipment"
msgstr "تعديل الشحنة"
msgid "Cancel Shipment"
msgstr "إلغاء الشحنة"
msgid "Print Label"
msgstr "طباعة الملصق"
msgid "Are you sure you want to cancel this shipment?"
msgstr "هل أنت متأكد أنك تريد إلغاء هذه الشحنة؟"
msgid "Point your camera at the Parcel Label QR Code"
msgstr "وجه الكاميرا نحو رمز الاستجابة السريعة (QR) الخاص بالملصق"
msgid "Scan QR Code"
msgstr "مسح رمز الاستجابة السريعة"
msgid "Tracking No"
msgstr "رقم التتبع"