Add service platform foundation

This commit is contained in:
VPN SaaS Dev
2026-05-12 19:45:08 +09:00
parent 2ba2e88432
commit 34035a27cb
23 changed files with 2199 additions and 18 deletions

View File

@@ -1,22 +1,227 @@
from datetime import datetime
from datetime import date, datetime
from decimal import Decimal
from pydantic import BaseModel, ConfigDict
from pydantic import BaseModel, ConfigDict, field_validator
from app.services.vehicle_identity import normalize_license_plate, validate_vin
class ServiceCenterCreate(BaseModel):
name: str
legal_name: str | None = None
display_name: str
country: str | None = None
city: str | None = None
address: str | None = None
phone: str | None = None
business_registration_number: str | None = None
telegram_chat_id: str | None = None
contact_phone: str | None = None
address: str | None = None
class ServiceCenterRead(ServiceCenterCreate):
id: int
name: str
verification_status: str
owner_user_id: int | None = None
created_at: datetime
verified_at: datetime | None = None
suspended_at: datetime | None = None
model_config = ConfigDict(from_attributes=True)
class ServiceCenterVerificationCreate(BaseModel):
submitted_documents: list[dict] | None = None
comment: str | None = None
class ServiceCenterVerificationRead(ServiceCenterVerificationCreate):
id: int
service_center_id: int
status: str
reviewed_by: int | None = None
reviewed_at: datetime | None = None
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class ServiceEmployeeInvite(BaseModel):
telegram_id: int
role: str = "receptionist"
permissions: dict | None = None
class ServiceEmployeeRead(BaseModel):
id: int
service_center_id: int
user_id: int
role: str
permissions: dict | None = None
status: str
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class VehicleAccessGrant(BaseModel):
service_center_id: int | None = None
user_id: int | None = None
role: str = "viewer"
class VehicleAccessRead(BaseModel):
id: int
vehicle_id: int
user_id: int
role: str
status: str
created_at: datetime
revoked_at: datetime | None = None
model_config = ConfigDict(from_attributes=True)
class VehicleCreate(BaseModel):
name: str
make: str | None = None
model: str | None = None
year: int | None = None
license_plate: str | None = None
license_plate_country: str | None = None
vin: str | None = None
current_odometer: int | None = None
engine_oil_type: str | None = None
engine_oil_volume_l: Decimal | None = None
@field_validator("vin")
@classmethod
def validate_vin_field(cls, value: str | None) -> str | None:
return validate_vin(value)
class VehicleUpdate(BaseModel):
name: str | None = None
make: str | None = None
model: str | None = None
year: int | None = None
license_plate: str | None = None
license_plate_country: str | None = None
vin: str | None = None
current_odometer: int | None = None
engine_oil_type: str | None = None
engine_oil_volume_l: Decimal | None = None
@field_validator("vin")
@classmethod
def validate_vin_field(cls, value: str | None) -> str | None:
return validate_vin(value)
class VehicleRead(BaseModel):
id: int
owner_id: int
name: str
make: str | None = None
model: str | None = None
year: int | None = None
license_plate_display: str | None = None
license_plate_country: str | None = None
vin_normalized: str | None = None
current_odometer: int | None = None
engine_oil_type: str | None = None
engine_oil_volume_l: Decimal | None = None
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class ServiceVisitCreate(BaseModel):
vehicle_id: int
visit_date: date
odometer: int | None = None
notes: str | None = None
total_cost: Decimal | None = None
currency: str = "RUB"
class ServiceVisitRead(ServiceVisitCreate):
id: int
service_center_id: int
created_by_employee_id: int | None = None
status: str
owner_resolved_at: datetime | None = None
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class ServiceWorkItemCreate(BaseModel):
work_type: str = "other"
title: str
description: str | None = None
parts: list[dict] | None = None
oil_brand: str | None = None
oil_viscosity: str | None = None
oil_volume: Decimal | None = None
next_due_odometer: int | None = None
next_due_date: date | None = None
price: Decimal | None = None
class ServiceWorkItemRead(ServiceWorkItemCreate):
id: int
service_visit_id: int
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class VehicleDataChangeRequestCreate(BaseModel):
vehicle_id: int
field_name: str
new_value: str | None = None
class VehicleDataChangeRequestRead(VehicleDataChangeRequestCreate):
id: int
requested_by_service_center_id: int | None = None
requested_by_employee_id: int | None = None
old_value: str | None = None
status: str
owner_user_id: int
created_at: datetime
resolved_at: datetime | None = None
model_config = ConfigDict(from_attributes=True)
class VehicleSearchRequest(BaseModel):
license_plate: str | None = None
country_code: str | None = None
vin: str | None = None
@field_validator("vin")
@classmethod
def validate_vin_field(cls, value: str | None) -> str | None:
return validate_vin(value)
@field_validator("license_plate")
@classmethod
def normalize_plate_field(cls, value: str | None) -> str | None:
return normalize_license_plate(value)
class VehicleSearchResult(BaseModel):
vehicle_id: int | None = None
make: str | None = None
model: str | None = None
year: int | None = None
masked_license_plate: str | None = None
masked_vin: str | None = None
access_status: str = "none"
class CarServiceLinkCreate(BaseModel):
car_id: int
service_center_id: int

View File

@@ -10,6 +10,7 @@ class UserUpsert(BaseModel):
last_name: str | None = None
locale: str | None = None
currency: str | None = None
platform_role: str | None = None
class WebAppAuthRequest(BaseModel):
@@ -27,7 +28,7 @@ class TelegramLoginRequest(BaseModel):
class AuthConfig(BaseModel):
bot_username: str
bot_username: str | None = None
vapid_public_key: str | None = None
app_env: str
allow_dev_auth: bool = False