Skip to content

Commit e4e753b

Browse files
committed
feat: orders navigation
1 parent 6f19cb2 commit e4e753b

12 files changed

Lines changed: 1241 additions & 396 deletions

File tree

backend/API_DOC.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,14 @@ All list endpoints return data in this format:
313313
"actual_arrival_datetime": null,
314314
"actual_departure_datetime": null,
315315
"notes": "First pickup",
316-
"is_completed": false
316+
"is_completed": false,
317+
"orders": [
318+
{
319+
"id": 1,
320+
"order_number": "ORD-2024-0001",
321+
"customer_name": "John Smith"
322+
}
323+
]
317324
}
318325
],
319326
"created_at": "2024-01-15T08:00:00Z",
@@ -344,7 +351,14 @@ Includes all above fields plus:
344351
"actual_arrival_datetime": null,
345352
"actual_departure_datetime": null,
346353
"notes": "First pickup",
347-
"is_completed": false
354+
"is_completed": false,
355+
"orders": [
356+
{
357+
"id": 1,
358+
"order_number": "ORD-2024-0001",
359+
"customer_name": "John Smith"
360+
}
361+
]
348362
}
349363
]
350364
}
@@ -390,10 +404,23 @@ Includes all above fields plus:
390404
"actual_arrival_datetime": null,
391405
"actual_departure_datetime": null,
392406
"notes": "First pickup",
393-
"is_completed": false
407+
"is_completed": false,
408+
"orders": [
409+
{
410+
"id": 1,
411+
"order_number": "ORD-2024-0001",
412+
"customer_name": "John Smith"
413+
}
414+
]
394415
}
395416
```
396417

418+
**Orders Field:**
419+
The `orders` field contains an array of orders that use this stop as either a pickup or delivery location. Each order includes:
420+
- `id`: Order ID for API references
421+
- `order_number`: Human-readable order number (e.g., "ORD-2024-0001")
422+
- `customer_name`: Name of the customer who placed the order
423+
397424
#### Trip Stop Order Management
398425

399426
**Creating Trip Stops with Order Conflicts:**

backend/dashmap/management/commands/reset_db.py

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -233,53 +233,92 @@ def handle(self, *args, **options):
233233
loading_stops = [s for s in stops if s.stop_type == 'loading']
234234
unloading_stops = [s for s in stops if s.stop_type == 'unloading']
235235

236-
orders_data = [
236+
# Create orders for the specific stops that will be used in trips
237+
# This ensures that trip stops will have associated orders
238+
trip_specific_orders = [
239+
# Order for Trip 1 (Paris to Marseille Export Route)
240+
# stops[0], stops[3], stops[9] -> Rungis, Marseille Port, Retail
237241
{
238242
'customer_name': 'ACME Manufacturing',
239243
'customer_company': 'ACME Corp',
240244
'customer_email': 'logistics@acme.com',
241245
'customer_phone': '+33-1-42-00-1234',
242-
'pickup_stop': loading_stops[0], # Rungis
243-
'delivery_stop': unloading_stops[0], # Carrefour Paris
246+
'pickup_stop': stops[0], # Rungis (loading)
247+
'delivery_stop': stops[9], # A retail location (should be unloading)
244248
'goods_description': 'Fresh produce and dairy products',
245249
'goods_weight': 2500.0,
246250
'goods_volume': 15.0,
247251
'goods_type': 'refrigerated',
248252
'special_instructions': 'Keep temperature at 2-4°C throughout transport'
249253
},
254+
# Order for Trip 2 (Lyon Industrial Supply)
255+
# stops[2], stops[10], stops[12] -> Lyon Hub, Auchan, Casino
250256
{
251257
'customer_name': 'TechCorp Europe',
252258
'customer_company': 'TechCorp Ltd',
253259
'customer_email': 'supply@techcorp.eu',
254260
'customer_phone': '+33-1-45-67-8900',
255-
'pickup_stop': loading_stops[4], # Toulouse Aerospace
256-
'delivery_stop': unloading_stops[7], # Frankfurt
257-
'goods_description': 'Aerospace electronic components',
261+
'pickup_stop': stops[2], # Lyon Hub (loading)
262+
'delivery_stop': stops[10], # Auchan (unloading)
263+
'goods_description': 'Industrial electronic components',
258264
'goods_weight': 850.0,
259265
'goods_volume': 5.2,
260266
'goods_type': 'fragile',
261267
'special_instructions': 'Handle with extreme care - sensitive electronics'
262268
},
269+
# Order for Trip 3 (Le Havre to Brussels)
270+
# stops[1], stops[16] -> Le Havre, Brussels
263271
{
264272
'customer_name': 'EuroConstruction',
265273
'customer_company': 'EuroConstruction SA',
266274
'customer_email': 'orders@euroconstruct.fr',
267275
'customer_phone': '+33-4-78-90-1234',
268-
'pickup_stop': loading_stops[8], # Saint-Gobain Melun
269-
'delivery_stop': unloading_stops[4], # Brussels
276+
'pickup_stop': stops[1], # Le Havre (loading)
277+
'delivery_stop': stops[16], # Brussels (unloading)
270278
'goods_description': 'Construction materials and tools',
271279
'goods_weight': 4200.0,
272280
'goods_volume': 28.0,
273281
'goods_type': 'standard',
274282
'special_instructions': 'Delivery to construction site - crane available'
275283
},
284+
# Order for Trip 4 (Toulouse Aerospace Delivery)
285+
# stops[4], stops[19], stops[21] -> Toulouse, Airbus, Tech
286+
{
287+
'customer_name': 'AeroSupply International',
288+
'customer_company': 'AeroSupply Ltd',
289+
'customer_email': 'urgent@aerosupply.com',
290+
'customer_phone': '+33-5-61-00-1234',
291+
'pickup_stop': stops[4], # Toulouse Aerospace (loading)
292+
'delivery_stop': stops[19], # Airbus (unloading)
293+
'goods_description': 'Aerospace manufacturing components',
294+
'goods_weight': 1200.0,
295+
'goods_volume': 8.5,
296+
'goods_type': 'standard',
297+
'special_instructions': 'Time-critical delivery for production line'
298+
},
299+
# Order for Trip 5 (Rhine Valley Route)
300+
# stops[5], stops[18], stops[22] -> Strasbourg, Frankfurt, Luxembourg
301+
{
302+
'customer_name': 'Rhine Logistics',
303+
'customer_company': 'Rhine Transport GmbH',
304+
'customer_email': 'operations@rhinetransport.de',
305+
'customer_phone': '+33-3-88-00-5678',
306+
'pickup_stop': stops[5], # Strasbourg Rhine Port (loading)
307+
'delivery_stop': stops[18], # Frankfurt (unloading)
308+
'goods_description': 'Industrial machinery parts',
309+
'goods_weight': 3200.0,
310+
'goods_volume': 18.0,
311+
'goods_type': 'oversized',
312+
'special_instructions': 'Requires special handling equipment'
313+
},
314+
# Additional orders for variety
276315
{
277316
'customer_name': 'PharmaLogistics',
278317
'customer_company': 'PharmaDistrib',
279318
'customer_email': 'urgent@pharmadistrib.com',
280319
'customer_phone': '+33-1-56-78-9012',
281-
'pickup_stop': loading_stops[9], # Sanofi
282-
'delivery_stop': unloading_stops[8], # Milan
320+
'pickup_stop': loading_stops[9] if len(loading_stops) > 9 else loading_stops[0], # Fallback to first if not enough
321+
'delivery_stop': unloading_stops[8] if len(unloading_stops) > 8 else unloading_stops[0],
283322
'goods_description': 'Pharmaceutical supplies and medications',
284323
'goods_weight': 320.0,
285324
'goods_volume': 2.8,
@@ -291,8 +330,8 @@ def handle(self, *args, **options):
291330
'customer_company': 'EliteStores International',
292331
'customer_email': 'procurement@elitestores.com',
293332
'customer_phone': '+33-1-44-55-6677',
294-
'pickup_stop': loading_stops[10], # LVMH Logistics
295-
'delivery_stop': unloading_stops[10], # Zurich
333+
'pickup_stop': loading_stops[10] if len(loading_stops) > 10 else loading_stops[1],
334+
'delivery_stop': unloading_stops[10] if len(unloading_stops) > 10 else unloading_stops[1],
296335
'goods_description': 'Luxury fashion and accessories',
297336
'goods_weight': 180.0,
298337
'goods_volume': 8.5,
@@ -302,7 +341,7 @@ def handle(self, *args, **options):
302341
]
303342

304343
orders = []
305-
for o_data in orders_data:
344+
for o_data in trip_specific_orders:
306345
order = Order.objects.create(
307346
customer_name=o_data['customer_name'],
308347
customer_company=o_data['customer_company'],
@@ -498,7 +537,8 @@ def handle(self, *args, **options):
498537
self.stdout.write(f'Positions: {Position.objects.count()}')
499538
self.stdout.write('\nTest data includes:')
500539
self.stdout.write('• Dashmove company with 20 heavy trucks (18-40 tons capacity)')
501-
self.stdout.write('• 5 sample orders with customer details, pickup/delivery locations, and goods information')
540+
self.stdout.write('• 7 sample orders with customer details, pickup/delivery locations, and goods information')
541+
self.stdout.write('• Orders specifically created to match trip stops for testing order linking')
502542
self.stdout.write('• 10 sample trips with different statuses')
503543
self.stdout.write('• 48 hours of position data for 10 vehicles across European routes')
504544
self.stdout.write('• Realistic heavy truck logistics operations')

backend/trips/views.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33
from django.utils.decorators import method_decorator
44
from django.views import View
55
from django.core.mail import send_mail
6+
from django.db import models
67
import json
78
import random
89
from faker import Faker
910
from datetime import datetime, date, time
1011
from .models import Trip, TripStop
11-
from orders.models import Stop
12+
from orders.models import Stop, Order
1213

14+
def get_orders_for_stop(stop):
15+
"""Get all orders that use this stop as pickup or delivery"""
16+
orders = Order.objects.filter(
17+
models.Q(pickup_stop=stop) | models.Q(delivery_stop=stop)
18+
).values('id', 'order_number', 'customer_name')
19+
return list(orders)
1320

1421

1522
@method_decorator(csrf_exempt, name='dispatch')
@@ -48,7 +55,8 @@ def get(self, request):
4855
'actual_arrival_datetime': trip_stop.actual_arrival_datetime.isoformat() if trip_stop.actual_arrival_datetime else None,
4956
'actual_departure_datetime': trip_stop.actual_departure_datetime.isoformat() if trip_stop.actual_departure_datetime else None,
5057
'notes': trip_stop.notes,
51-
'is_completed': trip_stop.is_completed
58+
'is_completed': trip_stop.is_completed,
59+
'orders': get_orders_for_stop(trip_stop.stop)
5260
})
5361

5462
data.append({
@@ -137,7 +145,8 @@ def get(self, request, pk):
137145
'actual_arrival_datetime': trip_stop.actual_arrival_datetime.isoformat() if trip_stop.actual_arrival_datetime else None,
138146
'actual_departure_datetime': trip_stop.actual_departure_datetime.isoformat() if trip_stop.actual_departure_datetime else None,
139147
'notes': trip_stop.notes,
140-
'is_completed': trip_stop.is_completed
148+
'is_completed': trip_stop.is_completed,
149+
'orders': get_orders_for_stop(trip_stop.stop)
141150
})
142151

143152
return JsonResponse({

frontend/src/App.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import { AuthPage } from './components/auth/AuthPage'
66
import { Layout } from './components/layout/Layout'
77
import { VehicleManagement } from './components/vehicles/VehicleManagement'
88
import { OrderManagement } from './components/orders/OrderManagement'
9+
import { OrderDetailPage } from './components/orders/OrderDetailPage'
910
import { TripManagement } from './components/trips/TripManagement'
11+
import { TripDetailPage } from './components/trips/TripDetailPage'
1012
import { Settings } from './components/settings/Settings'
1113
import MapView from './components/maps/MapView'
1214

@@ -44,6 +46,14 @@ const AppContent: React.FC = () => {
4446
</Layout>
4547
}
4648
/>
49+
<Route
50+
path="/trips/:id"
51+
element={
52+
<Layout>
53+
<TripDetailPage />
54+
</Layout>
55+
}
56+
/>
4757
<Route
4858
path="/vehicles"
4959
element={
@@ -60,6 +70,14 @@ const AppContent: React.FC = () => {
6070
</Layout>
6171
}
6272
/>
73+
<Route
74+
path="/orders/:id"
75+
element={
76+
<Layout>
77+
<OrderDetailPage />
78+
</Layout>
79+
}
80+
/>
6381
<Route
6482
path="/settings"
6583
element={

0 commit comments

Comments
 (0)