diff --git a/assets/vm-shot-2026-01-27T10-44-32-354Z.jpg b/assets/vm-shot-2026-01-27T10-44-32-354Z.jpg
new file mode 100644
index 0000000..14ea974
Binary files /dev/null and b/assets/vm-shot-2026-01-27T10-44-32-354Z.jpg differ
diff --git a/core/__pycache__/apps.cpython-311.pyc b/core/__pycache__/apps.cpython-311.pyc
index 6f131d4..143a227 100644
Binary files a/core/__pycache__/apps.cpython-311.pyc and b/core/__pycache__/apps.cpython-311.pyc differ
diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc
index 25d2e3b..9c79858 100644
Binary files a/core/__pycache__/forms.cpython-311.pyc and b/core/__pycache__/forms.cpython-311.pyc differ
diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc
index 987996d..c579a65 100644
Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ
diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc
index 0394ab0..c895336 100644
Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ
diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc
index 782558d..ad9397a 100644
Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ
diff --git a/core/apps.py b/core/apps.py
index 8115ae6..fcb1d96 100644
--- a/core/apps.py
+++ b/core/apps.py
@@ -1,6 +1,25 @@
from django.apps import AppConfig
+from django.utils.translation import gettext_lazy as _
class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'core'
+ verbose_name = _('Masar Express Management')
+ default = True
+
+ def ready(self):
+ from django.contrib.auth.models import Permission
+
+ # Monkey-patch Permission.__str__ to show a VERY short name
+ # Standard was: "app_label | model | name" (e.g. core | country | Can add country)
+ # Previous fix: "Country | Can add country"
+ # New fix: "add Country", "change Country" (strips "Can " prefix)
+
+ def short_str(self):
+ name = str(self.name)
+ if name.startswith("Can "):
+ return name[4:]
+ return name
+
+ Permission.__str__ = short_str
\ No newline at end of file
diff --git a/core/forms.py b/core/forms.py
index 86188ba..a4477c8 100644
--- a/core/forms.py
+++ b/core/forms.py
@@ -96,14 +96,44 @@ class UserRegistrationForm(forms.ModelForm):
user.save()
# Profile is created by signal, so we update it
profile, created = Profile.objects.get_or_create(user=user)
- profile.role = self.cleaned_data['role']
+ # Handle role if it exists in cleaned_data (it might be excluded in subclasses)
+ if 'role' in self.cleaned_data:
+ profile.role = self.cleaned_data['role']
profile.phone_number = self.cleaned_data['phone_number']
profile.country = self.cleaned_data['country']
profile.governate = self.cleaned_data['governate']
profile.city = self.cleaned_data['city']
+
+ # Save extra driver fields if they exist
+ if 'profile_picture' in self.cleaned_data and self.cleaned_data['profile_picture']:
+ profile.profile_picture = self.cleaned_data['profile_picture']
+ if 'license_front_image' in self.cleaned_data and self.cleaned_data['license_front_image']:
+ profile.license_front_image = self.cleaned_data['license_front_image']
+ if 'license_back_image' in self.cleaned_data and self.cleaned_data['license_back_image']:
+ profile.license_back_image = self.cleaned_data['license_back_image']
+ if 'car_plate_number' in self.cleaned_data:
+ profile.car_plate_number = self.cleaned_data['car_plate_number']
+
profile.save()
return user
+class ShipperRegistrationForm(UserRegistrationForm):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields['role'].widget = forms.HiddenInput()
+ self.fields['role'].initial = 'shipper'
+
+class DriverRegistrationForm(UserRegistrationForm):
+ profile_picture = forms.ImageField(label=_("Profile Picture (Webcam/Upload)"), required=True, widget=forms.FileInput(attrs={'class': 'form-control', 'capture': 'user', 'accept': 'image/*'}))
+ license_front_image = forms.ImageField(label=_("License Front Image"), required=True, widget=forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'}))
+ license_back_image = forms.ImageField(label=_("License Back Image"), required=True, widget=forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'}))
+ car_plate_number = forms.CharField(label=_("Car Plate Number"), max_length=20, required=True, widget=forms.TextInput(attrs={'class': 'form-control'}))
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields['role'].widget = forms.HiddenInput()
+ self.fields['role'].initial = 'car_owner'
+
class UserProfileForm(forms.ModelForm):
first_name = forms.CharField(label=_("First Name"), max_length=150, widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(label=_("Last Name"), max_length=150, widget=forms.TextInput(attrs={'class': 'form-control'}))
@@ -347,4 +377,4 @@ class DriverRatingForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Reverse choices for CSS star rating logic (5 to 1) to ensure left-to-right filling
- self.fields['rating'].choices = [(i, str(i)) for i in range(5, 0, -1)]
\ No newline at end of file
+ self.fields['rating'].choices = [(i, str(i)) for i in range(5, 0, -1)]
diff --git a/core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py b/core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py
new file mode 100644
index 0000000..0944535
--- /dev/null
+++ b/core/migrations/0019_profile_car_plate_number_profile_license_back_image_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 5.2.7 on 2026-01-27 23:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0018_alter_otpverification_purpose'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='profile',
+ name='car_plate_number',
+ field=models.CharField(blank=True, max_length=20, verbose_name='Car Plate Number'),
+ ),
+ migrations.AddField(
+ model_name='profile',
+ name='license_back_image',
+ field=models.ImageField(blank=True, null=True, upload_to='licenses/', verbose_name='License Back Image'),
+ ),
+ migrations.AddField(
+ model_name='profile',
+ name='license_front_image',
+ field=models.ImageField(blank=True, null=True, upload_to='licenses/', verbose_name='License Front Image'),
+ ),
+ ]
diff --git a/core/migrations/__pycache__/0019_profile_car_plate_number_profile_license_back_image_and_more.cpython-311.pyc b/core/migrations/__pycache__/0019_profile_car_plate_number_profile_license_back_image_and_more.cpython-311.pyc
new file mode 100644
index 0000000..ac07d52
Binary files /dev/null and b/core/migrations/__pycache__/0019_profile_car_plate_number_profile_license_back_image_and_more.cpython-311.pyc differ
diff --git a/core/models.py b/core/models.py
index 8d068a8..db45946 100644
--- a/core/models.py
+++ b/core/models.py
@@ -73,6 +73,11 @@ class Profile(models.Model):
profile_picture = models.ImageField(_('Profile Picture'), upload_to='profile_pics/', blank=True, null=True)
address = models.CharField(_('Address'), max_length=255, blank=True)
+ # Driver specific fields
+ license_front_image = models.ImageField(_('License Front Image'), upload_to='licenses/', blank=True, null=True)
+ license_back_image = models.ImageField(_('License Back Image'), upload_to='licenses/', blank=True, null=True)
+ car_plate_number = models.CharField(_('Car Plate Number'), max_length=20, blank=True)
+
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Country'))
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'))
@@ -270,4 +275,4 @@ class DriverRating(models.Model):
class Meta:
verbose_name = _('Driver Rating')
- verbose_name_plural = _('Driver Ratings')
\ No newline at end of file
+ verbose_name_plural = _('Driver Ratings')
diff --git a/core/templates/core/register_choice.html b/core/templates/core/register_choice.html
new file mode 100644
index 0000000..92d1c89
--- /dev/null
+++ b/core/templates/core/register_choice.html
@@ -0,0 +1,73 @@
+{% extends 'base.html' %}
+{% load i18n %}
+
+{% block title %}{% trans "Register" %} | masarX{% endblock %}
+
+{% block content %}
+ {% trans "Choose how you want to join us today." %} {% trans "I want to send parcels and track my shipments easily." %} {% trans "I want to deliver parcels and earn money on my own schedule." %} {% trans "Already have an account?" %} {% trans "Login here" %}{% trans "Welcome to masarX" %}
+ {% trans "I am a Shipper" %}
+ {% trans "I am a Car Owner" %}
+ {% trans "Car Owner Registration" %}
+
+