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>
100 lines
3.7 KiB
Python
100 lines
3.7 KiB
Python
"""Tracking query specifications — Phase 10.7."""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy import Select, asc, desc
|
|
from sqlalchemy.sql import ColumnElement
|
|
|
|
from app.models.tracking import CustomerTrackingToken, ProofOfDelivery, TrackingSession
|
|
from app.models.types import (
|
|
CustomerTrackingTokenStatus,
|
|
ProofOfDeliveryStatus,
|
|
TrackingSessionStatus,
|
|
)
|
|
|
|
SESSION_SORT = frozenset({"created_at", "updated_at", "status"})
|
|
POD_SORT = frozenset({"created_at", "updated_at", "status"})
|
|
TOKEN_SORT = frozenset({"created_at", "updated_at", "status"})
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class TrackingSessionListSpec:
|
|
status: TrackingSessionStatus | None = None
|
|
dispatch_job_id: UUID | None = None
|
|
driver_id: UUID | None = None
|
|
sort_by: str = "created_at"
|
|
sort_dir: str = "desc"
|
|
|
|
def filter_clauses(self) -> list[ColumnElement]:
|
|
clauses: list[ColumnElement] = []
|
|
if self.status is not None:
|
|
clauses.append(TrackingSession.status == self.status)
|
|
if self.dispatch_job_id is not None:
|
|
clauses.append(TrackingSession.dispatch_job_id == self.dispatch_job_id)
|
|
if self.driver_id is not None:
|
|
clauses.append(TrackingSession.driver_id == self.driver_id)
|
|
return clauses
|
|
|
|
def apply(self, stmt: Select) -> Select:
|
|
clauses = self.filter_clauses()
|
|
if clauses:
|
|
stmt = stmt.where(*clauses)
|
|
sort_key = self.sort_by if self.sort_by in SESSION_SORT else "created_at"
|
|
column = getattr(TrackingSession, sort_key)
|
|
order = desc(column) if self.sort_dir.lower() != "asc" else asc(column)
|
|
return stmt.order_by(order)
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class ProofOfDeliveryListSpec:
|
|
status: ProofOfDeliveryStatus | None = None
|
|
dispatch_job_id: UUID | None = None
|
|
sort_by: str = "created_at"
|
|
sort_dir: str = "desc"
|
|
|
|
def filter_clauses(self) -> list[ColumnElement]:
|
|
clauses: list[ColumnElement] = []
|
|
if self.status is not None:
|
|
clauses.append(ProofOfDelivery.status == self.status)
|
|
if self.dispatch_job_id is not None:
|
|
clauses.append(ProofOfDelivery.dispatch_job_id == self.dispatch_job_id)
|
|
return clauses
|
|
|
|
def apply(self, stmt: Select) -> Select:
|
|
clauses = self.filter_clauses()
|
|
if clauses:
|
|
stmt = stmt.where(*clauses)
|
|
sort_key = self.sort_by if self.sort_by in POD_SORT else "created_at"
|
|
column = getattr(ProofOfDelivery, sort_key)
|
|
order = desc(column) if self.sort_dir.lower() != "asc" else asc(column)
|
|
return stmt.order_by(order)
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class CustomerTrackingTokenListSpec:
|
|
status: CustomerTrackingTokenStatus | None = None
|
|
dispatch_job_id: UUID | None = None
|
|
sort_by: str = "created_at"
|
|
sort_dir: str = "desc"
|
|
|
|
def filter_clauses(self) -> list[ColumnElement]:
|
|
clauses: list[ColumnElement] = []
|
|
if self.status is not None:
|
|
clauses.append(CustomerTrackingToken.status == self.status)
|
|
if self.dispatch_job_id is not None:
|
|
clauses.append(
|
|
CustomerTrackingToken.dispatch_job_id == self.dispatch_job_id
|
|
)
|
|
return clauses
|
|
|
|
def apply(self, stmt: Select) -> Select:
|
|
clauses = self.filter_clauses()
|
|
if clauses:
|
|
stmt = stmt.where(*clauses)
|
|
sort_key = self.sort_by if self.sort_by in TOKEN_SORT else "created_at"
|
|
column = getattr(CustomerTrackingToken, sort_key)
|
|
order = desc(column) if self.sort_dir.lower() != "asc" else asc(column)
|
|
return stmt.order_by(order)
|