diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 5638d92..d73f1af 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 6eff269..cab1269 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 244821d..6f3a076 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 60cc7da..5089a78 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/forms.py b/core/forms.py index 5970473..f03e4b7 100644 --- a/core/forms.py +++ b/core/forms.py @@ -77,4 +77,7 @@ class BidForm(forms.ModelForm): user = kwargs.pop('user', None) super().__init__(*args, **kwargs) if user: - self.fields['truck'].queryset = Truck.objects.filter(owner=user) \ No newline at end of file + # Only allow bidding with approved trucks + self.fields['truck'].queryset = Truck.objects.filter(owner=user, is_approved=True) + if not self.fields['truck'].queryset.exists(): + self.fields['truck'].help_text = _("You must have an approved truck to place a bid.") diff --git a/core/migrations/0003_truck_is_approved.py b/core/migrations/0003_truck_is_approved.py new file mode 100644 index 0000000..c9ad86f --- /dev/null +++ b/core/migrations/0003_truck_is_approved.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-01-23 10:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_shipment_message_truck_shipment_assigned_truck_bid'), + ] + + operations = [ + migrations.AddField( + model_name='truck', + name='is_approved', + field=models.BooleanField(default=False, verbose_name='Is Approved'), + ), + ] diff --git a/core/migrations/__pycache__/0003_truck_is_approved.cpython-311.pyc b/core/migrations/__pycache__/0003_truck_is_approved.cpython-311.pyc new file mode 100644 index 0000000..0e0325d Binary files /dev/null and b/core/migrations/__pycache__/0003_truck_is_approved.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index de81f2d..f1f1ddc 100644 --- a/core/models.py +++ b/core/models.py @@ -32,6 +32,7 @@ class Truck(models.Model): registration_back = models.ImageField(_('Registration Back'), upload_to='docs/', blank=True, null=True) driver_license = models.ImageField(_('Driver License'), upload_to='docs/', blank=True, null=True) + is_approved = models.BooleanField(_('Is Approved'), default=False) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): @@ -96,4 +97,4 @@ def save_user_profile(sender, instance, **kwargs): if hasattr(instance, 'profile'): instance.profile.save() else: - Profile.objects.create(user=instance) + Profile.objects.create(user=instance) \ No newline at end of file diff --git a/core/templates/core/admin_dashboard.html b/core/templates/core/admin_dashboard.html index dd8715d..0b50a02 100644 --- a/core/templates/core/admin_dashboard.html +++ b/core/templates/core/admin_dashboard.html @@ -17,7 +17,7 @@ -
+
@@ -48,6 +48,62 @@
+ +
+
+
{% trans "Pending Truck Approvals" %}
+
+
+
+ + + + + + + + + + + + {% for truck in pending_trucks %} + + + + + + + + {% empty %} + + + + {% endfor %} + +
{% trans "Owner" %}{% trans "Truck Details" %}{% trans "Plate No" %}{% trans "Documents" %}{% trans "Actions" %}
{{ truck.owner.username }}
{{ truck.owner.email }}
+ {{ truck.truck_type }}
+ {{ truck.model }} ({{ truck.year }}) - {{ truck.color }} +
{{ truck.plate_no }} +
+ {% if truck.truck_picture %} + {% trans "Photo" %} + {% endif %} + {% if truck.registration_front %} + {% trans "Reg. Front" %} + {% endif %} + {% if truck.registration_back %} + {% trans "Reg. Back" %} + {% endif %} +
+
+ + {% trans "Approve" %} + +
{% trans "No trucks awaiting approval." %}
+
+
+
+

{% trans "Quick Actions" %}

@@ -101,4 +157,4 @@ transition: all 0.3s ease; } -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/truck_owner_dashboard.html b/core/templates/core/truck_owner_dashboard.html index 919e63a..0be8ea6 100644 --- a/core/templates/core/truck_owner_dashboard.html +++ b/core/templates/core/truck_owner_dashboard.html @@ -1,10 +1,14 @@ {% extends "base.html" %} {% load i18n %} +{% load static %} {% block content %}
-

{% trans "Truck Owner Dashboard" %}

+
+

{% trans "Truck Owner Dashboard" %}

+

{% trans "Manage your fleet and active bids." %}

+
-
-
-
-
-
{% trans "My Trucks" %}
-
-
- {% if trucks %} -
    - {% for truck in trucks %} -
  • - {{ truck.truck_type }} - {{ truck.plate_no }} - {{ truck.load_capacity }} -
  • - {% endfor %} -
+ +

{% trans "My Approved Trucks" %}

+
+ {% if trucks %} + {% for truck in trucks %} +
+
+ {% if truck.truck_picture %} + {{ truck.truck_type }} {% else %} -

{% trans "No trucks registered." %}

+
+ +
{% endif %} +
+
{{ truck.truck_type }}
+

{% trans "Plate No:" %} {{ truck.plate_no }}

+

{% trans "Model:" %} {{ truck.model }} ({{ truck.year }})

