""" Delivery Route Repository """ from typing import List, Dict, Any, Optional from datetime import date, datetime import uuid from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from app.models.distribution import DeliveryRoute, DeliveryRouteStatus from shared.database.base import Base class DeliveryRouteRepository: def __init__(self, db_session: AsyncSession): self.db_session = db_session async def create_route(self, route_data: Dict[str, Any]) -> Dict[str, Any]: """ Create a new delivery route """ # Define system user ID to use when user_id is not provided SYSTEM_USER_ID = uuid.UUID("50000000-0000-0000-0000-000000000004") route = DeliveryRoute( id=uuid.uuid4(), tenant_id=route_data['tenant_id'], route_number=route_data['route_number'], route_date=route_data['route_date'], vehicle_id=route_data.get('vehicle_id'), driver_id=route_data.get('driver_id'), total_distance_km=route_data.get('total_distance_km'), estimated_duration_minutes=route_data.get('estimated_duration_minutes'), route_sequence=route_data.get('route_sequence'), status=route_data.get('status', 'planned'), created_by=route_data.get('created_by', SYSTEM_USER_ID), updated_by=route_data.get('updated_by', SYSTEM_USER_ID) ) self.db_session.add(route) await self.db_session.commit() await self.db_session.refresh(route) # Convert SQLAlchemy object to dict for return return { 'id': str(route.id), 'tenant_id': str(route.tenant_id), 'route_number': route.route_number, 'route_date': route.route_date, 'vehicle_id': route.vehicle_id, 'driver_id': route.driver_id, 'total_distance_km': route.total_distance_km, 'estimated_duration_minutes': route.estimated_duration_minutes, 'route_sequence': route.route_sequence, 'status': route.status.value if hasattr(route.status, 'value') else route.status, 'created_at': route.created_at, 'updated_at': route.updated_at } async def get_routes_by_date(self, tenant_id: str, target_date: date) -> List[Dict[str, Any]]: """ Get all delivery routes for a specific date and tenant """ stmt = select(DeliveryRoute).where( (DeliveryRoute.tenant_id == tenant_id) & (DeliveryRoute.route_date >= datetime.combine(target_date, datetime.min.time())) & (DeliveryRoute.route_date < datetime.combine(target_date, datetime.max.time().replace(hour=23, minute=59, second=59))) ) result = await self.db_session.execute(stmt) routes = result.scalars().all() return [ { 'id': str(route.id), 'tenant_id': str(route.tenant_id), 'route_number': route.route_number, 'route_date': route.route_date, 'vehicle_id': route.vehicle_id, 'driver_id': route.driver_id, 'total_distance_km': route.total_distance_km, 'estimated_duration_minutes': route.estimated_duration_minutes, 'route_sequence': route.route_sequence, 'status': route.status.value if hasattr(route.status, 'value') else route.status, 'created_at': route.created_at, 'updated_at': route.updated_at } for route in routes ] async def get_routes_by_date_range(self, tenant_id: str, start_date: date, end_date: date) -> List[Dict[str, Any]]: """ Get all delivery routes for a specific date range and tenant """ stmt = select(DeliveryRoute).where( (DeliveryRoute.tenant_id == tenant_id) & (DeliveryRoute.route_date >= datetime.combine(start_date, datetime.min.time())) & (DeliveryRoute.route_date <= datetime.combine(end_date, datetime.max.time().replace(hour=23, minute=59, second=59))) ) result = await self.db_session.execute(stmt) routes = result.scalars().all() return [ { 'id': str(route.id), 'tenant_id': str(route.tenant_id), 'route_number': route.route_number, 'route_date': route.route_date, 'vehicle_id': route.vehicle_id, 'driver_id': route.driver_id, 'total_distance_km': route.total_distance_km, 'estimated_duration_minutes': route.estimated_duration_minutes, 'route_sequence': route.route_sequence, 'status': route.status.value if hasattr(route.status, 'value') else route.status, 'created_at': route.created_at, 'updated_at': route.updated_at } for route in routes ] async def get_route_by_id(self, route_id: str) -> Optional[Dict[str, Any]]: """ Get a specific delivery route by ID """ stmt = select(DeliveryRoute).where(DeliveryRoute.id == route_id) result = await self.db_session.execute(stmt) route = result.scalar_one_or_none() if route: return { 'id': str(route.id), 'tenant_id': str(route.tenant_id), 'route_number': route.route_number, 'route_date': route.route_date, 'vehicle_id': route.vehicle_id, 'driver_id': route.driver_id, 'total_distance_km': route.total_distance_km, 'estimated_duration_minutes': route.estimated_duration_minutes, 'route_sequence': route.route_sequence, 'status': route.status.value if hasattr(route.status, 'value') else route.status, 'created_at': route.created_at, 'updated_at': route.updated_at } return None async def update_route_status(self, route_id: str, status: str, user_id: str) -> Optional[Dict[str, Any]]: """ Update route status """ stmt = select(DeliveryRoute).where(DeliveryRoute.id == route_id) result = await self.db_session.execute(stmt) route = result.scalar_one_or_none() if not route: return None # Handle system user ID if passed as string if user_id == 'system': SYSTEM_USER_ID = uuid.UUID("50000000-0000-0000-0000-000000000004") route.updated_by = SYSTEM_USER_ID else: route.updated_by = user_id route.status = status await self.db_session.commit() await self.db_session.refresh(route) return { 'id': str(route.id), 'tenant_id': str(route.tenant_id), 'route_number': route.route_number, 'route_date': route.route_date, 'vehicle_id': route.vehicle_id, 'driver_id': route.driver_id, 'total_distance_km': route.total_distance_km, 'estimated_duration_minutes': route.estimated_duration_minutes, 'route_sequence': route.route_sequence, 'status': route.status.value if hasattr(route.status, 'value') else route.status, 'created_at': route.created_at, 'updated_at': route.updated_at } async def delete_demo_routes_for_tenant(self, tenant_id: str) -> int: """ Delete all demo routes for a tenant Used for demo session cleanup Args: tenant_id: The tenant ID to delete routes for Returns: Number of routes deleted """ from sqlalchemy import delete # Delete routes with DEMO- prefix in route_number stmt = delete(DeliveryRoute).where( (DeliveryRoute.tenant_id == uuid.UUID(tenant_id)) & (DeliveryRoute.route_number.like('DEMO-%')) ) result = await self.db_session.execute(stmt) await self.db_session.commit() deleted_count = result.rowcount return deleted_count