mashrur950 commited on
Commit
580a4eb
·
1 Parent(s): 807de16

add new field driver location

Browse files
chat/tools.py CHANGED
@@ -141,7 +141,7 @@ TOOLS_SCHEMA = [
141
  },
142
  {
143
  "name": "create_driver",
144
- "description": "Create a new delivery driver in the database. Use this to onboard new drivers to the fleet.",
145
  "input_schema": {
146
  "type": "object",
147
  "properties": {
@@ -159,12 +159,24 @@ TOOLS_SCHEMA = [
159
  },
160
  "vehicle_type": {
161
  "type": "string",
162
- "description": "Type of vehicle: van, truck, car, motorcycle (default: van)"
163
  },
164
  "vehicle_plate": {
165
  "type": "string",
166
  "description": "Vehicle license plate number (optional)"
167
  },
 
 
 
 
 
 
 
 
 
 
 
 
168
  "capacity_kg": {
169
  "type": "number",
170
  "description": "Vehicle cargo capacity in kilograms (default: 1000.0)"
@@ -186,7 +198,7 @@ TOOLS_SCHEMA = [
186
  "description": "Driver status (default: active)"
187
  }
188
  },
189
- "required": ["name"]
190
  }
191
  },
192
  {
@@ -1557,6 +1569,7 @@ def handle_create_driver(tool_input: dict, user_id: str = None) -> dict:
1557
  capacity_m3 = tool_input.get("capacity_m3", 12.0)
1558
  current_lat = tool_input.get("current_lat") # No default - REQUIRED
1559
  current_lng = tool_input.get("current_lng") # No default - REQUIRED
 
1560
 
1561
  # Convert skills to regular list (handles protobuf RepeatedComposite)
1562
  skills_raw = tool_input.get("skills", [])
@@ -1582,11 +1595,11 @@ def handle_create_driver(tool_input: dict, user_id: str = None) -> dict:
1582
 
1583
  status = tool_input.get("status", "active")
1584
 
1585
- # Validate ALL required fields (name, vehicle_type, current_lat, current_lng)
1586
- if not all([name, vehicle_type, current_lat is not None, current_lng is not None]):
1587
  return {
1588
  "success": False,
1589
- "error": "Missing required fields: name, vehicle_type, current_lat, current_lng. All fields are mandatory."
1590
  }
1591
 
1592
  # Validate coordinates are valid numbers
@@ -1620,10 +1633,10 @@ def handle_create_driver(tool_input: dict, user_id: str = None) -> dict:
1620
  query = """
1621
  INSERT INTO drivers (
1622
  driver_id, name, phone, email,
1623
- current_lat, current_lng, last_location_update,
1624
  status, vehicle_type, vehicle_plate,
1625
  capacity_kg, capacity_m3, skills, user_id
1626
- ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
1627
  """
1628
 
1629
  # Convert skills list to JSON
@@ -1637,6 +1650,7 @@ def handle_create_driver(tool_input: dict, user_id: str = None) -> dict:
1637
  email,
1638
  current_lat,
1639
  current_lng,
 
1640
  now,
1641
  status,
1642
  vehicle_type,
@@ -1655,11 +1669,17 @@ def handle_create_driver(tool_input: dict, user_id: str = None) -> dict:
1655
  "success": True,
1656
  "driver_id": driver_id,
1657
  "name": name,
 
1658
  "status": status,
1659
  "vehicle_type": vehicle_type,
1660
  "vehicle_plate": vehicle_plate,
1661
  "capacity_kg": capacity_kg,
1662
  "skills": skills,
 
 
 
 
 
1663
  "message": f"Driver {driver_id} ({name}) created successfully!"
1664
  }
1665
  except Exception as e:
@@ -3187,7 +3207,7 @@ def handle_fetch_drivers(tool_input: dict, user_id: str = None) -> dict:
3187
  query = f"""
3188
  SELECT
3189
  driver_id, name, phone, email,
3190
- current_lat, current_lng, last_location_update,
3191
  status, vehicle_type, vehicle_plate,
3192
  capacity_kg, capacity_m3, skills,
3193
  created_at, updated_at
@@ -3232,6 +3252,7 @@ def handle_fetch_drivers(tool_input: dict, user_id: str = None) -> dict:
3232
  "location": {
3233
  "latitude": float(row['current_lat']) if row['current_lat'] else None,
3234
  "longitude": float(row['current_lng']) if row['current_lng'] else None,
 
3235
  "last_update": str(row['last_location_update']) if row['last_location_update'] else None
3236
  },
3237
  "status": row['status'],
@@ -3302,7 +3323,7 @@ def handle_get_driver_details(tool_input: dict, user_id: str = None) -> dict:
3302
  query = """
3303
  SELECT
3304
  driver_id, name, phone, email,
3305
- current_lat, current_lng, last_location_update,
3306
  status, vehicle_type, vehicle_plate,
3307
  capacity_kg, capacity_m3, skills,
3308
  created_at, updated_at
@@ -3330,16 +3351,15 @@ def handle_get_driver_details(tool_input: dict, user_id: str = None) -> dict:
3330
  except:
3331
  skills = []
3332
 
3333
- # Reverse geocode location to get address
3334
- # Use safe_reverse_geocode with timeout protection
3335
- location_address = None
3336
- if row['current_lat'] and row['current_lng']:
3337
  try:
3338
  reverse_result = safe_reverse_geocode(
3339
  float(row['current_lat']),
3340
  float(row['current_lng'])
3341
  )
3342
- location_address = reverse_result.get('formatted_address', None)
3343
  logger.info(f"Reverse geocoded driver location: {location_address}")
3344
  except Exception as e:
3345
  logger.warning(f"Failed to reverse geocode driver location: {e}")
@@ -3424,7 +3444,8 @@ def handle_search_drivers(tool_input: dict, user_id: str = None) -> dict:
3424
  query = """
3425
  SELECT
3426
  driver_id, name, phone, email,
3427
- vehicle_type, vehicle_plate, status, created_at
 
3428
  FROM drivers
3429
  WHERE
3430
  user_id = %s AND (
@@ -3454,14 +3475,29 @@ def handle_search_drivers(tool_input: dict, user_id: str = None) -> dict:
3454
 
3455
  drivers = []
3456
  for row in results:
 
 
 
 
 
 
 
 
 
3457
  drivers.append({
3458
  "driver_id": row['driver_id'],
3459
  "name": row['name'],
3460
  "phone": row['phone'],
3461
  "email": row['email'],
 
 
 
 
 
3462
  "vehicle_type": row['vehicle_type'],
3463
  "vehicle_plate": row['vehicle_plate'],
3464
  "status": row['status'],
 
3465
  "created_at": str(row['created_at'])
3466
  })
3467
 
@@ -3512,7 +3548,7 @@ def handle_get_available_drivers(tool_input: dict, user_id: str = None) -> dict:
3512
  query = """
3513
  SELECT
3514
  driver_id, name, phone, vehicle_type, vehicle_plate,
3515
- current_lat, current_lng, last_location_update,
3516
  status, capacity_kg, capacity_m3, skills
3517
  FROM drivers
3518
  WHERE user_id = %s AND status IN ('active', 'offline')
@@ -3554,6 +3590,7 @@ def handle_get_available_drivers(tool_input: dict, user_id: str = None) -> dict:
3554
  "location": {
3555
  "latitude": float(row['current_lat']) if row['current_lat'] else None,
3556
  "longitude": float(row['current_lng']) if row['current_lng'] else None,
 
3557
  "last_update": str(row['last_location_update']) if row['last_location_update'] else None
3558
  },
3559
  "status": row['status'],
@@ -5067,17 +5104,18 @@ def handle_complete_delivery(tool_input: dict, user_id: str = None) -> dict:
5067
  WHERE assignment_id = %s
5068
  """, tuple(params))
5069
 
5070
- # Step 2: Update driver location to delivery address
5071
  cursor.execute("""
5072
  UPDATE drivers
5073
  SET current_lat = %s,
5074
  current_lng = %s,
 
5075
  last_location_update = %s,
5076
  updated_at = %s
5077
  WHERE driver_id = %s
5078
- """, (delivery_lat, delivery_lng, completion_time, completion_time, driver_id))
5079
 
5080
- logger.info(f"Driver {driver_id} location updated to delivery address: ({delivery_lat}, {delivery_lng})")
5081
 
5082
  # Step 3: Calculate delivery performance status
5083
  delivery_status = "on_time" # Default
@@ -5210,6 +5248,7 @@ def handle_fail_delivery(tool_input: dict, user_id: str = None) -> dict:
5210
  from datetime import datetime
5211
 
5212
  assignment_id = (tool_input.get("assignment_id") or "").strip()
 
5213
  current_lat = tool_input.get("current_lat")
5214
  current_lng = tool_input.get("current_lng")
5215
  failure_reason = (tool_input.get("failure_reason") or "").strip()
@@ -5229,10 +5268,10 @@ def handle_fail_delivery(tool_input: dict, user_id: str = None) -> dict:
5229
  "error": "Delivery failure requires confirm=true for safety"
5230
  }
5231
 
5232
- if current_lat is None or current_lng is None:
5233
  return {
5234
  "success": False,
5235
- "error": "Driver must provide current location (current_lat and current_lng required)"
5236
  }
5237
 
5238
  if not failure_reason:
@@ -5345,17 +5384,18 @@ def handle_fail_delivery(tool_input: dict, user_id: str = None) -> dict:
5345
  WHERE assignment_id = %s
5346
  """, tuple(params))
