from __future__ import annotations from datetime import datetime from typing import Annotated, Any, Literal from pydantic import BaseModel, Field Role = Literal["operations_manager", "rental_employee"] class DemoLoginRequest(BaseModel): role: Role class CurrentUser(BaseModel): public_ref: str display_name: str role: Role class VehicleOut(BaseModel): public_ref: str make: str model: str model_year: int registration_number: str location: str operational_status: str odometer_km: int next_service_km: int active: bool attention: bool = False class BookingSummaryOut(BaseModel): public_ref: str customer_ref: str vehicle_ref: str starts_at: datetime ends_at: datetime status: str class BookingOut(BookingSummaryOut): start_odometer_km: int | None end_odometer_km: int | None requirements_complete: bool customer_name: str class RegisterReturnRequest(BaseModel): end_odometer_km: Annotated[int, Field(ge=0)] fuel_level_percent: Annotated[int, Field(ge=0, le=100)] cleanliness_ok: bool damage_reported: bool technical_warning: bool notes: str | None = Field(default=None, max_length=2000) class NextBookingRisk(BaseModel): booking_ref: str starts_at: datetime at_risk: bool class RegisterReturnResult(BaseModel): booking_ref: str vehicle_ref: str inspection_ref: str resulting_vehicle_status: str odometer_regression: bool quality_issue_ref: str | None workflow_event_id: str next_booking_risk: NextBookingRisk | None class InspectionOut(BaseModel): public_ref: str booking_ref: str type: str fuel_level_percent: int cleanliness_ok: bool damage_reported: bool technical_warning: bool odometer_km: int completed_at: datetime class MaintenanceOut(BaseModel): public_ref: str occurred_at: datetime odometer_km: int category: str summary: str class DataQualityIssueOut(BaseModel): public_ref: str rule_type: str entity_type: str entity_ref: str severity: str status: str evidence: dict[str, Any] detected_at: datetime resolved_at: datetime | None = None class DataQualityIssueDetailOut(DataQualityIssueOut): entity_snapshot: dict[str, Any] | None = None related_snapshots: list[dict[str, Any]] = Field(default_factory=list) class MergeCustomersRequest(BaseModel): survivor_ref: str field_overrides: dict[str, str] | None = None class MergeCustomersResult(BaseModel): issue_ref: str survivor_ref: str loser_ref: str rewired_bookings: int class ScanResultOut(BaseModel): created: dict[str, int] class VehicleDetailOut(VehicleOut): bookings: list[BookingSummaryOut] = Field(default_factory=list) inspections: list[InspectionOut] = Field(default_factory=list) maintenance: list[MaintenanceOut] = Field(default_factory=list) quality_issues: list[DataQualityIssueOut] = Field(default_factory=list) class DashboardMetrics(BaseModel): available: int rented: int cleaning: int maintenance: int blocked: int open_quality_issues: int pending_or_failed_workflows: int class AttentionItem(BaseModel): kind: Literal["quality_issue", "vehicle"] severity: str title: str detail: str link_type: Literal["vehicle", "booking", "customer"] link_ref: str issue_ref: str | None = None class TodayItem(BaseModel): kind: Literal["departure", "return"] booking_ref: str vehicle_ref: str scheduled_at: datetime class AutomationRunOut(BaseModel): event_id: str event_type: str aggregate_ref: str status: str attempts: int last_error: str | None occurred_at: datetime class DashboardOut(BaseModel): metrics: DashboardMetrics attention_items: list[AttentionItem] today: list[TodayItem] recent_automation: list[AutomationRunOut] class OperationsSummaryOut(BaseModel): tenant: str metrics: DashboardMetrics class AttentionVehicleOut(BaseModel): vehicle_ref: str severity: Literal["low", "medium", "high"] rule_type: str summary: str detected_at: datetime class McpVehicleDetailOut(BaseModel): public_ref: str make: str model: str model_year: int location: str operational_status: str odometer_km: int next_service_km: int open_quality_issue_count: int current_booking_ref: str | None class McpKnowledgeSearchRequest(BaseModel): question: str = Field(min_length=3, max_length=1000) max_sources: int = Field(default=4, ge=1, le=8) class AuditEventOut(BaseModel): id: str actor_type: str actor_label: str action: str entity_type: str entity_id: str | None correlation_id: str occurred_at: datetime metadata: dict[str, Any] | None = None