New enterprise feature
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user