5347
 
5348
- # Step 2: Update driver location to reported current location
5349
  cursor.execute("""
5350
  UPDATE drivers
5351
  SET current_lat = %s,
5352
  current_lng = %s,
 
5353
  last_location_update = %s,
5354
  updated_at = %s
5355
  WHERE driver_id = %s
5356
- """, (current_lat, current_lng, failure_time, failure_time, driver_id))
5357
 
5358
- logger.info(f"Driver {driver_id} location updated to reported position: ({current_lat}, {current_lng})")
5359
 
5360
  # Step 3: Calculate delivery performance status for failure
5361
  delivery_status = "failed_on_time" # Default - failed but before deadline
@@ -5433,10 +5473,11 @@ def handle_fail_delivery(tool_input: dict, user_id: str = None) -> dict:
5433
  "driver_location": {
5434
  "lat": current_lat,
5435
  "lng": current_lng,
 
5436
  "updated_at": failure_time.isoformat()
5437
  },
5438
  "cascading_actions": cascading_actions,
5439
- "message": f"Delivery failed for order {order_id}. Reason: {reason_display}. Timing: {timing_info.get('status', delivery_status)}. Driver {driver_name} location updated to ({current_lat}, {current_lng})."
5440
  }
5441
 
5442
  except Exception as e:
 
