Files
optovia/logistics_nodes/routers/logistics_api.py
Ruslan Bakiev 75cc01ff08 fix: use transport_category.code instead of name for transport_types
- Move import scripts from scripts/odoo to datasets/hub
- Add ensure_reference_data() to create transport categories and loading types
- Fix logistics_api.py to use code field directly instead of name mapping

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-12-27 09:53:15 +07:00

218 lines
7.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from typing import List
from odoo import http
from odoo.addons.fastapi.dependencies import odoo_env
router = APIRouter(tags=["logistics"])
class LogisticsNodeResponse(BaseModel):
uuid: str
name: str
latitude: float
longitude: float
country: str
country_code: str
transport_types: List[str] # ['auto', 'rail', 'air', 'sea']
def get_node_transport_types(node) -> List[str]:
"""Получить список типов транспорта для узла из его соединений"""
types = set()
for conn in node.connection_ids:
if conn.transport_category_id and conn.transport_category_id.code:
types.add(conn.transport_category_id.code)
return list(types)
class LogisticsRouteResponse(BaseModel):
uuid: str
name: str
departure_node_uuid: str
departure_node_name: str
arrival_node_uuid: str
arrival_node_name: str
transport_type: str
distance_km: float | None
travel_time_hours: float
active: bool
class LogisticsScheduleResponse(BaseModel):
uuid: str
name: str
departure_node_uuid: str
departure_node_name: str
arrival_node_uuid: str
arrival_node_name: str
route_uuid: str | None
transport_type: str
departure_time: float
frequency: str
travel_time_hours: float | None
active: bool
@router.get("/nodes")
def get_logistics_nodes(env=Depends(odoo_env)) -> List[LogisticsNodeResponse]:
"""Получить список всех логистических узлов"""
LogisticsNode = env['logistics.node']
nodes = LogisticsNode.search([])
result = []
for node in nodes:
result.append(LogisticsNodeResponse(
uuid=node.uuid,
name=node.name,
latitude=node.latitude,
longitude=node.longitude,
country=node.country_id.name if node.country_id else '',
country_code=node.country_id.code if node.country_id else '',
transport_types=get_node_transport_types(node)
))
return result
@router.get("/nodes/{node_uuid}")
def get_logistics_node(node_uuid: str, env=Depends(odoo_env)) -> LogisticsNodeResponse:
"""Получить логистический узел по UUID"""
LogisticsNode = env['logistics.node']
node = LogisticsNode.search([('uuid', '=', node_uuid)], limit=1)
if not node:
raise HTTPException(status_code=404, detail=f"Node with UUID {node_uuid} not found")
return LogisticsNodeResponse(
uuid=node.uuid,
name=node.name,
latitude=node.latitude,
longitude=node.longitude,
country=node.country_id.name if node.country_id else '',
country_code=node.country_id.code if node.country_id else '',
transport_types=get_node_transport_types(node)
)
@router.get("/routes")
def get_logistics_routes(env=Depends(odoo_env)) -> List[LogisticsRouteResponse]:
"""Get all active logistics routes"""
LogisticsRoute = env['logistics.route']
routes = LogisticsRoute.search([('active', '=', True)])
result = []
for route in routes:
result.append(LogisticsRouteResponse(
uuid=route.uuid if hasattr(route, 'uuid') else str(route.id),
name=route.name,
departure_node_uuid=route.departure_node_id.uuid,
departure_node_name=route.departure_node_id.name,
arrival_node_uuid=route.arrival_node_id.uuid,
arrival_node_name=route.arrival_node_id.name,
transport_type=route.transport_type,
distance_km=route.distance_km,
travel_time_hours=route.travel_time_hours,
active=route.active
))
return result
@router.get("/routes/{route_uuid}")
def get_logistics_route(route_uuid: str, env=Depends(odoo_env)) -> LogisticsRouteResponse:
"""Get logistics route by UUID"""
LogisticsRoute = env['logistics.route']
# Try to find by uuid field first, fallback to id
route = LogisticsRoute.search([('uuid', '=', route_uuid)], limit=1)
if not route:
try:
route = LogisticsRoute.browse(int(route_uuid))
if not route.exists():
route = None
except (ValueError, TypeError):
route = None
if not route:
raise HTTPException(status_code=404, detail=f"Route with UUID {route_uuid} not found")
return LogisticsRouteResponse(
uuid=route.uuid if hasattr(route, 'uuid') else str(route.id),
name=route.name,
departure_node_uuid=route.departure_node_id.uuid,
departure_node_name=route.departure_node_id.name,
arrival_node_uuid=route.arrival_node_id.uuid,
arrival_node_name=route.arrival_node_id.name,
transport_type=route.transport_type,
distance_km=route.distance_km,
travel_time_hours=route.travel_time_hours,
active=route.active
)
@router.get("/schedules")
def get_logistics_schedules(env=Depends(odoo_env)) -> List[LogisticsScheduleResponse]:
"""Get all active logistics schedules"""
LogisticsSchedule = env['logistics.schedule']
schedules = LogisticsSchedule.search([('active', '=', True)])
result = []
for schedule in schedules:
result.append(LogisticsScheduleResponse(
uuid=schedule.uuid if hasattr(schedule, 'uuid') else str(schedule.id),
name=schedule.name,
departure_node_uuid=schedule.departure_node_id.uuid,
departure_node_name=schedule.departure_node_id.name,
arrival_node_uuid=schedule.arrival_node_id.uuid,
arrival_node_name=schedule.arrival_node_id.name,
route_uuid=schedule.route_id.uuid if schedule.route_id and hasattr(schedule.route_id, 'uuid') else None,
transport_type=schedule.route_id.transport_type if schedule.route_id else 'auto',
departure_time=schedule.departure_time,
frequency=schedule.frequency,
travel_time_hours=schedule.route_id.travel_time_hours if schedule.route_id else None,
active=schedule.active
))
return result
@router.get("/schedules/{schedule_uuid}")
def get_logistics_schedule(schedule_uuid: str, env=Depends(odoo_env)) -> LogisticsScheduleResponse:
"""Get logistics schedule by UUID"""
LogisticsSchedule = env['logistics.schedule']
# Try to find by uuid field first, fallback to id
schedule = LogisticsSchedule.search([('uuid', '=', schedule_uuid)], limit=1)
if not schedule:
try:
schedule = LogisticsSchedule.browse(int(schedule_uuid))
if not schedule.exists():
schedule = None
except (ValueError, TypeError):
schedule = None
if not schedule:
raise HTTPException(status_code=404, detail=f"Schedule with UUID {schedule_uuid} not found")
return LogisticsScheduleResponse(
uuid=schedule.uuid if hasattr(schedule, 'uuid') else str(schedule.id),
name=schedule.name,
departure_node_uuid=schedule.departure_node_id.uuid,
departure_node_name=schedule.departure_node_id.name,
arrival_node_uuid=schedule.arrival_node_id.uuid,
arrival_node_name=schedule.arrival_node_id.name,
route_uuid=schedule.route_id.uuid if schedule.route_id and hasattr(schedule.route_id, 'uuid') else None,
transport_type=schedule.route_id.transport_type if schedule.route_id else 'auto',
departure_time=schedule.departure_time,
frequency=schedule.frequency,
travel_time_hours=schedule.route_id.travel_time_hours if schedule.route_id else None,
active=schedule.active
)