+

{% trans "Capacity:" %} {{ truck.load_capacity }}

+
+ +
+
+ {% endfor %} + {% else %} +
+

{% trans "No approved trucks yet." %}

+
+ {% endif %} +
+ + + {% if pending_trucks %} +

{% trans "Pending Approval" %}

+
+ {% for truck in pending_trucks %} +
+
+
+
{{ truck.truck_type }}
+

{% trans "Plate No:" %} {{ truck.plate_no }}

+

{% trans "Submitted on:" %} {{ truck.created_at|date }}

+
+
-
-
+ {% endfor %} +
+ {% endif %} + +
+
+
{% trans "My Active Bids" %}
- + + {% for bid in bids %} - + + {% empty %} - + {% endfor %} @@ -76,4 +115,4 @@ -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index ba2a209..6d4fb4d 100644 --- a/core/urls.py +++ b/core/urls.py @@ -9,6 +9,7 @@ urlpatterns = [ path("logout/", auth_views.LogoutView.as_view(), name="logout"), path("dashboard/", views.dashboard, name="dashboard"), path("truck/register/", views.truck_register, name="truck_register"), + path("truck//approve/", views.approve_truck, name="approve_truck"), path("shipment/post/", views.post_shipment, name="post_shipment"), path("marketplace/", views.marketplace, name="marketplace"), path("shipment//", views.shipment_detail, name="shipment_detail"), diff --git a/core/views.py b/core/views.py index e9f193f..b069d85 100644 --- a/core/views.py +++ b/core/views.py @@ -41,18 +41,22 @@ def dashboard(request): my_shipments = Shipment.objects.filter(shipper=request.user).order_by('-created_at') return render(request, 'core/shipper_dashboard.html', {'shipments': my_shipments}) elif profile.role == 'TRUCK_OWNER': - my_trucks = Truck.objects.filter(owner=request.user) + approved_trucks = Truck.objects.filter(owner=request.user, is_approved=True) + pending_trucks = Truck.objects.filter(owner=request.user, is_approved=False) my_bids = Bid.objects.filter(truck_owner=request.user).order_by('-created_at') return render(request, 'core/truck_owner_dashboard.html', { - 'trucks': my_trucks, + 'trucks': approved_trucks, + 'pending_trucks': pending_trucks, 'bids': my_bids }) elif profile.role == 'ADMIN' or request.user.is_superuser: + pending_trucks = Truck.objects.filter(is_approved=False).order_by('-created_at') context = { 'total_users': User.objects.count(), 'total_trucks': Truck.objects.count(), 'total_shipments': Shipment.objects.count(), 'total_bids': Bid.objects.count(), + 'pending_trucks': pending_trucks, } return render(request, 'core/admin_dashboard.html', context) else: @@ -69,8 +73,9 @@ def truck_register(request): if form.is_valid(): truck = form.save(commit=False) truck.owner = request.user + truck.is_approved = False # Ensure it stays false on new reg truck.save() - messages.success(request, _("Truck registered successfully!")) + messages.success(request, _("Truck registered successfully! It will be visible after admin approval.")) return redirect('dashboard') else: messages.error(request, _("There was an error in your registration. Please check the form.")) @@ -79,6 +84,17 @@ def truck_register(request): return render(request, 'core/truck_register.html', {'form': form}) +@login_required +def approve_truck(request, truck_id): + if not (request.user.profile.role == 'ADMIN' or request.user.is_superuser): + return redirect('dashboard') + + truck = get_object_or_404(Truck, id=truck_id) + truck.is_approved = True + truck.save() + messages.success(request, _("Truck approved successfully!")) + return redirect('dashboard') + @login_required def post_shipment(request): if request.user.profile.role != 'SHIPPER': @@ -113,6 +129,11 @@ def place_bid(request, shipment_id): if request.user.profile.role != 'TRUCK_OWNER': return redirect('dashboard') + # Optional: Only allow bidding if user has at least one approved truck + if not Truck.objects.filter(owner=request.user, is_approved=True).exists(): + messages.warning(request, _("You must have at least one approved truck to place a bid.")) + return redirect('dashboard') + if request.method == 'POST': form = BidForm(request.POST, user=request.user) if form.is_valid(): @@ -159,4 +180,4 @@ def accept_bid(request, bid_id): bid.shipment.save() messages.success(request, _("Bid accepted! Shipment is now in progress.")) - return redirect('shipment_detail', shipment_id=bid.shipment.id) \ No newline at end of file + return redirect('shipment_detail', shipment_id=bid.shipment.id)
{% trans "Shipment" %} {% trans "Amount" %} {% trans "Status" %}{% trans "Date" %}
{{ bid.shipment.origin }} - {{ bid.shipment.destination }}{{ bid.amount }}${{ bid.amount }} - + {{ bid.get_status_display }} {{ bid.created_at|date }}
{% trans "No bids placed." %}{% trans "No bids placed yet." %}