141
  },
142
  {
143
  "name": "create_driver",
144
+ "description": "Create a new delivery driver in the database. Use this to onboard new drivers to the fleet. Requires driver location (address + coordinates).",
145
  "input_schema": {
146
  "type": "object",
147
  "properties": {
 
159
  },
160
  "vehicle_type": {
161
  "type": "string",
162
+ "description": "Type of vehicle: van, truck, car, motorcycle"
163
  },
164
  "vehicle_plate": {
165
  "type": "string",
166
  "description": "Vehicle license plate number (optional)"
167
  },
168
+ "current_address": {
169
+ "type": "string",
170
+ "description": "Driver's current location address (e.g., '123 Main St, New York, NY')"
171
+ },
172
+ "current_lat": {
173
+ "type": "number",
174
+ "description": "Driver's current latitude coordinate"
175
+ },
176
+ "current_lng": {
177
+ "type": "number",
178
+ "description": "Driver's current longitude coordinate"
179
+ },
180
  "capacity_kg": {
181
  "type": "number",
182
  "description": "Vehicle cargo capacity in kilograms (default: 1000.0)"
 
198
  "description": "Driver status (default: active)"
199
  }
200
  },
201
+ "required": ["name", "vehicle_type", "current_address", "current_lat", "current_lng"]
202
  }
203
  },
