From 3dda6a9314df9def3aa3ec9be8bb2a7c1dbd87c4 Mon Sep 17 00:00:00 2001 From: Bafokeng Masitha Date: Fri, 9 Jan 2026 18:31:39 +0200 Subject: [PATCH 1/4] Add working Trip Request Processor CLI Prototype --- backend/fleet_management/__init__.py | 0 backend/fleet_management/allocation.py | 0 backend/fleet_management/models.py | 77 ++++++++++++++++++++++++ backend/fleet_management/monitoring.py | 0 backend/fleet_management/trip_request.py | 45 ++++++++++++++ backend/main.py | 23 +++++++ 6 files changed, 145 insertions(+) create mode 100644 backend/fleet_management/__init__.py create mode 100644 backend/fleet_management/allocation.py create mode 100644 backend/fleet_management/models.py create mode 100644 backend/fleet_management/monitoring.py create mode 100644 backend/fleet_management/trip_request.py create mode 100644 backend/main.py diff --git a/backend/fleet_management/__init__.py b/backend/fleet_management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/fleet_management/allocation.py b/backend/fleet_management/allocation.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/fleet_management/models.py b/backend/fleet_management/models.py new file mode 100644 index 0000000..adf4c20 --- /dev/null +++ b/backend/fleet_management/models.py @@ -0,0 +1,77 @@ +#This file defines the core data structures for my backend services + +from dataclasses import dataclass +from datetime import datetime + +@dataclass +class Ministry: + """ + Represents a government ministry that uses the system. + Columns: + - ministry_id: Unique ID for each ministry + - name: Ministry name (e.g., "Ministry of Health") + - budget_code: Used for billing purposes + """ + ministry_id: str + name: str + budget_code: str + + +@dataclass +class User: + """ + Represents a system user (employee, driver, admin, etc.) + Columns: + - user_id: Unique ID for each user + - name: Full name + - role: One of ('employee', 'admin_manager', 'fleet_manager', 'driver', 'admin') + - ministry_id: Ministry the user belongs to (foreign key to Ministry) + """ + user_id: str + name: str + role: str + ministry_id: str + + +@dataclass +class Vehicle: + """ + Represents a vehicle in the fleet. + Columns: + - vehicle_id: Unique vehicle identifier + - registration_number: Vehicle’s license plate + - vehicle_type: e.g., 'sedan', '4x4', 'minibus' + - fuel_type: e.g., 'petrol', 'diesel' + - current_status: e.g., 'available', 'in_use', 'maintenance' + - acquisition_date: Date when vehicle was acquired + """ + vehicle_id: str + registration_number: str + vehicle_type: str + fuel_type: str + current_status: str + acquisition_date: datetime + + +@dataclass +class TripRequest: + """ + Represents a vehicle trip request made by a government employee. + Columns: + - request_id: Unique trip request ID + - user_id: Employee who made the request + - pickup_location: Starting point + - destination: Trip destination + - trip_date: Scheduled date of the trip + - purpose: Reason for the trip + - passengers: Number of passengers + - status: Current status ('pending', 'approved', 'rejected', 'completed') + """ + request_id: str + user_id: str + pickup_location: str + destination: str + trip_date: datetime + purpose: str + passengers: int = 1 + status: str = "pending" diff --git a/backend/fleet_management/monitoring.py b/backend/fleet_management/monitoring.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/fleet_management/trip_request.py b/backend/fleet_management/trip_request.py new file mode 100644 index 0000000..16c9cd5 --- /dev/null +++ b/backend/fleet_management/trip_request.py @@ -0,0 +1,45 @@ +#This is the Trip Request Processor which collects trip requests from employees and gathers required information +from dataclasses import dataclass +from datetime import datetime +from typing import List, Optional +from .models import TripRequest, Vehicle, User + +VEHICLE_POOL = [ + Vehicle("V001", "ABC-123", "sedan", "petrol", "available", datetime(2020, 5, 10)), + Vehicle("V002", "XYZ-456", "4x4", "diesel", "available", datetime(2021, 7, 20)), +] + +EMPLOYEES = [ + User("U001", "Thabo Mohapi", "employee", "M001"), + User("U002", "Molupi Lekhanya", "employee", "M002"), +] + +TRIP_REQUESTS: List[TripRequest] = [] + +def create_trip_request(user_id: str, pickup: str, destination: str, trip_date: datetime, purpose: str, passengers: int = 1) -> TripRequest: + user = next((u for u in EMPLOYEES if u.user_id == user_id), None) + if not user: + raise ValueError(f"User {user_id} not found") + + request_id = f"TR{len(TRIP_REQUESTS)+1:03d}" + trip = TripRequest( + request_id=request_id, + user_id=user_id, + pickup_location=pickup, + destination=destination, + trip_date=trip_date, + purpose=purpose, + passengers=passengers, + status="pending" + ) + TRIP_REQUESTS.append(trip) + print(f"Trip request {trip.request_id} created successfully for {user.name}") + return trip + +def recommend_vehicle(trip: TripRequest) -> Optional[Vehicle]: + for vehicle in VEHICLE_POOL: + if vehicle.current_status == "available": + print(f"Recommended vehicle {vehicle.registration_number} ({vehicle.vehicle_type}) for trip {trip.request_id}") + return vehicle + print(f"No vehicles available for trip {trip.request_id}") + return None diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..b86b552 --- /dev/null +++ b/backend/main.py @@ -0,0 +1,23 @@ +#This program tests the CLI demo + +from datetime import datetime +from fleet_management.trip_request import create_trip_request, recommend_vehicle + +def cli_demo(): + trip = create_trip_request( + user_id="U001", + pickup="Maseru Central", + destination="Thaba-Tseka", + trip_date=datetime(2026, 1, 15, 9, 0), + purpose="Official Meeting" + ) + vehicle = recommend_vehicle(trip) + print("\n--- Trip Summary ---") + print(f"Trip ID: {trip.request_id}") + print(f"Employee ID: {trip.user_id}") + print(f"Pickup: {trip.pickup_location}") + print(f"Destination: {trip.destination}") + print(f"Recommended Vehicle: {vehicle.registration_number if vehicle else 'None'}") + +if __name__ == "__main__": + cli_demo() From bddf768b904888e3efb19eca81c5de73a1cb79fd Mon Sep 17 00:00:00 2001 From: Bafokeng Masitha Date: Fri, 9 Jan 2026 20:34:22 +0200 Subject: [PATCH 2/4] Add allocation and trip monitoring modules with PIN authentication --- backend/fleet_management/allocation.py | 74 ++++++++++++++++++++++++++ backend/fleet_management/monitoring.py | 36 +++++++++++++ 2 files changed, 110 insertions(+) diff --git a/backend/fleet_management/allocation.py b/backend/fleet_management/allocation.py index e69de29..bc50f8b 100644 --- a/backend/fleet_management/allocation.py +++ b/backend/fleet_management/allocation.py @@ -0,0 +1,74 @@ +#This is the backend logic where there is Admin approval, Fleet manager confirmation and generation of PIN + +from dataclasses import dataclass +from datetime import datetime +from typing import Optional +from .models import TripRequest, Vehicle, User +from .trip_request import TRIP_REQUESTS, VEHICLE_POOL +import random + +# Mock roles for simplicity +ADMIN_MANAGERS = [ + User("A001", "Mampho Nthunya", "admin_manager", "M001"), +] + +FLEET_MANAGERS = [ + User("F001", "Pheko Matela", "fleet_manager", "MFM001"), +] + +# Mock drivers +DRIVERS = [ + User("D001", "Teboho Mohlomi", "driver", "MFM001"), + User("D002", "Lineo Seeiso", "driver", "MFM001"), +] + + +def admin_approve_trip(request_id: str, approve: bool) -> str: + """ + Admin Manager approves or rejects the trip based on trip details. + """ + trip = next((t for t in TRIP_REQUESTS if t.request_id == request_id), None) + if not trip: + return f"Trip {request_id} not found." + + if approve: + trip.status = "approved" + return f"Trip {trip.request_id} approved by Admin Manager." + else: + trip.status = "rejected" + return f"Trip {trip.request_id} rejected by Admin Manager." + + +def fleet_manager_confirm_trip(request_id: str, vehicle_id: Optional[str] = None, driver_id: Optional[str] = None): + """ + Fleet Manager assigns final vehicle and driver after Admin approval. + """ + trip = next((t for t in TRIP_REQUESTS if t.request_id == request_id), None) + if not trip or trip.status != "approved": + return f"Trip {request_id} not available for allocation." + + # Select vehicle + vehicle = next((v for v in VEHICLE_POOL if v.vehicle_id == vehicle_id), None) if vehicle_id else VEHICLE_POOL[0] + + # Select driver (rotate to maintain fairness) + driver = next((d for d in DRIVERS if d.user_id == driver_id), None) if driver_id else random.choice(DRIVERS) + + # Mark trip as allocated + trip.status = "allocated" + allocation_info = { + "trip_id": trip.request_id, + "vehicle": vehicle.registration_number if vehicle else "None", + "driver": driver.name if driver else "None", + "security_pin": generate_security_pin(trip.request_id) + } + + return allocation_info + + +def generate_security_pin(request_id: str) -> str: + """ + Generates a unique 4-digit PIN for trip verification. + """ + random.seed(request_id) + pin = str(random.randint(1000, 9999)) + return pin diff --git a/backend/fleet_management/monitoring.py b/backend/fleet_management/monitoring.py index e69de29..4aba9d5 100644 --- a/backend/fleet_management/monitoring.py +++ b/backend/fleet_management/monitoring.py @@ -0,0 +1,36 @@ +#This code implements trip execution and authentication functionality for starting and ending trips. + +from datetime import datetime +from .models import TripRequest +from .allocation import generate_security_pin +from .trip_request import TRIP_REQUESTS + +def authenticate_trip(trip_id: str, employee_pin: str, driver_input_pin: str) -> str: + """ + Trip can only start if employee and driver pins match. + """ + trip = next((t for t in TRIP_REQUESTS if t.request_id == trip_id), None) + if not trip: + return f"Trip {trip_id} not found." + + correct_pin = generate_security_pin(trip_id) + + if employee_pin == correct_pin and driver_input_pin == correct_pin: + trip.status = "ongoing" + trip.start_time = datetime.now() + return f"Trip {trip_id} has started at {trip.start_time}." + else: + return "Authentication failed. Trip cannot start." + + +def end_trip(trip_id: str) -> str: + """ + Mark trip as completed and record end time. + """ + trip = next((t for t in TRIP_REQUESTS if t.request_id == trip_id), None) + if not trip or trip.status != "ongoing": + return f"Trip {trip_id} is not ongoing." + + trip.status = "completed" + trip.end_time = datetime.now() + return f"Trip {trip_id} completed at {trip.end_time}." From 95a5b8c62598df2339dc74e4a20ecfdde57eaa0f Mon Sep 17 00:00:00 2001 From: Bafokeng Masitha Date: Fri, 9 Jan 2026 20:40:10 +0200 Subject: [PATCH 3/4] Add requirements.txt for CI workflow dependencies --- backend/requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 backend/requirements.txt diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..9767e16 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,6 @@ +dataclasses +python-dateutil +fastapi +uvicorn +pydantic +pytest From d830fc1312fb4dcd78bc166a0c9cee45475d3047 Mon Sep 17 00:00:00 2001 From: Bafokeng Masitha Date: Fri, 9 Jan 2026 23:14:25 +0200 Subject: [PATCH 4/4] Enhanced Fleet management logic: dynamic fleet manager, rerecommendation, and API-ready structure --- backend/fleet_management/allocation.py | 102 ++++++++++++++---- .../fleet_management/fleet_management_api.py | 88 +++++++++++++++ backend/fleet_management/models.py | 41 ++----- backend/main.py | 31 ++++-- 4 files changed, 202 insertions(+), 60 deletions(-) create mode 100644 backend/fleet_management/fleet_management_api.py diff --git a/backend/fleet_management/allocation.py b/backend/fleet_management/allocation.py index bc50f8b..eb1cebf 100644 --- a/backend/fleet_management/allocation.py +++ b/backend/fleet_management/allocation.py @@ -1,28 +1,35 @@ -#This is the backend logic where there is Admin approval, Fleet manager confirmation and generation of PIN - -from dataclasses import dataclass from datetime import datetime from typing import Optional -from .models import TripRequest, Vehicle, User -from .trip_request import TRIP_REQUESTS, VEHICLE_POOL import random +from .models import TripRequest, User, Vehicle +from .trip_request import TRIP_REQUESTS, VEHICLE_POOL, EMPLOYEES -# Mock roles for simplicity +# Mock data for demonstration ADMIN_MANAGERS = [ User("A001", "Mampho Nthunya", "admin_manager", "M001"), + User("A002", "Lerato Moeti", "admin_manager", "M002"), ] FLEET_MANAGERS = [ User("F001", "Pheko Matela", "fleet_manager", "MFM001"), ] -# Mock drivers DRIVERS = [ User("D001", "Teboho Mohlomi", "driver", "MFM001"), User("D002", "Lineo Seeiso", "driver", "MFM001"), ] +def get_admin_manager_for_employee(user_id: str) -> Optional[User]: + """ + Finds the admin manager for the employee's ministry. + """ + employee = next((u for u in EMPLOYEES if u.user_id == user_id), None) + if not employee: + return None + return next((a for a in ADMIN_MANAGERS if a.ministry_id == employee.ministry_id), None) + + def admin_approve_trip(request_id: str, approve: bool) -> str: """ Admin Manager approves or rejects the trip based on trip details. @@ -31,38 +38,94 @@ def admin_approve_trip(request_id: str, approve: bool) -> str: if not trip: return f"Trip {request_id} not found." + admin_manager = get_admin_manager_for_employee(trip.user_id) + if not admin_manager: + return "No Admin Manager found for employee’s ministry." + if approve: trip.status = "approved" - return f"Trip {trip.request_id} approved by Admin Manager." + trip.approved_by_admin = admin_manager.name + return f"Trip {trip.request_id} approved by {admin_manager.name}." else: trip.status = "rejected" - return f"Trip {trip.request_id} rejected by Admin Manager." + return f"Trip {trip.request_id} rejected by {admin_manager.name}." def fleet_manager_confirm_trip(request_id: str, vehicle_id: Optional[str] = None, driver_id: Optional[str] = None): """ - Fleet Manager assigns final vehicle and driver after Admin approval. + Fleet Manager confirms or modifies the system recommendation. """ trip = next((t for t in TRIP_REQUESTS if t.request_id == request_id), None) if not trip or trip.status != "approved": return f"Trip {request_id} not available for allocation." - # Select vehicle + # Choose or modify vehicle vehicle = next((v for v in VEHICLE_POOL if v.vehicle_id == vehicle_id), None) if vehicle_id else VEHICLE_POOL[0] + driver = next((d for d in DRIVERS if d.user_id == driver_id), None) if driver_id else random.choice(DRIVERS) + + trip.status = "allocated" + trip.assigned_vehicle = vehicle.registration_number if vehicle else None + trip.assigned_driver = driver.name if driver else None + trip.recommended_by_fleet_manager = FLEET_MANAGERS[0].name + trip.security_pin = generate_security_pin(trip.request_id) + + return { + "trip_id": trip.request_id, + "vehicle": trip.assigned_vehicle, + "driver": trip.assigned_driver, + "security_pin": trip.security_pin, + } + +def fleet_manager_confirm_trip(request_id: str, fleet_manager_id: str, vehicle_id: Optional[str] = None, driver_id: Optional[str] = None): + """ + Fleet Manager confirms or modifies the system recommendation. + """ + trip = next((t for t in TRIP_REQUESTS if t.request_id == request_id), None) + if not trip or trip.status != "approved": + return f"Trip {request_id} not available for allocation." + + fleet_manager = next((f for f in FLEET_MANAGERS if f.user_id == fleet_manager_id), None) + if not fleet_manager: + return f"Fleet Manager with ID {fleet_manager_id} not found." - # Select driver (rotate to maintain fairness) + # Choose vehicle and driver (either from parameters or defaults) + vehicle = next((v for v in VEHICLE_POOL if v.vehicle_id == vehicle_id), None) if vehicle_id else VEHICLE_POOL[0] driver = next((d for d in DRIVERS if d.user_id == driver_id), None) if driver_id else random.choice(DRIVERS) - # Mark trip as allocated + # Update trip trip.status = "allocated" - allocation_info = { + trip.assigned_vehicle = vehicle.registration_number if vehicle else None + trip.assigned_driver = driver.name if driver else None + trip.recommended_by_fleet_manager = fleet_manager.name + trip.security_pin = generate_security_pin(trip.request_id) + + return { "trip_id": trip.request_id, - "vehicle": vehicle.registration_number if vehicle else "None", - "driver": driver.name if driver else "None", - "security_pin": generate_security_pin(trip.request_id) + "vehicle": trip.assigned_vehicle, + "driver": trip.assigned_driver, + "fleet_manager": fleet_manager.name, + "security_pin": trip.security_pin, } - return allocation_info + +def rerecommend_trip(request_id: str, new_vehicle_id: Optional[str] = None, new_driver_id: Optional[str] = None): + """ + Fleet Manager can re-recommend a new vehicle or driver after initial allocation. + """ + trip = next((t for t in TRIP_REQUESTS if t.request_id == request_id), None) + if not trip: + return f"Trip {request_id} not found." + + if new_vehicle_id: + vehicle = next((v for v in VEHICLE_POOL if v.vehicle_id == new_vehicle_id), None) + trip.assigned_vehicle = vehicle.registration_number if vehicle else trip.assigned_vehicle + + if new_driver_id: + driver = next((d for d in DRIVERS if d.user_id == new_driver_id), None) + trip.assigned_driver = driver.name if driver else trip.assigned_driver + + trip.recommended_by_fleet_manager = FLEET_MANAGERS[0].name + return f"Trip {trip.request_id} rerecommended with updates: vehicle={trip.assigned_vehicle}, driver={trip.assigned_driver}." def generate_security_pin(request_id: str) -> str: @@ -70,5 +133,4 @@ def generate_security_pin(request_id: str) -> str: Generates a unique 4-digit PIN for trip verification. """ random.seed(request_id) - pin = str(random.randint(1000, 9999)) - return pin + return str(random.randint(1000, 9999)) diff --git a/backend/fleet_management/fleet_management_api.py b/backend/fleet_management/fleet_management_api.py new file mode 100644 index 0000000..2b05f23 --- /dev/null +++ b/backend/fleet_management/fleet_management_api.py @@ -0,0 +1,88 @@ +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +from datetime import datetime +from fleet_management.trip_request import create_trip_request, recommend_vehicle +from fleet_management.allocation import admin_approve_trip, fleet_manager_confirm_trip, rerecommend_trip +from fleet_management.monitoring import authenticate_trip, end_trip + +app = FastAPI(title="GovRide AI Fleet Management API") + +# ---------------------------- +# Request Models +# ---------------------------- + +class TripRequestIn(BaseModel): + user_id: str + pickup_location: str + destination: str + trip_date: datetime + purpose: str + +class AdminApprovalIn(BaseModel): + approve: bool + +class FleetAllocationIn(BaseModel): + fleet_manager_id: str + vehicle_id: str | None = None + driver_id: str | None = None + +class FleetReRecommendationIn(BaseModel): + new_vehicle_id: str | None = None + new_driver_id: str | None = None + +class TripAuthIn(BaseModel): + employee_pin: str + driver_pin: str + + +# ---------------------------- +# Endpoints +# ---------------------------- + +@app.post("/trip-request/") +def submit_trip_request(trip_data: TripRequestIn): + trip = create_trip_request( + user_id=trip_data.user_id, + pickup=trip_data.pickup_location, + destination=trip_data.destination, + trip_date=trip_data.trip_date, + purpose=trip_data.purpose, + ) + recommend_vehicle(trip) + return {"message": f"Trip {trip.request_id} created successfully", "trip_id": trip.request_id} + + +@app.patch("/trip-request/{request_id}/approve") +def approve_trip(request_id: str, data: AdminApprovalIn): + result = admin_approve_trip(request_id, approve=data.approve) + if "not found" in result: + raise HTTPException(status_code=404, detail=result) + return {"message": result} + + +@app.patch("/trip-request/{request_id}/allocate") +def confirm_trip_allocation(request_id: str, data: FleetAllocationIn): + result = fleet_manager_confirm_trip(request_id, data.fleet_manager_id, data.vehicle_id, data.driver_id) + if isinstance(result, str): + raise HTTPException(status_code=404, detail=result) + return result + + +@app.patch("/trip-request/{request_id}/rerecommend") +def rerecommend_allocation(request_id: str, data: FleetReRecommendationIn): + result = rerecommend_trip(request_id, data.new_vehicle_id, data.new_driver_id) + return {"message": result} + + +@app.patch("/trip-request/{request_id}/start") +def start_trip(request_id: str, data: TripAuthIn): + result = authenticate_trip(request_id, data.employee_pin, data.driver_pin) + if "failed" in result: + raise HTTPException(status_code=400, detail=result) + return {"message": result} + + +@app.patch("/trip-request/{request_id}/complete") +def complete_trip(request_id: str): + result = end_trip(request_id) + return {"message": result} diff --git a/backend/fleet_management/models.py b/backend/fleet_management/models.py index adf4c20..8f743b2 100644 --- a/backend/fleet_management/models.py +++ b/backend/fleet_management/models.py @@ -1,16 +1,11 @@ -#This file defines the core data structures for my backend services - -from dataclasses import dataclass +from dataclasses import dataclass, field from datetime import datetime +from typing import Optional @dataclass class Ministry: """ Represents a government ministry that uses the system. - Columns: - - ministry_id: Unique ID for each ministry - - name: Ministry name (e.g., "Ministry of Health") - - budget_code: Used for billing purposes """ ministry_id: str name: str @@ -21,15 +16,10 @@ class Ministry: class User: """ Represents a system user (employee, driver, admin, etc.) - Columns: - - user_id: Unique ID for each user - - name: Full name - - role: One of ('employee', 'admin_manager', 'fleet_manager', 'driver', 'admin') - - ministry_id: Ministry the user belongs to (foreign key to Ministry) """ user_id: str name: str - role: str + role: str # ('employee', 'admin_manager', 'fleet_manager', 'driver', 'admin') ministry_id: str @@ -37,19 +27,12 @@ class User: class Vehicle: """ Represents a vehicle in the fleet. - Columns: - - vehicle_id: Unique vehicle identifier - - registration_number: Vehicle’s license plate - - vehicle_type: e.g., 'sedan', '4x4', 'minibus' - - fuel_type: e.g., 'petrol', 'diesel' - - current_status: e.g., 'available', 'in_use', 'maintenance' - - acquisition_date: Date when vehicle was acquired """ vehicle_id: str registration_number: str vehicle_type: str fuel_type: str - current_status: str + current_status: str # ('available', 'in_use', 'maintenance') acquisition_date: datetime @@ -57,15 +40,6 @@ class Vehicle: class TripRequest: """ Represents a vehicle trip request made by a government employee. - Columns: - - request_id: Unique trip request ID - - user_id: Employee who made the request - - pickup_location: Starting point - - destination: Trip destination - - trip_date: Scheduled date of the trip - - purpose: Reason for the trip - - passengers: Number of passengers - - status: Current status ('pending', 'approved', 'rejected', 'completed') """ request_id: str user_id: str @@ -75,3 +49,10 @@ class TripRequest: purpose: str passengers: int = 1 status: str = "pending" + assigned_driver: Optional[str] = None + assigned_vehicle: Optional[str] = None + start_time: Optional[datetime] = None + end_time: Optional[datetime] = None + approved_by_admin: Optional[str] = None + recommended_by_fleet_manager: Optional[str] = None + security_pin: Optional[str] = None diff --git a/backend/main.py b/backend/main.py index b86b552..8590e9a 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,9 +1,11 @@ -#This program tests the CLI demo - -from datetime import datetime +from fleet_management.monitoring import authenticate_trip, end_trip from fleet_management.trip_request import create_trip_request, recommend_vehicle +from fleet_management.allocation import admin_approve_trip, fleet_manager_confirm_trip +from datetime import datetime def cli_demo(): + + # Step 1: Create trip trip = create_trip_request( user_id="U001", pickup="Maseru Central", @@ -11,13 +13,22 @@ def cli_demo(): trip_date=datetime(2026, 1, 15, 9, 0), purpose="Official Meeting" ) - vehicle = recommend_vehicle(trip) - print("\n--- Trip Summary ---") - print(f"Trip ID: {trip.request_id}") - print(f"Employee ID: {trip.user_id}") - print(f"Pickup: {trip.pickup_location}") - print(f"Destination: {trip.destination}") - print(f"Recommended Vehicle: {vehicle.registration_number if vehicle else 'None'}") + recommend_vehicle(trip) + + # Step 2: Admin approval + admin_approve_trip(trip.request_id, approve=True) + + # Step 3: Fleet manager allocation + allocation_info = fleet_manager_confirm_trip(trip.request_id, fleet_manager_id="F001") + + # Step 4: Trip authentication & start + print("\nAuthenticating and starting trip...") + employee_pin = allocation_info['security_pin'] + driver_input_pin = allocation_info['security_pin'] + print(authenticate_trip(trip.request_id, employee_pin, driver_input_pin)) + + # Step 5: End trip + print(end_trip(trip.request_id)) if __name__ == "__main__": cli_demo()