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

108 lines
3.6 KiB
Python

"""Dispatch repositories — Phase 10.5."""
from __future__ import annotations
from typing import Sequence
from uuid import UUID
from sqlalchemy import func, select
from app.models.dispatch import DispatchJob, JobAssignment
from app.repositories.base import TenantBaseRepository
from app.specifications.dispatch import DispatchJobListSpec, JobAssignmentListSpec
class DispatchJobRepository(TenantBaseRepository[DispatchJob]):
model = DispatchJob
async def get_by_code(self, tenant_id: UUID, code: str) -> DispatchJob | 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: DispatchJobListSpec | None = None,
) -> Sequence[DispatchJob]:
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: DispatchJobListSpec | 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 JobAssignmentRepository(TenantBaseRepository[JobAssignment]):
model = JobAssignment
async def list_filtered(
self,
tenant_id: UUID,
*,
offset: int = 0,
limit: int = 20,
spec: JobAssignmentListSpec | None = None,
) -> Sequence[JobAssignment]:
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: JobAssignmentListSpec | 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())
async def list_for_job(
self, tenant_id: UUID, dispatch_job_id: UUID
) -> Sequence[JobAssignment]:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.dispatch_job_id == dispatch_job_id,
self.model.is_deleted.is_(False),
)
result = await self.session.execute(stmt)
return result.scalars().all()