204
  {
 
1569
  capacity_m3 = tool_input.get("capacity_m3", 12.0)
1570
  current_lat = tool_input.get("current_lat") # No default - REQUIRED
1571
  current_lng = tool_input.get("current_lng") # No default - REQUIRED
1572
+ current_address = tool_input.get("current_address") # No default - REQUIRED
1573
 
1574
  # Convert skills to regular list (handles protobuf RepeatedComposite)
1575
  skills_raw = tool_input.get("skills", [])
 
1595
 
1596
  status = tool_input.get("status", "active")
1597
 
1598
+ # Validate ALL required fields (name, vehicle_type, current_address, current_lat, current_lng)
1599
+ if not all([name, vehicle_type, current_address, current_lat is not None, current_lng is not None]):
1600
  return {
1601
  "success": False,
1602
+ "error": "Missing required fields: name, vehicle_type, current_address, current_lat, current_lng. All fields are mandatory."
1603
  }
1604
 
1605
  # Validate coordinates are valid numbers
 
1633
  query = """
1634
  INSERT INTO drivers (
1635
  driver_id, name, phone, email,
1636
+ current_lat, current_lng, current_address, last_location_update,
1637
  status, vehicle_type, vehicle_plate,
1638
  capacity_kg, capacity_m3, skills, user_id
1639
+ ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
1640
  """
1641
 
1642
  # Convert skills list to JSON
 
1650
  email,
1651
  current_lat,
1652
  current_lng,
1653
+ current_address,
1654
  now,
1655
  status,
1656
  vehicle_type,
 
1669
  "success": True,
1670
  "driver_id": driver_id,
1671
  "name": name,
1672
+ "phone": phone,
1673
  "status": status,
1674
  "vehicle_type": vehicle_type,
1675
  "vehicle_plate": vehicle_plate,
1676
  "capacity_kg": capacity_kg,
1677
  "skills": skills,
1678
+ "location": {
1679
+ "latitude": current_lat,
1680
+ "longitude": current_lng,
1681
+ "address": current_address
1682
+ },
1683
  "message": f"Driver {driver_id} ({name}) created successfully!"
1684
  }
1685
  except Exception as e:
 
3207
  query = f"""
3208
  SELECT
3209
  driver_id, name, phone, email,
3210
+ current_lat, current_lng, current_address, last_location_update,
3211
  status, vehicle_type, vehicle_plate,
3212
  capacity_kg, capacity_m3, skills,
3213
  created_at, updated_at
 
3252
  "location": {
3253
  "latitude": float(row['current_lat']) if row['current_lat'] else None,
3254
  "longitude": float(row['current_lng']) if row['current_lng'] else None,
3255
+ "address": row['current_address'],
3256
  "last_update": str(row['last_location_update']) if row['last_location_update'] else None
3257
  },
3258
  "status": row['status'],
 
3323
  query = """
3324
  SELECT
3325
  driver_id, name, phone, email,
3326
+ current_lat, current_lng, current_address, last_location_update,
3327
  status, vehicle_type, vehicle_plate,
3328
  capacity_kg, capacity_m3, skills,
3329
  created_at, updated_at
 
3351
  except:
3352
  skills = []
3353
 
3354
+ # Use stored address from database, or reverse geocode if not available
3355
+ location_address = row['current_address']
3356
+ if not location_address and row['current_lat'] and row['current_lng']:
 
3357
  try:
3358
  reverse_result = safe_reverse_geocode(
3359
  float(row['current_lat']),
3360
  float(row['current_lng'])
3361
  )
3362
+ location_address = reverse_result.get('address', None)
3363
  logger.info(f"Reverse geocoded driver location: {location_address}")
3364
  except Exception as e:
3365
  logger.warning(f"Failed to reverse geocode driver location: {e}")
 
3444
  query = """
3445
  SELECT
3446
  driver_id, name, phone, email,
3447
+ current_lat, current_lng, current_address,
3448
+ vehicle_type, vehicle_plate, status, skills, created_at
3449
  FROM drivers
3450
  WHERE
3451
  user_id = %s AND (
 
3475
 
3476
  drivers = []
3477
  for row in results:
3478
+ # Parse skills JSON if present
3479
+ skills = []
3480
+ if row['skills']:
3481
+ try:
3482
+ import json
3483
+ skills = json.loads(row['skills']) if isinstance(row['skills'], str) else row['skills']
3484
+ except:
3485
+ skills = []
3486
+
3487
  drivers.append({
3488
  "driver_id": row['driver_id'],
3489
  "name": row['name'],
3490
  "phone": row['phone'],
3491
  "email": row['email'],
3492
+ "location": {
3493
+ "latitude": float(row['current_lat']) if row['current_lat'] else None,
3494
+ "longitude": float(row['current_lng']) if row['current_lng'] else None,
3495
+ "address": row['current_address']
3496
+ },
3497
  "vehicle_type": row['vehicle_type'],
3498
  "vehicle_plate": row['vehicle_plate'],
3499
  "status": row['status'],
3500
+ "skills": skills,
3501
  "created_at": str(row['created_at'])
3502
  })
3503
 
 
3548
  query = """
3549
  SELECT
