Files
checklist/backend/app/schemas.py
ronalds fdad7b10ad v1.0.64 Backend / v1.0.58 Frontend - Renombrar cliente a N° de Pedido
Backend (1.0.64):
- Renombrado campo client_name a order_number en modelo Inspection
- Actualizado InspectionBase schema con nuevo campo order_number
- Comentario descriptivo: "Número de pedido asociado a la inspección"

Frontend (1.0.58):
- Renombrado client_name a order_number en toda la aplicación
- Actualizado label: "Nombre del Cliente" → "Nº de Pedido"
- Actualizado placeholder: "Juan Pérez" → "PED-12345"
- Actualizado título sección: "Información del Cliente" → "Información del Pedido"
- Actualizado filtro de búsqueda para incluir número de pedido
- Actualizado texto de búsqueda: "cliente" → "Nº pedido"

Database:
- Script de migración: rename_client_name_to_order_number.sql
- Comando: ALTER TABLE inspections RENAME COLUMN client_name TO order_number

Nota: Ejecutar migración SQL antes de usar esta versión
2025-11-27 01:49:42 -03:00

358 lines
8.8 KiB
Python

from pydantic import BaseModel, EmailStr, Field
from typing import Optional, List
from datetime import datetime
# User Schemas
class UserBase(BaseModel):
username: str
email: Optional[EmailStr] = None
full_name: Optional[str] = None
employee_code: Optional[str] = None # Nro Operario - código de otro sistema
role: str = "mechanic"
class UserCreate(UserBase):
password: str
class UserUpdate(BaseModel):
username: Optional[str] = None
email: Optional[EmailStr] = None
full_name: Optional[str] = None
employee_code: Optional[str] = None
role: Optional[str] = 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(UserBase):
id: int
employee_code: Optional[str] = None
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):
mechanic_ids: Optional[List[int]] = [] # IDs de mecánicos autorizados
class ChecklistUpdate(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
ai_mode: Optional[str] = None
scoring_enabled: Optional[bool] = None
logo_url: Optional[str] = None
is_active: Optional[bool] = None
mechanic_ids: Optional[List[int]] = None # IDs de mecánicos autorizados
class Checklist(ChecklistBase):
id: int
max_score: int
is_active: bool
created_by: int
created_at: datetime
allowed_mechanics: Optional[List[int]] = [] # IDs de mecánicos permitidos
class Config:
from_attributes = True
# Question Schemas
# Tipos de preguntas soportados:
# - boolean: Dos opciones personalizables (ej: Sí/No, Pasa/Falla)
# - single_choice: Selección única con N opciones
# - multiple_choice: Selección múltiple
# - scale: Escala numérica (1-5, 1-10, etc.)
# - text: Texto libre
# - number: Valor numérico
# - date: Fecha
# - time: Hora
class QuestionBase(BaseModel):
section: Optional[str] = None
text: str
type: str # boolean, single_choice, multiple_choice, scale, text, number, date, time
points: int = 1
options: Optional[dict] = None # Configuración flexible según tipo
# Estructura de options:
# Boolean: {"type": "boolean", "choices": [{"value": "yes", "label": "Sí", "points": 1, "status": "ok"}, ...]}
# Single/Multiple Choice: {"type": "single_choice", "choices": [{"value": "opt1", "label": "Opción 1", "points": 2}, ...]}
# Scale: {"type": "scale", "min": 1, "max": 5, "step": 1, "labels": {"min": "Muy malo", "max": "Excelente"}}
# Text: {"type": "text", "multiline": true, "max_length": 500}
order: int = 0
allow_photos: bool = True
max_photos: int = 3
requires_comment_on_fail: bool = False
send_notification: bool = False
parent_question_id: Optional[int] = None
show_if_answer: Optional[str] = None
ai_prompt: Optional[str] = None
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
# Question Audit Schemas
class QuestionAuditLog(BaseModel):
id: int
question_id: int
checklist_id: int
user_id: int
action: str
field_name: Optional[str] = None
old_value: Optional[str] = None
new_value: Optional[str] = None
comment: Optional[str] = None
created_at: datetime
user: Optional['User'] = None
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
order_number: Optional[str] = None # Nº de Pedido
mechanic_employee_code: 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
mechanic_employee_code: Optional[str] = None
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
ai_analysis: Optional[dict] = None # Análisis de IA completo
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: Optional[str] = None
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
# Reports Schemas
class InspectionStats(BaseModel):
total_inspections: int
completed_inspections: int
pending_inspections: int
completion_rate: float
avg_score: float
total_flagged_items: int
class MechanicRanking(BaseModel):
mechanic_id: int
mechanic_name: str
total_inspections: int
avg_score: float
completion_rate: float
class ChecklistStats(BaseModel):
checklist_id: int
checklist_name: str
total_inspections: int
avg_score: float
class DashboardData(BaseModel):
stats: InspectionStats
mechanic_ranking: List[MechanicRanking]
checklist_stats: List[ChecklistStats]
inspections_by_date: dict
pass_fail_ratio: dict
class InspectionListItem(BaseModel):
id: int
vehicle_plate: str
checklist_name: str
mechanic_name: str
status: str
score: Optional[int]
max_score: Optional[int]
flagged_items: int
started_at: Optional[datetime]
completed_at: Optional[datetime]
# Audit Log Schemas
class AuditLogBase(BaseModel):
action: str
entity_type: str
field_name: Optional[str] = None
old_value: Optional[str] = None
new_value: Optional[str] = None
comment: Optional[str] = None
class AuditLog(AuditLogBase):
id: int
inspection_id: int
answer_id: Optional[int] = None
user_id: int
user_name: Optional[str] = None
created_at: datetime
class Config:
from_attributes = True
class AnswerEdit(BaseModel):
answer_value: Optional[str] = None
status: Optional[str] = None
comment: Optional[str] = None
is_flagged: Optional[bool] = None
edit_comment: Optional[str] = None # Comentario del admin sobre por qué editó