Agrega backend FastAPI al proyecto
This commit is contained in:
242
recolector_backend/app/routers/operator.py
Normal file
242
recolector_backend/app/routers/operator.py
Normal file
@@ -0,0 +1,242 @@
|
||||
from datetime import datetime
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import Alert, Route, User
|
||||
from app.schemas import AlertOut, OperatorActionOut, RouteDetailOut, RouteOut
|
||||
from app.security import require_role
|
||||
|
||||
router = APIRouter(prefix="/operator", tags=["Operator"])
|
||||
|
||||
|
||||
def get_assigned_route(db: Session, route_id: str, operator: User) -> Route:
|
||||
route = (
|
||||
db.query(Route)
|
||||
.options(selectinload(Route.positions))
|
||||
.filter(Route.route_id == route_id)
|
||||
.first()
|
||||
)
|
||||
if not route:
|
||||
raise HTTPException(status_code=404, detail="Ruta no encontrada")
|
||||
if route.assigned_operator_id != operator.id:
|
||||
raise HTTPException(status_code=403, detail="Esta ruta no está asignada a este operador")
|
||||
return route
|
||||
|
||||
|
||||
def create_alert(
|
||||
db: Session,
|
||||
route: Route,
|
||||
operator: User,
|
||||
type_: str,
|
||||
title: str,
|
||||
message: str,
|
||||
priority: int,
|
||||
) -> Alert:
|
||||
alert = Alert(
|
||||
type=type_,
|
||||
title=title,
|
||||
message=message,
|
||||
route_id=route.route_id,
|
||||
truck_id=route.truck_id,
|
||||
operator_id=operator.id,
|
||||
priority=priority,
|
||||
status="NUEVA",
|
||||
)
|
||||
db.add(alert)
|
||||
db.flush()
|
||||
return alert
|
||||
|
||||
|
||||
def action_response(db: Session, route: Route, alert: Alert | None, message: str) -> OperatorActionOut:
|
||||
db.commit()
|
||||
db.refresh(route)
|
||||
if alert:
|
||||
db.refresh(alert)
|
||||
return OperatorActionOut(ok=True, route=route, alert=alert, message=message)
|
||||
|
||||
|
||||
@router.get("/routes", response_model=list[RouteOut])
|
||||
def my_routes(
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
return (
|
||||
db.query(Route)
|
||||
.filter(Route.assigned_operator_id == operator.id)
|
||||
.order_by(Route.route_id.asc())
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
@router.get("/routes/{route_id}", response_model=RouteDetailOut)
|
||||
def route_detail(
|
||||
route_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
route.positions = sorted(route.positions, key=lambda p: p.position_id)
|
||||
return route
|
||||
|
||||
|
||||
@router.get("/alerts", response_model=list[AlertOut])
|
||||
def my_sent_alerts(
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
return (
|
||||
db.query(Alert)
|
||||
.filter(Alert.operator_id == operator.id)
|
||||
.order_by(Alert.created_at.desc())
|
||||
.limit(30)
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
@router.post("/routes/{route_id}/start", response_model=OperatorActionOut)
|
||||
def start_route(
|
||||
route_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
route.status = "EN_RUTA"
|
||||
route.current_position_id = 2
|
||||
route.updated_at = datetime.utcnow()
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"ROUTE_START",
|
||||
"Ruta iniciada",
|
||||
f"El camión {route.truck_id} inició la ruta {route.route_id}.",
|
||||
1,
|
||||
)
|
||||
return action_response(db, route, alert, "Jornada iniciada correctamente")
|
||||
|
||||
|
||||
@router.post("/routes/{route_id}/advance/{position_id}", response_model=OperatorActionOut)
|
||||
def advance_route(
|
||||
route_id: str,
|
||||
position_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
valid_positions = {p.position_id for p in route.positions}
|
||||
if position_id not in valid_positions:
|
||||
raise HTTPException(status_code=422, detail="positionId inválido para esta ruta")
|
||||
|
||||
route.current_position_id = position_id
|
||||
route.status = "EN_RUTA" if position_id < 8 else "FINALIZADA"
|
||||
route.updated_at = datetime.utcnow()
|
||||
|
||||
alert = None
|
||||
if position_id == 4:
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"TRUCK_PROXIMITY",
|
||||
"Camión cercano",
|
||||
f"El camión {route.truck_id} está a menos de 15 minutos de la zona asignada.",
|
||||
2,
|
||||
)
|
||||
elif position_id == 8:
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"ROUTE_COMPLETED",
|
||||
"Servicio finalizado",
|
||||
f"El camión {route.truck_id} finalizó la ruta {route.route_id}.",
|
||||
1,
|
||||
)
|
||||
|
||||
return action_response(db, route, alert, "Avance de ruta actualizado")
|
||||
|
||||
|
||||
@router.post("/routes/{route_id}/delay", response_model=OperatorActionOut)
|
||||
def delay_route(
|
||||
route_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
route.status = "RETRASO"
|
||||
route.updated_at = datetime.utcnow()
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"DELAY",
|
||||
"Retraso operativo",
|
||||
f"La ruta {route.route_id} presenta un retraso aproximado de 25 minutos.",
|
||||
2,
|
||||
)
|
||||
return action_response(db, route, alert, "Retraso reportado")
|
||||
|
||||
|
||||
@router.post("/routes/{route_id}/breakdown", response_model=OperatorActionOut)
|
||||
def breakdown_route(
|
||||
route_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
route.status = "AVERIA"
|
||||
route.updated_at = datetime.utcnow()
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"MECHANICAL_FAILURE",
|
||||
"Avería mecánica",
|
||||
f"El camión {route.truck_id} presenta falla mecánica. Se requiere apoyo logístico.",
|
||||
3,
|
||||
)
|
||||
return action_response(db, route, alert, "Avería reportada")
|
||||
|
||||
|
||||
@router.post("/routes/{route_id}/incident", response_model=OperatorActionOut)
|
||||
def incident_route(
|
||||
route_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
route.status = "INCIDENCIA"
|
||||
route.updated_at = datetime.utcnow()
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"INCIDENT",
|
||||
"Incidencia en ruta",
|
||||
f"Se registró una incidencia menor en {route.route_id}: obstrucción vial o exceso de residuos.",
|
||||
2,
|
||||
)
|
||||
return action_response(db, route, alert, "Incidencia reportada")
|
||||
|
||||
|
||||
@router.post("/routes/{route_id}/complete", response_model=OperatorActionOut)
|
||||
def complete_route(
|
||||
route_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
operator: User = Depends(require_role("operador")),
|
||||
):
|
||||
route = get_assigned_route(db, route_id, operator)
|
||||
route.status = "FINALIZADA"
|
||||
route.current_position_id = 8
|
||||
route.updated_at = datetime.utcnow()
|
||||
alert = create_alert(
|
||||
db,
|
||||
route,
|
||||
operator,
|
||||
"ROUTE_COMPLETED",
|
||||
"Servicio finalizado",
|
||||
f"El operador finalizó la ruta {route.route_id}.",
|
||||
1,
|
||||
)
|
||||
return action_response(db, route, alert, "Ruta finalizada")
|
||||
Reference in New Issue
Block a user