3550
  driver_id, name, phone, vehicle_type, vehicle_plate,
3551
+ current_lat, current_lng, current_address, last_location_update,
3552
  status, capacity_kg, capacity_m3, skills
3553
  FROM drivers
3554
  WHERE user_id = %s AND status IN ('active', 'offline')
 
3590
  "location": {
3591
  "latitude": float(row['current_lat']) if row['current_lat'] else None,
3592
  "longitude": float(row['current_lng']) if row['current_lng'] else None,
3593
+ "address": row['current_address'],
3594
  "last_update": str(row['last_location_update']) if row['last_location_update'] else None
3595
  },
3596
  "status": row['status'],
 
5104
  WHERE assignment_id = %s
5105
  """, tuple(params))
5106
 
5107
+ # Step 2: Update driver location to delivery address (including address text)
5108
  cursor.execute("""
5109
  UPDATE drivers
5110
  SET current_lat = %s,
5111
  current_lng = %s,
5112
+ current_address = %s,
5113
  last_location_update = %s,
5114
  updated_at = %s
5115
  WHERE driver_id = %s
5116
+ """, (delivery_lat, delivery_lng, delivery_address, completion_time, completion_time, driver_id))
5117
 
5118
+ logger.info(f"Driver {driver_id} location updated to delivery address: {delivery_address} ({delivery_lat}, {delivery_lng})")
5119
 
5120
  # Step 3: Calculate delivery performance status
5121
  delivery_status = "on_time" # Default
 
5248
  from datetime import datetime
5249
 
5250
  assignment_id = (tool_input.get("assignment_id") or "").strip()
5251
+ current_address = (tool_input.get("current_address") or "").strip()
5252
  current_lat = tool_input.get("current_lat")
5253
  current_lng = tool_input.get("current_lng")
5254
  failure_reason = (tool_input.get("failure_reason") or "").strip()
 
5268
  "error": "Delivery failure requires confirm=true for safety"
5269
  }
5270
 
5271
+ if not current_address or current_lat is None or current_lng is None:
5272
  return {
5273
  "success": False,
5274
+ "error": "Driver must provide current location (current_address, current_lat, and current_lng required)"
5275
  }
5276
 
5277
  if not failure_reason:
 
5384
  WHERE assignment_id = %s
5385
  """, tuple(params))
5386
 
5387
+ # Step 2: Update driver location to reported current location (address provided by user)
5388
  cursor.execute("""
5389
  UPDATE drivers
5390
  SET current_lat = %s,
5391
  current_lng = %s,
5392
+ current_address = %s,
5393
  last_location_update = %s,
5394
  updated_at = %s
5395
  WHERE driver_id = %s
5396
+ """, (current_lat, current_lng, current_address, failure_time, failure_time, driver_id))
5397
 
5398
+ logger.info(f"Driver {driver_id} location updated to reported position: {current_address} ({current_lat}, {current_lng})")
5399
 
5400
  # Step 3: Calculate delivery performance status for failure
5401
  delivery_status = "failed_on_time" # Default - failed but before deadline
 
5473
  "driver_location": {
5474
  "lat": current_lat,
5475
  "lng": current_lng,
5476
+ "address": current_address,
5477
  "updated_at": failure_time.isoformat()
5478
  },
5479
  "cascading_actions": cascading_actions,
5480
+ "message": f"Delivery failed for order {order_id}. Reason: {reason_display}. Timing: {timing_info.get('status', delivery_status)}. Driver {driver_name} location updated to {current_address or f'({current_lat}, {current_lng})'}."
5481
  }
5482
 
5483
  except Exception as e:
database/connection.py CHANGED
@@ -46,7 +46,7 @@ def get_db_connection() -> psycopg2.extensions.connection:
46
  user=DB_CONFIG['user'],
47
  password=DB_CONFIG['password'],
48
  cursor_factory=psycopg2.extras.RealDictCursor,
49
- sslmode='require'
50
  )
51
 
52
  logger.info(f"Database connection established: {DB_CONFIG['database']}@{DB_CONFIG['host']}")
 
46
  user=DB_CONFIG['user'],
47
  password=DB_CONFIG['password'],
48
  cursor_factory=psycopg2.extras.RealDictCursor,
49
+ sslmode='prefer'
50
  )
51
 
52
  logger.info(f"Database connection established: {DB_CONFIG['database']}@{DB_CONFIG['host']}")
