TorbatYar/backend/services/delivery/app/repositories/fleet.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

185 lines
6.3 KiB
Python

"""Fleet repositories — Phase 10.2."""
from __future__ import annotations
from typing import Sequence
from uuid import UUID
from sqlalchemy import func, select
from app.models.fleet import Fleet, Vehicle, VehicleAssignment, VehicleType
from app.models.types import VehicleAssignmentStatus
from app.repositories.base import TenantBaseRepository
from app.specifications.fleet import FleetListSpec, VehicleListSpec, VehicleTypeListSpec
class FleetRepository(TenantBaseRepository[Fleet]):
model = Fleet
async def get_by_code(self, tenant_id: UUID, code: str) -> Fleet | 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: FleetListSpec | None = None,
) -> Sequence[Fleet]:
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: FleetListSpec | 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 VehicleTypeRepository(TenantBaseRepository[VehicleType]):
model = VehicleType
async def get_by_code(self, tenant_id: UUID, code: str) -> VehicleType | 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: VehicleTypeListSpec | None = None,
) -> Sequence[VehicleType]:
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: VehicleTypeListSpec | 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 VehicleRepository(TenantBaseRepository[Vehicle]):
model = Vehicle
async def get_by_code(self, tenant_id: UUID, code: str) -> Vehicle | 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: VehicleListSpec | None = None,
) -> Sequence[Vehicle]:
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: VehicleListSpec | 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 VehicleAssignmentRepository(TenantBaseRepository[VehicleAssignment]):
model = VehicleAssignment
async def list_for_vehicle(
self, tenant_id: UUID, vehicle_id: UUID
) -> Sequence[VehicleAssignment]:
stmt = (
select(self.model)
.where(
self.model.tenant_id == tenant_id,
self.model.vehicle_id == vehicle_id,
self.model.is_deleted.is_(False),
)
.order_by(self.model.created_at.desc())
)
result = await self.session.execute(stmt)
return result.scalars().all()
async def get_active_for_vehicle(
self, tenant_id: UUID, vehicle_id: UUID
) -> VehicleAssignment | None:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.vehicle_id == vehicle_id,
self.model.status == VehicleAssignmentStatus.ACTIVE,
self.model.is_deleted.is_(False),
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()