diff --git a/backend/app/models/route.py b/backend/app/models/route.py index a1752fc..06aa14d 100644 --- a/backend/app/models/route.py +++ b/backend/app/models/route.py @@ -9,9 +9,9 @@ from sqlalchemy import DateTime, func class RouteStatus(str, Enum): """Route status enumeration.""" - ACTIVE = "active" - INACTIVE = "inactive" - MAINTENANCE = "maintenance" + ACTIVE = "ACTIVE" + INACTIVE = "INACTIVE" + MAINTENANCE = "MAINTENANCE" class Route(SQLModel, table=True): diff --git a/backend/inject_routes.py b/backend/inject_routes.py new file mode 100644 index 0000000..110f20f --- /dev/null +++ b/backend/inject_routes.py @@ -0,0 +1,140 @@ +""" +Script de emergencia: Inyectar rutas directamente en la BD de producción +Ejecutar desde el servidor Render o con acceso directo a la BD. + +USO: python inject_routes.py +""" +import os +import sys + +# Añadir el path del backend +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from sqlmodel import Session, create_engine, select, SQLModel +from app.models.route import Route, RouteStatus +from app.core.config import settings + +# Rutas de bus más importantes de Boquete / Chiriquí +SAMPLE_ROUTES = [ + { + "name": "Boquete - David", + "origin_city": "Boquete", + "destination_city": "David", + "color": "#FEE715", + "direction": "outbound", + "distance_km": 38.0, + "estimated_duration_minutes": 55, + "average_speed_kmh": 40.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "David - Boquete", + "origin_city": "David", + "destination_city": "Boquete", + "color": "#FEE715", + "direction": "inbound", + "distance_km": 38.0, + "estimated_duration_minutes": 55, + "average_speed_kmh": 40.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "Boquete - Caldera", + "origin_city": "Boquete", + "destination_city": "Caldera", + "color": "#4CAF50", + "direction": "outbound", + "distance_km": 22.0, + "estimated_duration_minutes": 35, + "average_speed_kmh": 38.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "Caldera - Boquete", + "origin_city": "Caldera", + "destination_city": "Boquete", + "color": "#4CAF50", + "direction": "inbound", + "distance_km": 22.0, + "estimated_duration_minutes": 35, + "average_speed_kmh": 38.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "David - Paso Canoas", + "origin_city": "David", + "destination_city": "Paso Canoas", + "color": "#2196F3", + "direction": "outbound", + "distance_km": 52.0, + "estimated_duration_minutes": 70, + "average_speed_kmh": 45.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "David - Cerro Punta", + "origin_city": "David", + "destination_city": "Cerro Punta", + "color": "#9C27B0", + "direction": "outbound", + "distance_km": 75.0, + "estimated_duration_minutes": 100, + "average_speed_kmh": 45.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "David - Volcán", + "origin_city": "David", + "destination_city": "Volcán", + "color": "#FF5722", + "direction": "outbound", + "distance_km": 62.0, + "estimated_duration_minutes": 85, + "average_speed_kmh": 44.0, + "status": RouteStatus.ACTIVE, + }, + { + "name": "Boquete - Dolega", + "origin_city": "Boquete", + "destination_city": "Dolega", + "color": "#00BCD4", + "direction": "outbound", + "distance_km": 28.0, + "estimated_duration_minutes": 40, + "average_speed_kmh": 42.0, + "status": RouteStatus.ACTIVE, + }, +] + + +def inject_routes(): + db_url = settings.get_database_url + engine = create_engine(db_url, echo=True) + + with Session(engine) as session: + inserted = 0 + skipped = 0 + + for route_data in SAMPLE_ROUTES: + # Verificar si ya existe + existing = session.exec( + select(Route).where(Route.name == route_data["name"]) + ).first() + + if existing: + print(f" [SKIP] Ya existe: {route_data['name']}") + skipped += 1 + continue + + route = Route(**route_data) + session.add(route) + print(f" [ADD] {route_data['name']} ({route_data['origin_city']} → {route_data['destination_city']})") + inserted += 1 + + session.commit() + print(f"\n✅ Listo: {inserted} rutas insertadas, {skipped} ya existían.") + + +if __name__ == "__main__": + print("🚌 Inyectando rutas de bus en producción...\n") + inject_routes() diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 7d1ccb8..8c54206 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1,6 +1,6 @@ /** Type definitions for the SIBU transportation app */ -export type RouteStatus = 'active' | 'inactive' | 'maintenance' +export type RouteStatus = 'ACTIVE' | 'INACTIVE' | 'MAINTENANCE' export type StopType = 'terminal' | 'regular' | 'express_only' export type ScheduleType = 'weekday' | 'weekend' | 'holiday' diff --git a/frontend/src/views/AdminRoutes.vue b/frontend/src/views/AdminRoutes.vue index 258a281..723f19b 100644 --- a/frontend/src/views/AdminRoutes.vue +++ b/frontend/src/views/AdminRoutes.vue @@ -346,7 +346,7 @@ async function confirmCreateRoute() { name: computedRouteName.value, origin_city: newRouteForm.value.origin, destination_city: newRouteForm.value.destination, - status: 'active', + status: 'ACTIVE', color: '#FEE715', direction: 'outbound' }) diff --git a/frontend/src/views/RoutesView.vue b/frontend/src/views/RoutesView.vue index 151bb7d..c5f7108 100644 --- a/frontend/src/views/RoutesView.vue +++ b/frontend/src/views/RoutesView.vue @@ -60,7 +60,7 @@ const correlimientos = computed(() => { }) const getStatusClass = (status: string) => { - if (status === 'active') return 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400' + if (status === 'ACTIVE') return 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400' return 'bg-slate-100 dark:bg-zinc-800 text-slate-500 dark:text-zinc-400' } diff --git a/inject_api.py b/inject_api.py new file mode 100644 index 0000000..c2b4230 --- /dev/null +++ b/inject_api.py @@ -0,0 +1,52 @@ +import requests +import json + +base_url = "https://sibu-backend.onrender.com" + +def login(): + response = requests.post(f"{base_url}/api/auth/login", json={"email": "admin@sibu.com", "password": "admin"}) + if response.status_code == 200: + return response.json().get("access_token") + else: + print("Login failed:", response.status_code, response.text) + return None + +def create_route(token, route_data): + headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} + response = requests.post(f"{base_url}/api/routes", headers=headers, json=route_data) + if response.status_code == 200: + print(f"✅ Creada: {route_data['name']}") + else: + print(f"❌ Error en {route_data['name']}:", response.status_code, response.text) + +def main(): + print("Iniciando sesión...") + token = login() + if not token: + return + + print("Inyectando rutas...") + routes = [ + {"name": "Boquete - David", "origin_city": "Boquete", "destination_city": "David", "color": "#FEE715", "direction": "outbound", "distance_km": 38.0, "estimated_duration_minutes": 55, "average_speed_kmh": 40.0, "status": "active"}, + {"name": "David - Boquete", "origin_city": "David", "destination_city": "Boquete", "color": "#FEE715", "direction": "inbound", "distance_km": 38.0, "estimated_duration_minutes": 55, "average_speed_kmh": 40.0, "status": "active"}, + {"name": "Caldera - David", "origin_city": "Caldera", "destination_city": "David", "color": "#4CAF50", "direction": "outbound", "distance_km": 55.0, "estimated_duration_minutes": 75, "average_speed_kmh": 44.0, "status": "active"}, + {"name": "David - Caldera", "origin_city": "David", "destination_city": "Caldera", "color": "#4CAF50", "direction": "inbound", "distance_km": 55.0, "estimated_duration_minutes": 75, "average_speed_kmh": 44.0, "status": "active"}, + {"name": "Boquete - Caldera", "origin_city": "Boquete", "destination_city": "Caldera", "color": "#2196F3", "direction": "outbound", "distance_km": 22.0, "estimated_duration_minutes": 35, "average_speed_kmh": 38.0, "status": "active"}, + {"name": "Caldera - Boquete", "origin_city": "Caldera", "destination_city": "Boquete", "color": "#2196F3", "direction": "inbound", "distance_km": 22.0, "estimated_duration_minutes": 35, "average_speed_kmh": 38.0, "status": "active"} + ] + + for route in routes: + create_route(token, route) + + # Verificar rutas + print("\nVerificando rutas actuales en el servidor:") + r = requests.get(f"{base_url}/api/routes") + if r.status_code == 200: + current_routes = r.json() + print(f"Total rutas en el servidor: {len(current_routes)}") + if len(current_routes) > 0: + for rt in current_routes: + print(f" - {rt['name']}") + +if __name__ == "__main__": + main()