database/migrations/008_add_driver_address.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Migration 008: Add current_address field to drivers table
3
+ This stores the address for driver locations (provided by user along with lat/lng)
4
+ """
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ # Add parent directory to path
10
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent))
11
+
12
+ from database.connection import execute_write
13
+
14
+
15
+ def up():
16
+ """Add current_address column to drivers table"""
17
+
18
+ migrations = [
19
+ """
20
+ ALTER TABLE drivers
21
+ ADD COLUMN IF NOT EXISTS current_address TEXT;
22
+ """,
23
+ ]
24
+
25
+ print("Migration 008: Adding current_address column to drivers...")
26
+
27
+ for i, sql in enumerate(migrations, 1):
28
+ try:
29
+ print(f" [{i}/{len(migrations)}] Executing: {sql.strip()[:60]}...")
30
+ execute_write(sql)
31
+ print(f" Success")
32
+ except Exception as e:
33
+ print(f" Warning: {e}")
34
+
35
+ print("\nMigration 008 complete!")
36
+
37
+
38
+ def down():
39
+ """Remove current_address column from drivers table"""
40
+
41
+ rollback_migrations = [
42
+ "ALTER TABLE drivers DROP COLUMN IF EXISTS current_address;",
43
+ ]
44
+
45
+ print("Rolling back Migration 008...")
46
+
47
+ for i, sql in enumerate(rollback_migrations, 1):
48
+ try:
49
+ print(f" [{i}/{len(rollback_migrations)}] {sql[:60]}...")
50
+ execute_write(sql)
51
+ print(f" Success")
52
+ except Exception as e:
53
+ print(f" Warning: {e}")
54
+
55
+ print("\nRollback complete!")
56
+
57
+
58
+ if __name__ == "__main__":
59
+ import sys
60
+
61
+ if len(sys.argv) > 1 and sys.argv[1] == "down":
62
+ down()
63
+ else:
64
+ up()
server.py CHANGED
@@ -1015,6 +1015,7 @@ def delete_order(order_id: str, confirm: bool) -> dict:
1015
  def create_driver(
1016
  name: str,
1017
  vehicle_type: str,
 
1018
  current_lat: float,
1019
  current_lng: float,
1020
  phone: str | None = None,
@@ -1031,6 +1032,7 @@ def create_driver(
1031
  Args:
1032
  name: Full name of the driver (REQUIRED)
1033
  vehicle_type: Type of vehicle: van, truck, car, motorcycle (REQUIRED)
 
1034
  current_lat: Driver's current latitude location (REQUIRED, -90 to 90)
1035
  current_lng: Driver's current longitude location (REQUIRED, -180 to 180)
1036
  phone: Driver phone number (optional)
@@ -1051,11 +1053,12 @@ def create_driver(
1051
  vehicle_plate: str,
1052
  capacity_kg: float,
1053
  skills: list[str],
 
1054
  message: str
1055
  }
1056
  """
1057
  from chat.tools import handle_create_driver
1058
- logger.info(f"Tool: create_driver(name='{name}', vehicle_type='{vehicle_type}', location=({current_lat}, {current_lng}))")
1059
 
1060
  # STEP 1: Authenticate user
1061
  user = get_authenticated_user()
@@ -1078,6 +1081,7 @@ def create_driver(
1078
  "capacity_m3": capacity_m3,
1079
  "skills": skills or [],
1080
  "status": status,
 
1081
  "current_lat": current_lat,
1082
  "current_lng": current_lng
1083
  }, user_id=user['user_id'])
