From 5976b14df79dadf576beb2a3d8e36b6b0e25bc95 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 23 Jan 2026 10:23:21 +0000 Subject: [PATCH] dem5 --- core/__pycache__/forms.cpython-311.pyc | Bin 6993 -> 7290 bytes core/__pycache__/models.cpython-311.pyc | Bin 8272 -> 8407 bytes core/__pycache__/urls.cpython-311.pyc | Bin 1484 -> 1595 bytes core/__pycache__/views.cpython-311.pyc | Bin 10479 -> 11931 bytes core/forms.py | 5 +- core/migrations/0003_truck_is_approved.py | 18 ++++ .../0003_truck_is_approved.cpython-311.pyc | Bin 0 -> 868 bytes core/models.py | 3 +- core/templates/core/admin_dashboard.html | 60 +++++++++++- .../templates/core/truck_owner_dashboard.html | 89 +++++++++++++----- core/urls.py | 1 + core/views.py | 29 +++++- 12 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 core/migrations/0003_truck_is_approved.py create mode 100644 core/migrations/__pycache__/0003_truck_is_approved.cpython-311.pyc diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 5638d921c8dda43ab380be3ef6778473bd3d32b4..d73f1af6833105ddc3b9e29b4616d285af0cbc4d 100644 GIT binary patch delta 610 zcmca;_RE5IIWI340}x#HF3$YBk$0gOQxxOm4PxnxWs@bu^&(Q3)-W$)VqjPe#1K%! zki`aLr?5!Em<;jkFeWY)S#T8#I3^p43r{X!<*zSRE)j-lWMD{PUB(Es42U5Bmr?Ox zH-prqFa*P~CY#?ameS(Xq7Y4{Tdeuzd8tLWxHF666AKE8^2<_Fin4$js`MlCOBHfU zi%S$T63bLm6%z9lU-dnJIdj+>>XDn~2|HORdN(E-5au z1e$V-Gb1&pAigBEV)7YrcgC%gMI@~1Svb=epXwN{@x89&a7oAEK*@#3*b6!i7j@#U z=)`rn^mxx;zrv$%g-7#-u=o_~8Rb`m)vpK}To*RKBy4_B*z$_7xTNE7pyYy%!$lpRD>^ qSV26J$jR|iR~f4}n@Te=I`c7tv|}ebQhV}0g5|#8P*J1`^bP>4#Z2x1 diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 6eff2693246ca351c2ffd5e6e57796030a381246..cab1269d3e44c64c28c4d771fa75aa351b11c8a2 100644 GIT binary patch delta 715 zcmccMaNUt_IWI340}v#67iU@vZsgm_%6Me+5!Pa+FeZjn&J>Ylj0_B`ffxc(MAwKd zV*-i*F$6@31JyBSNx=9id~3u}^+ZXgNVG6SNu@{zGiXXp4(GTlTE*>Itl(HsP?TSm zn&PI(SR?|}KG}q`pHXe{5l&4;>B;XnFG}$^<>%+5Cg!1D*%dXj1FRQ>+%5{aT@i9?@V>FRfk&5x(Pr{G zfjMl^KzoW}CI<-0F~&~L7gW~p1_}6p2zd~p1tJtcgdB+QgAtmWcL`2qWc1q{Ak4$|fHWQ*%rJGH-Dt=jZ08=9Lr|X@F#6K?Huw zGeAl}g#Bi9aYIH{5HoqApy=iziAF}o@X22!J^jHBM6+$&r690mb)S4V9{~rLT%&6c1 delta 551 zcmccac)@{hIWI340}#BjD9-#Uu#s;oD^nlSF{9Kxhl9MgDE>2eEwq;zqIhnheaq>K2iOur7 zqAZNolT8KZutfsRD2keVT~LlOdh$0xWj0TcfY;=YQW9J~ASQ^=*z71Ym66eB^L1f1 zW=7x1_rzRPVnCA2Ai@@=tVkWiDg_ZNAfjZlySSQs9FTd7BRM}eH#M)MxJUye6AdDe zY)S+1L4@7rb>fDMjA@%6NX%kn44Ygn<*5sH2Aa|JAPr!X*^~40N`NLqjB5Zpyc#46 zA_680OHbkeu{0Tr>L;(2p1@c?*-plZwG${5xw%z_nbEu%B+GV-JtMI=v81G^s2j+? z#ZsJDmRiIKWEQo6h*ppy<|44QZ6JY;$@^thSo?s?xXCYMe;9)u3HAoqa*+8&AlV`< z5TO7f}J2r-&{V8A3g+;=q6al<`?@qxxUQi4RycrBj)+gkaJsGHckD z0rji~VhBj*i4snc4Q9}ko2 z#e?N0A7k3XC^EU3xr?btcrq7D0GAxlP(~mwu9%#{@ Vne571!7s_n&(y#Tf<-bwwE%hOHSGWZ delta 112 zcmdnZbB0@eIWI340}zN<7H7sXGcY^`abSQS%J|H*QT;C?S2}l;P>OUggQm>nAf}m< vC7E|K3QxYu+%-9c#g|JKsFo3kixVdAW_dArH)|okI1fKl12+g3Ndsj7&ruh9 diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 60cc7da51d2c2e11d0644e895fc427b8a74eb5a5..5089a781f0700c15785556fbf0fb0f9104bb9fb6 100644 GIT binary patch delta 2506 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 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 0000000000000000000000000000000000000000..0e0325d499a891b73958684504fa69ab768ee7d3 GIT binary patch literal 868 zcmZuvJ#W-N5Z$$XKHIrS#6k)vD54;UD~L}}&_qa~2nvMgBqRz8Y2~|}Tzv5tUORkL zS5Q!<%RdMp@+0ySf^@}cTPiw7mns#zK05)0U3)xlc6R5@TYsIOw~!dgOXi+A` z0j=UapYleT!smQOyd+8EeV`kk<~G^g^$Lj+O$s|+9%Q_=4{0xEKq4=MwkkxCLX?PW zGR7M_J_K}IkTggcCxlysh`c-i;kO8RmwSQCm54$D5rwGl152g$+*qe{L!Oap61JYj zaR6RahPV|cP+h`zG?hACY&yGf2u|M1qbzse1N8GOPM!C0y2lc)4~~?_xw{*c)L+m$T53xrGZ=xv7t~3JaNczF1>pX|lLHSy-OfD+l+-_R2Rn zd3b7ff7;!#-7T7$X`LZq&ZQ|--PT7h(G)&!{ZQv@-X$ y@GgwCnTk)-B>}}RKjT=a7-K;Xw@=Z7>rbJ#uwJ0+=D-@?xOXNO&i}Jo*8Kw#&*uOD literal 0 HcmV?d00001 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." %}