TorbatYar/backend/services/delivery/app/models/drivers.py
Mortezakoohjani 5c6a2e78cf feat(platform): seed service registry, deploy all modules, and fix homepage catalog.
Register all active platform services and base features in core DB so admin can manage them, add delivery/hospitality/sports-center backend phases, update apps catalog and production deploy tooling.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 12:39:51 +03:30

168 lines
6.0 KiB
Python

"""Driver management aggregates — Phase 10.1.
UUID refs only within delivery_db. No fleet/dispatch ownership.
Identity/CRM/Storage are external refs only.
"""
from __future__ import annotations
import uuid
from datetime import date, datetime
from sqlalchemy import (
Boolean,
Date,
DateTime,
Index,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON
from app.core.database import Base
from app.models.base import (
ActorAuditMixin,
OptimisticLockMixin,
SoftDeleteMixin,
TenantMixin,
TimestampMixin,
UUIDPrimaryKeyMixin,
)
from app.models.types import (
DriverCredentialKind,
DriverDocumentKind,
DriverLifecycleAction,
DriverStatus,
GUID,
)
class Driver(
Base,
UUIDPrimaryKeyMixin,
TenantMixin,
TimestampMixin,
SoftDeleteMixin,
ActorAuditMixin,
OptimisticLockMixin,
):
"""Courier/driver profile owned by Delivery Platform."""
__tablename__ = "drivers"
organization_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
hub_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
code: Mapped[str] = mapped_column(String(50), nullable=False)
display_name: Mapped[str] = mapped_column(String(255), nullable=False)
first_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
last_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
mobile: Mapped[str | None] = mapped_column(String(32), nullable=True)
email: Mapped[str | None] = mapped_column(String(255), nullable=True)
status: Mapped[DriverStatus] = mapped_column(
default=DriverStatus.PENDING, nullable=False
)
external_user_ref: Mapped[str | None] = mapped_column(String(100), nullable=True)
external_crm_contact_ref: Mapped[str | None] = mapped_column(
String(100), nullable=True
)
hire_date: Mapped[date | None] = mapped_column(Date, nullable=True)
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
capability_tags: Mapped[list | None] = mapped_column(JSON, nullable=True)
metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
status_reason: Mapped[str | None] = mapped_column(String(500), nullable=True)
status_changed_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
__table_args__ = (
UniqueConstraint("tenant_id", "code", name="uq_drivers_tenant_code"),
Index("ix_drivers_tenant_status", "tenant_id", "status"),
Index("ix_drivers_org", "tenant_id", "organization_id"),
Index("ix_drivers_hub", "tenant_id", "hub_id"),
Index("ix_drivers_mobile", "tenant_id", "mobile"),
Index("ix_drivers_tenant_deleted", "tenant_id", "is_deleted"),
Index("ix_drivers_display_name", "tenant_id", "display_name"),
)
class DriverCredential(
Base,
UUIDPrimaryKeyMixin,
TenantMixin,
TimestampMixin,
SoftDeleteMixin,
ActorAuditMixin,
):
"""Credential / compliance refs for a driver (binaries via Storage refs)."""
__tablename__ = "driver_credentials"
driver_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
kind: Mapped[DriverCredentialKind] = mapped_column(
default=DriverCredentialKind.LICENSE, nullable=False
)
number: Mapped[str] = mapped_column(String(100), nullable=False)
issued_at: Mapped[date | None] = mapped_column(Date, nullable=True)
expires_at: Mapped[date | None] = mapped_column(Date, nullable=True)
is_verified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
document_file_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
__table_args__ = (
UniqueConstraint(
"tenant_id",
"driver_id",
"kind",
"number",
name="uq_driver_credentials_tenant_kind_number",
),
Index("ix_driver_credentials_driver", "tenant_id", "driver_id"),
Index("ix_driver_credentials_tenant_deleted", "tenant_id", "is_deleted"),
)
class DriverDocument(
Base,
UUIDPrimaryKeyMixin,
TenantMixin,
TimestampMixin,
SoftDeleteMixin,
ActorAuditMixin,
):
"""Driver document metadata — Storage owns file blobs."""
__tablename__ = "driver_documents"
driver_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
kind: Mapped[DriverDocumentKind] = mapped_column(
default=DriverDocumentKind.OTHER, nullable=False
)
title: Mapped[str] = mapped_column(String(255), nullable=False)
storage_file_ref: Mapped[str] = mapped_column(String(255), nullable=False)
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
__table_args__ = (
Index("ix_driver_documents_driver", "tenant_id", "driver_id"),
Index("ix_driver_documents_tenant_deleted", "tenant_id", "is_deleted"),
)
class DriverLifecycleEvent(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
"""Append-only driver lifecycle history."""
__tablename__ = "driver_lifecycle_events"
driver_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
action: Mapped[DriverLifecycleAction] = mapped_column(nullable=False)
from_status: Mapped[DriverStatus] = mapped_column(nullable=False)
to_status: Mapped[DriverStatus] = mapped_column(nullable=False)
reason: Mapped[str | None] = mapped_column(String(500), nullable=True)
actor_user_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
__table_args__ = (
Index("ix_driver_lifecycle_driver", "tenant_id", "driver_id"),
Index("ix_driver_lifecycle_created", "tenant_id", "created_at"),
)