@@ -1915,6 +1919,7 @@ def complete_delivery(
1915
  @mcp.tool()
1916
  def fail_delivery(
1917
  assignment_id: str,
 
1918
  current_lat: float,
1919
  current_lng: float,
1920
  failure_reason: str,
@@ -1924,7 +1929,7 @@ def fail_delivery(
1924
  """
1925
  Mark a delivery as failed with mandatory driver location and failure reason.
1926
 
1927
- IMPORTANT: Driver MUST provide their current GPS location and a valid failure reason.
1928
  This ensures accurate location tracking and proper failure documentation.
1929
 
1930
  Handles all necessary updates:
@@ -1947,12 +1952,13 @@ def fail_delivery(
1947
 
1948
  Requirements:
1949
  - Assignment must be in 'active' or 'in_progress' status
1950
- - Driver must provide current GPS coordinates
1951
  - Must provide a valid failure_reason from the list above
1952
  - Requires confirm=true
1953
 
1954
  Args:
1955
  assignment_id: Assignment ID to mark as failed (e.g., 'ASN-20250114123456')
 
1956
  current_lat: Driver's current latitude (-90 to 90)
1957
  current_lng: Driver's current longitude (-180 to 180)
1958
  failure_reason: Reason for failure (must be from valid list)
@@ -1971,7 +1977,7 @@ def fail_delivery(
1971
  failure_reason: str,
1972
  failure_reason_display: str (human-readable),
1973
  delivery_address: str,
1974
- driver_location: {lat, lng, updated_at},
1975
  cascading_actions: list[str],
1976
  message: str
1977
  }
@@ -1992,6 +1998,7 @@ def fail_delivery(
1992
  # STEP 3: Execute with user_id
1993
  return handle_fail_delivery({
1994
  "assignment_id": assignment_id,
 
1995
  "current_lat": current_lat,
1996
  "current_lng": current_lng,
1997
  "failure_reason": failure_reason,
 
1015
  def create_driver(
1016
  name: str,
1017
  vehicle_type: str,
1018
+ current_address: str,
1019
  current_lat: float,
1020
  current_lng: float,
1021
  phone: str | None = None,
 
1032
  Args:
1033
  name: Full name of the driver (REQUIRED)
1034
  vehicle_type: Type of vehicle: van, truck, car, motorcycle (REQUIRED)
1035
+ current_address: Driver's current location address, e.g. '123 Main St, New York, NY' (REQUIRED)
1036
  current_lat: Driver's current latitude location (REQUIRED, -90 to 90)
1037
  current_lng: Driver's current longitude location (REQUIRED, -180 to 180)
1038
  phone: Driver phone number (optional)
 
1053
  vehicle_plate: str,
1054
  capacity_kg: float,
1055
  skills: list[str],
1056
+ location: {latitude, longitude, address},
1057
  message: str
1058
  }
1059
  """
1060
  from chat.tools import handle_create_driver
1061
+ logger.info(f"Tool: create_driver(name='{name}', vehicle_type='{vehicle_type}', address='{current_address}', location=({current_lat}, {current_lng}))")
1062
 
1063
  # STEP 1: Authenticate user
1064
  user = get_authenticated_user()
 
1081
  "capacity_m3": capacity_m3,
1082
  "skills": skills or [],
1083
  "status": status,
1084
+ "current_address": current_address,
1085
  "current_lat": current_lat,
1086
  "current_lng": current_lng
1087
  }, user_id=user['user_id'])
 
1919
  @mcp.tool()
1920
  def fail_delivery(
1921
  assignment_id: str,
1922
+ current_address: str,
1923
  current_lat: float,
1924
  current_lng: float,
1925
  failure_reason: str,
 
1929
  """
1930
  Mark a delivery as failed with mandatory driver location and failure reason.
1931
 
1932
+ IMPORTANT: Driver MUST provide their current location (address + GPS coordinates) and a valid failure reason.
1933
  This ensures accurate location tracking and proper failure documentation.
1934
 
1935
  Handles all necessary updates:
 
1952
 
1953
  Requirements:
1954
  - Assignment must be in 'active' or 'in_progress' status
1955
+ - Driver must provide current address and GPS coordinates
1956
  - Must provide a valid failure_reason from the list above
1957
  - Requires confirm=true
1958
 
1959
  Args:
1960
  assignment_id: Assignment ID to mark as failed (e.g., 'ASN-20250114123456')
1961
+ current_address: Driver's current location address (e.g., '123 Main St, New York, NY')
1962
  current_lat: Driver's current latitude (-90 to 90)
1963
  current_lng: Driver's current longitude (-180 to 180)
1964
  failure_reason: Reason for failure (must be from valid list)
 
1977
  failure_reason: str,
1978
  failure_reason_display: str (human-readable),
1979
  delivery_address: str,
1980
+ driver_location: {lat, lng, address, updated_at},
1981
  cascading_actions: list[str],
1982
  message: str
1983
  }
 
1998
  # STEP 3: Execute with user_id
1999
  return handle_fail_delivery({
2000
  "assignment_id": assignment_id,
2001
+ "current_address": current_address,
2002
  "current_lat": current_lat,
2003
  "current_lng": current_lng,
2004
  "failure_reason": failure_reason,