changes19
This commit is contained in:
parent
459f38ada6
commit
3da5d477df
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,7 +4,7 @@ from django.shortcuts import render
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType
|
||||
from .whatsapp import send_whatsapp_message
|
||||
|
||||
@admin.register(Country)
|
||||
@ -12,6 +12,17 @@ class CountryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'code', 'is_default')
|
||||
list_editable = ('is_default',)
|
||||
|
||||
@admin.register(City)
|
||||
class CityAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'country')
|
||||
list_filter = ('country',)
|
||||
search_fields = ('name',)
|
||||
|
||||
@admin.register(TruckType)
|
||||
class TruckTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'name_ar')
|
||||
search_fields = ('name', 'name_ar')
|
||||
|
||||
@admin.register(Profile)
|
||||
class ProfileAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'role', 'country_code', 'phone_number')
|
||||
@ -20,20 +31,21 @@ class ProfileAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Truck)
|
||||
class TruckAdmin(admin.ModelAdmin):
|
||||
list_display = ('truck_type', 'model', 'plate_no', 'owner', 'load_capacity')
|
||||
search_fields = ('plate_no', 'owner__username', 'truck_type')
|
||||
list_display = ('display_truck_type', 'model', 'plate_no', 'owner', 'load_capacity')
|
||||
search_fields = ('plate_no', 'owner__username', 'model')
|
||||
list_filter = ('truck_type_link', 'is_approved')
|
||||
|
||||
@admin.register(Shipment)
|
||||
class ShipmentAdmin(admin.ModelAdmin):
|
||||
list_display = ('origin', 'destination', 'shipper', 'status', 'delivery_date')
|
||||
list_filter = ('status', 'delivery_date')
|
||||
search_fields = ('origin', 'destination', 'shipper__username')
|
||||
list_display = ('display_origin', 'display_destination', 'shipper', 'status', 'delivery_date')
|
||||
list_filter = ('status', 'delivery_date', 'required_truck_type_link')
|
||||
search_fields = ('origin', 'destination', 'shipper__username', 'description')
|
||||
|
||||
@admin.register(Bid)
|
||||
class BidAdmin(admin.ModelAdmin):
|
||||
list_display = ('shipment', 'truck_owner', 'amount', 'status')
|
||||
list_filter = ('status',)
|
||||
search_fields = ('shipment__origin', 'shipment__destination', 'truck_owner__username')
|
||||
search_fields = ('shipment__description', 'truck_owner__username')
|
||||
|
||||
@admin.register(Message)
|
||||
class MessageAdmin(admin.ModelAdmin):
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from django import forms
|
||||
from .models import Truck, Shipment, Bid, Profile, Country, OTPCode, City
|
||||
from .models import Truck, Shipment, Bid, Profile, Country, OTPCode, City, TruckType
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.contrib.auth.models import User
|
||||
@ -64,13 +64,12 @@ class TruckForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Truck
|
||||
fields = [
|
||||
'truck_type', 'truck_type_ar', 'model', 'model_ar', 'year', 'plate_no',
|
||||
'truck_type_link', 'model', 'model_ar', 'year', 'plate_no',
|
||||
'load_capacity', 'load_capacity_ar', 'color', 'color_ar', 'registration_expiry_date',
|
||||
'truck_picture', 'registration_front', 'registration_back', 'driver_license'
|
||||
]
|
||||
widgets = {
|
||||
'truck_type': forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('e.g. Flatbed')}),
|
||||
'truck_type_ar': forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('مثلا سطحة')}),
|
||||
'truck_type_link': forms.Select(attrs={'class': 'form-select'}),
|
||||
'model': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
'model_ar': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
'year': forms.NumberInput(attrs={'class': 'form-control'}),
|
||||
@ -85,12 +84,16 @@ class TruckForm(forms.ModelForm):
|
||||
'registration_back': forms.FileInput(attrs={'class': 'form-control'}),
|
||||
'driver_license': forms.FileInput(attrs={'class': 'form-control'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['truck_type_link'].label = _("Truck Type")
|
||||
|
||||
class ShipmentForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Shipment
|
||||
fields = [
|
||||
'description', 'weight',
|
||||
'description', 'weight', 'required_truck_type_link',
|
||||
'origin_country', 'origin_city',
|
||||
'destination_country', 'destination_city',
|
||||
'delivery_date'
|
||||
@ -98,12 +101,17 @@ class ShipmentForm(forms.ModelForm):
|
||||
widgets = {
|
||||
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
||||
'weight': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
'required_truck_type_link': forms.Select(attrs={'class': 'form-select'}),
|
||||
'origin_country': forms.Select(attrs={'class': 'form-select location-selector', 'data-type': 'origin'}),
|
||||
'origin_city': forms.Select(attrs={'class': 'form-select'}),
|
||||
'destination_country': forms.Select(attrs={'class': 'form-select location-selector', 'data-type': 'destination'}),
|
||||
'destination_city': forms.Select(attrs={'class': 'form-select'}),
|
||||
'delivery_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['required_truck_type_link'].label = _("Truck Type")
|
||||
|
||||
class BidForm(forms.ModelForm):
|
||||
class Meta:
|
||||
@ -127,6 +135,7 @@ class BidForm(forms.ModelForm):
|
||||
class ShipperOfferForm(forms.Form):
|
||||
description = forms.CharField(label=_('Goods Description'), widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}))
|
||||
weight = forms.CharField(label=_('Weight/Volume'), widget=forms.TextInput(attrs={'class': 'form-control'}))
|
||||
required_truck_type_link = forms.ModelChoiceField(label=_('Required Truck Type'), queryset=TruckType.objects.all(), widget=forms.Select(attrs={'class': 'form-select'}))
|
||||
|
||||
origin_country = forms.ModelChoiceField(queryset=Country.objects.all(), widget=forms.Select(attrs={'class': 'form-select location-selector', 'data-type': 'origin'}))
|
||||
origin_city = forms.ModelChoiceField(queryset=City.objects.all(), widget=forms.Select(attrs={'class': 'form-select'}))
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-23 15:12
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0010_shipment_destination_country_shipment_origin_country_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='TruckType',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='Name (EN)')),
|
||||
('name_ar', models.CharField(blank=True, max_length=100, verbose_name='Name (AR)')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Truck Type',
|
||||
'verbose_name_plural': 'Truck Types',
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='truck',
|
||||
name='truck_type',
|
||||
field=models.CharField(blank=True, max_length=100, verbose_name='Truck Type (EN)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shipment',
|
||||
name='required_truck_type_link',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.trucktype', verbose_name='Required Truck Type'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='truck',
|
||||
name='truck_type_link',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.trucktype', verbose_name='Truck Type (New)'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
@ -32,6 +32,19 @@ class City(models.Model):
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.country.name})"
|
||||
|
||||
class TruckType(models.Model):
|
||||
name = models.CharField(_('Name (EN)'), max_length=100)
|
||||
name_ar = models.CharField(_('Name (AR)'), max_length=100, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Truck Type')
|
||||
verbose_name_plural = _('Truck Types')
|
||||
|
||||
def __str__(self):
|
||||
if get_language() == 'ar' and self.name_ar:
|
||||
return self.name_ar
|
||||
return self.name
|
||||
|
||||
class Profile(models.Model):
|
||||
ROLE_CHOICES = (
|
||||
('SHIPPER', _('Shipper (Need Goods Moved)')),
|
||||
@ -73,8 +86,11 @@ class OTPCode(models.Model):
|
||||
class Truck(models.Model):
|
||||
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='trucks')
|
||||
|
||||
# Using a fresh name to avoid conflict with partially created fields
|
||||
truck_type_link = models.ForeignKey(TruckType, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Truck Type (New)'))
|
||||
|
||||
# English fields
|
||||
truck_type = models.CharField(_('Truck Type (EN)'), max_length=100)
|
||||
truck_type = models.CharField(_('Truck Type (EN)'), max_length=100, blank=True)
|
||||
model = models.CharField(_('Model (EN)'), max_length=100)
|
||||
load_capacity = models.CharField(_('Load Capacity (EN)'), max_length=100)
|
||||
color = models.CharField(_('Color (EN)'), max_length=50)
|
||||
@ -99,10 +115,14 @@ class Truck(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.display_truck_type} - {self.plate_no}"
|
||||
if self.truck_type_link:
|
||||
return f"{self.truck_type_link} - {self.plate_no}"
|
||||
return f"{self.truck_type} - {self.plate_no}"
|
||||
|
||||
@property
|
||||
def display_truck_type(self):
|
||||
if self.truck_type_link:
|
||||
return str(self.truck_type_link)
|
||||
if get_language() == 'ar' and self.truck_type_ar:
|
||||
return self.truck_type_ar
|
||||
return self.truck_type
|
||||
@ -136,6 +156,9 @@ class Shipment(models.Model):
|
||||
description = models.TextField(_('Goods Description'))
|
||||
weight = models.CharField(_('Weight/Volume'), max_length=100)
|
||||
|
||||
# Using a fresh name
|
||||
required_truck_type_link = models.ForeignKey(TruckType, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Required Truck Type'))
|
||||
|
||||
origin_country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True, related_name='shipments_origin')
|
||||
origin_city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, related_name='shipments_origin')
|
||||
destination_country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True, related_name='shipments_destination')
|
||||
|
||||
@ -20,13 +20,18 @@
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">{% trans "Weight/Volume" %}</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 fw-bold">{% trans "Requested Delivery Date" %}</label>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">{% trans "Truck Type" %}</label>
|
||||
{{ form.required_truck_type_link }}
|
||||
{% if form.required_truck_type_link.errors %}<div class="text-danger small">{{ form.required_truck_type_link.errors }}</div>{% endif %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">{% trans "Delivery Date" %}</label>
|
||||
{{ form.delivery_date }}
|
||||
{% if form.delivery_date.errors %}<div class="text-danger small">{{ form.delivery_date.errors }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
@ -17,11 +17,21 @@
|
||||
<h5 class="text-muted small text-uppercase fw-bold">{% trans "Shipment Details" %}</h5>
|
||||
<p class="lead fw-normal">{{ shipment.description }}</p>
|
||||
<div class="row mt-4">
|
||||
<div class="col-6 mb-3">
|
||||
<div class="col-md-4 mb-3">
|
||||
<small class="text-muted d-block text-uppercase small">{% trans "Weight / Volume" %}</small>
|
||||
<strong class="fs-5">{{ shipment.weight }}</strong>
|
||||
</div>
|
||||
<div class="col-6 mb-3">
|
||||
<div class="col-md-4 mb-3">
|
||||
<small class="text-muted d-block text-uppercase small">{% trans "Required Truck Type" %}</small>
|
||||
<strong class="fs-5">
|
||||
{% if shipment.required_truck_type_link %}
|
||||
{{ shipment.required_truck_type_link }}
|
||||
{% else %}
|
||||
<span class="text-muted opacity-50">{% trans "Any" %}</span>
|
||||
{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<small class="text-muted d-block text-uppercase small">{% trans "Requested Delivery Date" %}</small>
|
||||
<strong class="fs-5">{{ shipment.delivery_date }}</strong>
|
||||
</div>
|
||||
@ -141,4 +151,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@ -26,14 +26,20 @@
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card bg-light border-0 p-3">
|
||||
<label class="form-label fw-bold">{% trans "Truck Type" %}</label>
|
||||
{{ form.truck_type_link }}
|
||||
{{ form.truck_type_link.errors }}
|
||||
<small class="text-muted">{% trans "Select the type of your truck from the list." %}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row {% if CURRENT_LANGUAGE == "ar" %}flex-row-reverse{% endif %}">
|
||||
<div class="col-md-6 {% if CURRENT_LANGUAGE == "ar" %}border-start{% else %}border-end{% endif %}">
|
||||
<h5 class="mb-3 text-primary">{% trans "English Details" %}</h5>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{% trans "Truck Type" %}</label>
|
||||
{{ form.truck_type }}
|
||||
{{ form.truck_type.errors }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{% trans "Model" %}</label>
|
||||
{{ form.model }}
|
||||
@ -53,11 +59,6 @@
|
||||
|
||||
<div class="col-md-6">
|
||||
<h5 class="mb-3 text-success">{% trans "التفاصيل باللغة العربية" %}</h5>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{% trans "نوع الشاحنة" %}</label>
|
||||
{{ form.truck_type_ar }}
|
||||
{{ form.truck_type_ar.errors }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{% trans "الموديل" %}</label>
|
||||
{{ form.model_ar }}
|
||||
@ -157,4 +158,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user