Add STO booking and maintenance automation
This commit is contained in:
187
app/schemas/sto_booking.py
Normal file
187
app/schemas/sto_booking.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from datetime import date, datetime, time
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
|
||||
APPOINTMENT_STATUSES = {
|
||||
"draft",
|
||||
"requested",
|
||||
"confirmed",
|
||||
"proposed_new_time",
|
||||
"rejected",
|
||||
"cancelled_by_customer",
|
||||
"cancelled_by_sto",
|
||||
"completed",
|
||||
"no_show",
|
||||
}
|
||||
|
||||
|
||||
class AvailableSlotRead(BaseModel):
|
||||
start_at: datetime
|
||||
end_at: datetime
|
||||
|
||||
|
||||
class ServiceCatalogItem(BaseModel):
|
||||
id: int
|
||||
display_name: str | None = None
|
||||
name: str
|
||||
city: str | None = None
|
||||
address: str | None = None
|
||||
specializations: list[str] | None = None
|
||||
working_hours: str | None = None
|
||||
rating_avg: float | None = None
|
||||
reviews_count: int = 0
|
||||
nearest_slot_at: datetime | None = None
|
||||
accepts_online_booking: bool = True
|
||||
|
||||
|
||||
class ServiceCenterBookingSettingsUpsert(BaseModel):
|
||||
service_center_id: int
|
||||
working_days: list[int] = Field(default_factory=lambda: [0, 1, 2, 3, 4])
|
||||
open_time: time = time(9, 0)
|
||||
close_time: time = time(18, 0)
|
||||
lunch_break_start: time | None = None
|
||||
lunch_break_end: time | None = None
|
||||
timezone: str = "Asia/Seoul"
|
||||
slot_duration_minutes: int = Field(default=30, ge=10, le=240)
|
||||
booking_buffer_minutes: int = Field(default=0, ge=0, le=240)
|
||||
max_parallel_bookings: int = Field(default=1, ge=1, le=20)
|
||||
accepts_online_booking: bool = True
|
||||
|
||||
@field_validator("working_days")
|
||||
@classmethod
|
||||
def validate_working_days(cls, value: list[int]) -> list[int]:
|
||||
days = sorted(set(value))
|
||||
if any(day < 0 or day > 6 for day in days):
|
||||
raise ValueError("working_days must contain ISO weekdays 0..6")
|
||||
return days
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_times(self) -> "ServiceCenterBookingSettingsUpsert":
|
||||
if self.open_time >= self.close_time:
|
||||
raise ValueError("open_time must be before close_time")
|
||||
if bool(self.lunch_break_start) != bool(self.lunch_break_end):
|
||||
raise ValueError("both lunch break boundaries are required")
|
||||
if self.lunch_break_start and self.lunch_break_end and self.lunch_break_start >= self.lunch_break_end:
|
||||
raise ValueError("lunch_break_start must be before lunch_break_end")
|
||||
return self
|
||||
|
||||
|
||||
class ServiceCenterBookingSettingsRead(ServiceCenterBookingSettingsUpsert):
|
||||
id: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class ServiceCenterHolidayCreate(BaseModel):
|
||||
service_center_id: int
|
||||
holiday_date: date
|
||||
reason: str | None = None
|
||||
|
||||
|
||||
class ServiceCenterHolidayRead(ServiceCenterHolidayCreate):
|
||||
id: int
|
||||
created_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class AppointmentCreate(BaseModel):
|
||||
service_center_id: int
|
||||
vehicle_id: int
|
||||
service_type: str = Field(default="maintenance", max_length=64)
|
||||
service_name: str = Field(default="Обслуживание", max_length=180)
|
||||
requested_start_at: datetime
|
||||
estimated_duration_minutes: int = Field(default=60, ge=10, le=1440)
|
||||
customer_comment: str | None = Field(default=None, max_length=4000)
|
||||
source_recommendation_id: int | None = None
|
||||
|
||||
|
||||
class AppointmentRead(BaseModel):
|
||||
id: int
|
||||
service_center_id: int
|
||||
vehicle_id: int
|
||||
owner_id: int
|
||||
created_by: int
|
||||
service_type: str
|
||||
service_name: str
|
||||
requested_start_at: datetime
|
||||
requested_end_at: datetime
|
||||
confirmed_start_at: datetime | None = None
|
||||
confirmed_end_at: datetime | None = None
|
||||
proposed_start_at: datetime | None = None
|
||||
proposed_end_at: datetime | None = None
|
||||
estimated_duration_minutes: int
|
||||
status: str
|
||||
customer_comment: str | None = None
|
||||
service_center_comment: str | None = None
|
||||
source_recommendation_id: int | None = None
|
||||
linked_work_order_id: int | None = None
|
||||
cancellation_reason: str | None = None
|
||||
cancelled_at: datetime | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class AppointmentDecision(BaseModel):
|
||||
comment: str | None = Field(default=None, max_length=4000)
|
||||
|
||||
|
||||
class AppointmentProposeTime(BaseModel):
|
||||
proposed_start_at: datetime
|
||||
estimated_duration_minutes: int | None = Field(default=None, ge=10, le=1440)
|
||||
comment: str | None = Field(default=None, max_length=4000)
|
||||
|
||||
|
||||
class AppointmentCancel(BaseModel):
|
||||
reason: str | None = Field(default=None, max_length=1000)
|
||||
|
||||
|
||||
class AppointmentCreateWorkOrder(BaseModel):
|
||||
odometer: int | None = None
|
||||
notes: str | None = Field(default=None, max_length=4000)
|
||||
|
||||
|
||||
class MaintenanceRecommendationCreate(BaseModel):
|
||||
recommendation_type: str = Field(max_length=64)
|
||||
title: str = Field(max_length=180)
|
||||
description: str | None = None
|
||||
due_odometer_km: int | None = None
|
||||
due_date: date | None = None
|
||||
priority: str = "medium"
|
||||
source: str = "user_rule"
|
||||
|
||||
|
||||
class MaintenanceRecommendationRead(MaintenanceRecommendationCreate):
|
||||
id: int
|
||||
vehicle_id: int
|
||||
status: str
|
||||
source_service_center_id: int | None = None
|
||||
source_appointment_id: int | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class MaintenanceRecommendationBook(BaseModel):
|
||||
appointment_id: int
|
||||
|
||||
|
||||
class STODashboardRead(BaseModel):
|
||||
service_center_id: int
|
||||
connected_vehicles: int
|
||||
pending_vehicle_links: int
|
||||
active_appointments: int
|
||||
pending_appointments: int
|
||||
confirmed_appointments: int
|
||||
active_work_orders: int
|
||||
completed_work_orders_month: int
|
||||
revenue_month: float
|
||||
average_check_month: float
|
||||
rating_avg: float | None = None
|
||||
reviews_count: int
|
||||
warnings: list[str]
|
||||
Reference in New Issue
Block a user