TorbatYar/backend/services/delivery/app/repositories/routing.py
Mortezakoohjani 72077908f1 feat(delivery): deploy backend phases 10.2-10.8 through settlement
Ship fleet, availability, pricing, dispatch, routing, tracking, and settlement on delivery-service 0.10.8.0 with migrations and phase tests green.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 21:01:23 +03:30

116 lines
3.8 KiB
Python

"""Routing repositories — Phase 10.6."""
from __future__ import annotations
from typing import Sequence
from uuid import UUID
from sqlalchemy import func, select
from app.models.routing import OptimizationRun, RoutePlan, RouteStop
from app.repositories.base import TenantBaseRepository
from app.specifications.routing import OptimizationRunListSpec, RoutePlanListSpec
class RoutePlanRepository(TenantBaseRepository[RoutePlan]):
model = RoutePlan
async def get_by_code(self, tenant_id: UUID, code: str) -> RoutePlan | None:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.code == code,
self.model.is_deleted.is_(False),
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
async def list_filtered(
self,
tenant_id: UUID,
*,
offset: int = 0,
limit: int = 20,
spec: RoutePlanListSpec | None = None,
) -> Sequence[RoutePlan]:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.is_deleted.is_(False),
)
if spec is not None:
stmt = spec.apply(stmt)
else:
stmt = stmt.order_by(self.model.created_at.desc())
stmt = stmt.offset(offset).limit(limit)
result = await self.session.execute(stmt)
return result.scalars().all()
async def count_filtered(
self, tenant_id: UUID, *, spec: RoutePlanListSpec | None = None
) -> int:
stmt = select(func.count()).select_from(self.model).where(
self.model.tenant_id == tenant_id,
self.model.is_deleted.is_(False),
)
if spec is not None:
clauses = spec.filter_clauses()
if clauses:
stmt = stmt.where(*clauses)
result = await self.session.execute(stmt)
return int(result.scalar_one())
class RouteStopRepository(TenantBaseRepository[RouteStop]):
model = RouteStop
async def list_for_plan(
self, tenant_id: UUID, route_plan_id: UUID
) -> Sequence[RouteStop]:
stmt = (
select(self.model)
.where(
self.model.tenant_id == tenant_id,
self.model.route_plan_id == route_plan_id,
self.model.is_deleted.is_(False),
)
.order_by(self.model.sequence.asc())
)
result = await self.session.execute(stmt)
return result.scalars().all()
class OptimizationRunRepository(TenantBaseRepository[OptimizationRun]):
model = OptimizationRun
async def list_filtered(
self,
tenant_id: UUID,
*,
offset: int = 0,
limit: int = 20,
spec: OptimizationRunListSpec | None = None,
) -> Sequence[OptimizationRun]:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.is_deleted.is_(False),
)
if spec is not None:
stmt = spec.apply(stmt)
else:
stmt = stmt.order_by(self.model.created_at.desc())
stmt = stmt.offset(offset).limit(limit)
result = await self.session.execute(stmt)
return result.scalars().all()
async def count_filtered(
self, tenant_id: UUID, *, spec: OptimizationRunListSpec | None = None
) -> int:
stmt = select(func.count()).select_from(self.model).where(
self.model.tenant_id == tenant_id,
self.model.is_deleted.is_(False),
)
if spec is not None:
clauses = spec.filter_clauses()
if clauses:
stmt = stmt.where(*clauses)
result = await self.session.execute(stmt)
return int(result.scalar_one())