from pydantic import BaseModel, EmailStr, Field from typing import Optional, List from datetime import datetime # Role Schemas class RoleBase(BaseModel): name: str display_name: str description: Optional[str] = None can_manage_users: bool = False can_manage_roles: bool = False can_manage_checklists: bool = False can_create_inspections: bool = False can_view_all_inspections: bool = False can_view_reports: bool = False can_deactivate_inspections: bool = False class RoleCreate(RoleBase): pass class RoleUpdate(BaseModel): display_name: Optional[str] = None description: Optional[str] = None can_manage_users: Optional[bool] = None can_manage_roles: Optional[bool] = None can_manage_checklists: Optional[bool] = None can_create_inspections: Optional[bool] = None can_view_all_inspections: Optional[bool] = None can_view_reports: Optional[bool] = None can_deactivate_inspections: Optional[bool] = None class Role(RoleBase): id: int created_at: datetime class Config: from_attributes = True # User Schemas class UserBase(BaseModel): username: str email: Optional[EmailStr] = None full_name: Optional[str] = None role_id: int = 3 # Default: mecanico class UserCreate(UserBase): password: str class UserUpdate(BaseModel): username: Optional[str] = None email: Optional[EmailStr] = None full_name: Optional[str] = None role_id: Optional[int] = None class UserPasswordUpdate(BaseModel): current_password: str new_password: str class AdminPasswordUpdate(BaseModel): new_password: str class UserLogin(BaseModel): username: str password: str class User(BaseModel): id: int username: str email: Optional[str] = None full_name: Optional[str] = None role_id: int role: Role # Role object is_active: bool created_at: datetime class Config: from_attributes = True class Token(BaseModel): access_token: str token_type: str user: User # API Token Schemas class APITokenCreate(BaseModel): description: Optional[str] = None class APIToken(BaseModel): id: int description: Optional[str] = None is_active: bool last_used_at: Optional[datetime] = None created_at: datetime class Config: from_attributes = True class APITokenWithValue(APIToken): token: str # Checklist Schemas class ChecklistBase(BaseModel): name: str description: Optional[str] = None ai_mode: str = "off" scoring_enabled: bool = True logo_url: Optional[str] = None class ChecklistCreate(ChecklistBase): pass class ChecklistUpdate(ChecklistBase): is_active: Optional[bool] = None class Checklist(ChecklistBase): id: int max_score: int is_active: bool created_by: int created_at: datetime class Config: from_attributes = True # Question Schemas class QuestionBase(BaseModel): section: Optional[str] = None text: str type: str points: int = 1 options: Optional[dict] = None order: int = 0 allow_photos: bool = True max_photos: int = 3 requires_comment_on_fail: bool = False class QuestionCreate(QuestionBase): checklist_id: int class QuestionUpdate(QuestionBase): pass class Question(QuestionBase): id: int checklist_id: int created_at: datetime class Config: from_attributes = True # Inspection Schemas class InspectionBase(BaseModel): or_number: Optional[str] = None work_order_number: Optional[str] = None vehicle_plate: str vehicle_brand: Optional[str] = None vehicle_model: Optional[str] = None vehicle_km: Optional[int] = None client_name: Optional[str] = None class InspectionCreate(InspectionBase): checklist_id: int class InspectionUpdate(BaseModel): vehicle_brand: Optional[str] = None vehicle_model: Optional[str] = None vehicle_km: Optional[int] = None signature_data: Optional[str] = None status: Optional[str] = None class Inspection(InspectionBase): id: int checklist_id: int mechanic_id: int score: int max_score: int percentage: float flagged_items_count: int status: str started_at: datetime completed_at: Optional[datetime] = None class Config: from_attributes = True # Answer Schemas class AnswerBase(BaseModel): answer_value: str status: str = "ok" comment: Optional[str] = None is_flagged: bool = False class AnswerCreate(AnswerBase): inspection_id: int question_id: int class AnswerUpdate(AnswerBase): pass class Answer(AnswerBase): id: int inspection_id: int question_id: int points_earned: int ai_analysis: Optional[dict] = None created_at: datetime class Config: from_attributes = True # MediaFile Schemas class MediaFileBase(BaseModel): caption: Optional[str] = None order: int = 0 class MediaFileCreate(MediaFileBase): file_type: str = "image" class MediaFile(MediaFileBase): id: int answer_id: int file_path: str file_type: str uploaded_at: datetime class Config: from_attributes = True # Response Schemas class ChecklistWithQuestions(Checklist): questions: List[Question] = [] class AnswerWithMedia(Answer): media_files: List[MediaFile] = [] question: Question class InspectionDetail(Inspection): checklist: ChecklistWithQuestions mechanic: User answers: List[AnswerWithMedia] = [] # AI Configuration Schemas class AIConfigurationBase(BaseModel): provider: str # openai, gemini api_key: str model_name: str class AIConfigurationCreate(AIConfigurationBase): pass class AIConfigurationUpdate(BaseModel): provider: Optional[str] = None api_key: Optional[str] = None model_name: Optional[str] = None is_active: Optional[bool] = None class AIConfiguration(AIConfigurationBase): id: int is_active: bool created_at: datetime class Config: from_attributes = True class AIModelInfo(BaseModel): id: str name: str provider: str description: Optional[str] = None