Nuevo Commit
This commit is contained in:
180
backend/add_questions.py
Normal file
180
backend/add_questions.py
Normal file
@@ -0,0 +1,180 @@
|
||||
"""
|
||||
Script para agregar preguntas a un checklist basado en el formato del PDF
|
||||
Ejecutar: docker cp add_questions.py checklist-backend:/app/ && docker-compose exec -T backend python /app/add_questions.py
|
||||
"""
|
||||
|
||||
from app.core.database import SessionLocal
|
||||
from app.models import Checklist, Question
|
||||
|
||||
# ID del checklist al que quieres agregar preguntas
|
||||
CHECKLIST_ID = 2 # Cambia este número según el ID de tu checklist
|
||||
|
||||
db = SessionLocal()
|
||||
|
||||
# Verificar que el checklist existe
|
||||
checklist = db.query(Checklist).filter(Checklist.id == CHECKLIST_ID).first()
|
||||
if not checklist:
|
||||
print(f"❌ Checklist con ID {CHECKLIST_ID} no encontrado")
|
||||
exit(1)
|
||||
|
||||
print(f"✅ Agregando preguntas al checklist: {checklist.name}")
|
||||
|
||||
# Definir todas las preguntas por sección
|
||||
questions_data = [
|
||||
# DOCUMENTACIÓN
|
||||
('Documentación', 'Cédula Verde', 'pass_fail', 2, False),
|
||||
('Documentación', 'Verificación Técnica Vehicular', 'pass_fail', 2, False),
|
||||
('Documentación', 'Póliza de Seguro', 'pass_fail', 2, False),
|
||||
('Documentación', 'Licencia de conducir del chofer', 'pass_fail', 2, False),
|
||||
|
||||
# EXTERIOR DEL VEHÍCULO
|
||||
('Exterior', 'Estado de carrocería', 'good_bad', 1, True),
|
||||
('Exterior', 'Espejo retrovisor izquierdo', 'pass_fail', 1, True),
|
||||
('Exterior', 'Espejo retrovisor derecho', 'pass_fail', 1, True),
|
||||
('Exterior', 'Parabrisas delantero', 'pass_fail', 1, True),
|
||||
('Exterior', 'Luneta trasera', 'pass_fail', 1, True),
|
||||
('Exterior', 'Cristales laterales', 'pass_fail', 1, True),
|
||||
('Exterior', 'Escobillas limpiaparabrisas', 'pass_fail', 1, True),
|
||||
('Exterior', 'Antena', 'pass_fail', 1, False),
|
||||
('Exterior', 'Tapa de combustible', 'pass_fail', 1, True),
|
||||
('Exterior', 'Paragolpes delantero', 'pass_fail', 1, True),
|
||||
('Exterior', 'Paragolpes trasero', 'pass_fail', 1, True),
|
||||
|
||||
# NEUMÁTICOS
|
||||
('Neumáticos', 'Neumático delantero izquierdo - Presión', 'pass_fail', 1, True),
|
||||
('Neumáticos', 'Neumático delantero izquierdo - Banda de rodadura', 'good_bad', 2, True),
|
||||
('Neumáticos', 'Neumático delantero derecho - Presión', 'pass_fail', 1, True),
|
||||
('Neumáticos', 'Neumático delantero derecho - Banda de rodadura', 'good_bad', 2, True),
|
||||
('Neumáticos', 'Neumático trasero izquierdo - Presión', 'pass_fail', 1, True),
|
||||
('Neumáticos', 'Neumático trasero izquierdo - Banda de rodadura', 'good_bad', 2, True),
|
||||
('Neumáticos', 'Neumático trasero derecho - Presión', 'pass_fail', 1, True),
|
||||
('Neumáticos', 'Neumático trasero derecho - Banda de rodadura', 'good_bad', 2, True),
|
||||
('Neumáticos', 'Neumático de auxilio - Estado', 'pass_fail', 1, True),
|
||||
|
||||
# SISTEMA ELÉCTRICO
|
||||
('Sistema Eléctrico', 'Batería - Estado', 'good_bad', 2, True),
|
||||
('Sistema Eléctrico', 'Luces de posición delanteras', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces bajas', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces altas', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces de giro delanteras', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces de freno', 'pass_fail', 2, False),
|
||||
('Sistema Eléctrico', 'Luces de retroceso', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces traseras', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces de giro traseras', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luz de patente', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luz interior', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Bocina', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Testigos en tablero', 'pass_fail', 1, True),
|
||||
|
||||
# MOTOR
|
||||
('Motor', 'Nivel de aceite', 'pass_fail', 2, True),
|
||||
('Motor', 'Fugas de aceite', 'pass_fail', 2, True),
|
||||
('Motor', 'Filtro de aceite', 'status', 1, True),
|
||||
('Motor', 'Nivel de refrigerante', 'pass_fail', 1, True),
|
||||
('Motor', 'Fugas de refrigerante', 'pass_fail', 2, True),
|
||||
('Motor', 'Estado de mangueras', 'pass_fail', 1, True),
|
||||
('Motor', 'Filtro de aire', 'status', 1, True),
|
||||
('Motor', 'Correa de distribución', 'pass_fail', 2, True),
|
||||
('Motor', 'Correas auxiliares', 'pass_fail', 1, True),
|
||||
|
||||
# FRENOS
|
||||
('Frenos', 'Pastillas/zapatas delanteras', 'good_bad', 2, True),
|
||||
('Frenos', 'Discos/tambores delanteros', 'good_bad', 2, True),
|
||||
('Frenos', 'Pastillas/zapatas traseras', 'good_bad', 2, True),
|
||||
('Frenos', 'Discos/tambores traseros', 'good_bad', 2, True),
|
||||
('Frenos', 'Nivel de líquido de frenos', 'pass_fail', 2, False),
|
||||
('Frenos', 'Porcentaje de humedad en líquido', 'numeric', 1, False),
|
||||
('Frenos', 'Freno de mano', 'pass_fail', 2, False),
|
||||
|
||||
# SUSPENSIÓN Y DIRECCIÓN
|
||||
('Suspensión', 'Amortiguadores delanteros', 'pass_fail', 2, True),
|
||||
('Suspensión', 'Amortiguadores traseros', 'pass_fail', 2, True),
|
||||
('Suspensión', 'Cojinetes de ruedas', 'pass_fail', 2, False),
|
||||
('Suspensión', 'Rótulas', 'pass_fail', 2, True),
|
||||
('Suspensión', 'Bieletas', 'pass_fail', 1, True),
|
||||
('Suspensión', 'Bujes', 'pass_fail', 1, True),
|
||||
('Dirección', 'Nivel de líquido de dirección', 'pass_fail', 1, True),
|
||||
('Dirección', 'Estado de cremallera/caja', 'pass_fail', 2, True),
|
||||
('Dirección', 'Fugas en dirección', 'pass_fail', 2, True),
|
||||
|
||||
# INTERIOR
|
||||
('Interior', 'Tablero de instrumentos', 'pass_fail', 1, True),
|
||||
('Interior', 'Funcionamiento de velocímetro', 'pass_fail', 1, False),
|
||||
('Interior', 'Funcionamiento de cuentakilómetros', 'pass_fail', 1, False),
|
||||
('Interior', 'Cinturones de seguridad delanteros', 'pass_fail', 2, True),
|
||||
('Interior', 'Cinturones de seguridad traseros', 'pass_fail', 2, True),
|
||||
('Interior', 'Asientos', 'pass_fail', 1, True),
|
||||
('Interior', 'Apoyacabezas', 'pass_fail', 1, True),
|
||||
('Interior', 'Aire acondicionado', 'pass_fail', 1, False),
|
||||
('Interior', 'Calefacción', 'pass_fail', 1, False),
|
||||
('Interior', 'Radio/sistema de audio', 'pass_fail', 1, False),
|
||||
('Interior', 'Ceniceros', 'pass_fail', 1, False),
|
||||
('Interior', 'Encendedor', 'pass_fail', 1, False),
|
||||
('Interior', 'Guantera', 'pass_fail', 1, False),
|
||||
('Interior', 'Tapizado', 'good_bad', 1, True),
|
||||
|
||||
# SEGURIDAD
|
||||
('Seguridad', 'Matafuego - Fecha de vencimiento', 'pass_fail', 2, True),
|
||||
('Seguridad', 'Matafuego - Presión', 'pass_fail', 2, True),
|
||||
('Seguridad', 'Balizas triangulares', 'pass_fail', 1, True),
|
||||
('Seguridad', 'Botiquín de primeros auxilios', 'pass_fail', 1, True),
|
||||
('Seguridad', 'Llave de ruedas', 'pass_fail', 1, False),
|
||||
('Seguridad', 'Gato hidráulico', 'pass_fail', 1, False),
|
||||
('Seguridad', 'Chaleco reflectivo', 'pass_fail', 1, False),
|
||||
|
||||
# TRANSMISIÓN
|
||||
('Transmisión', 'Nivel de aceite de transmisión', 'pass_fail', 1, True),
|
||||
('Transmisión', 'Fugas en transmisión', 'pass_fail', 2, True),
|
||||
('Transmisión', 'Estado de embrague', 'pass_fail', 2, False),
|
||||
('Transmisión', 'Funcionamiento de cambios', 'pass_fail', 2, False),
|
||||
|
||||
# ESCAPE
|
||||
('Escape', 'Estado del sistema de escape', 'pass_fail', 1, True),
|
||||
('Escape', 'Fugas en escape', 'pass_fail', 2, True),
|
||||
('Escape', 'Silenciador', 'pass_fail', 1, True),
|
||||
('Escape', 'Catalizador', 'pass_fail', 1, True),
|
||||
|
||||
# PRUEBA DE RUTA
|
||||
('Prueba de Ruta', 'Arranque del motor', 'pass_fail', 2, False),
|
||||
('Prueba de Ruta', 'Ralentí estable', 'pass_fail', 1, False),
|
||||
('Prueba de Ruta', 'Aceleración', 'pass_fail', 2, False),
|
||||
('Prueba de Ruta', 'Frenado', 'pass_fail', 2, False),
|
||||
('Prueba de Ruta', 'Dirección', 'pass_fail', 2, False),
|
||||
('Prueba de Ruta', 'Cambios de marcha', 'pass_fail', 2, False),
|
||||
('Prueba de Ruta', 'Ruidos anormales', 'pass_fail', 2, True),
|
||||
('Prueba de Ruta', 'Vibraciones', 'pass_fail', 1, True),
|
||||
]
|
||||
|
||||
# Agregar todas las preguntas
|
||||
max_score = 0
|
||||
for idx, (section, text, qtype, points, photos) in enumerate(questions_data):
|
||||
question = Question(
|
||||
checklist_id=checklist.id,
|
||||
section=section,
|
||||
text=text,
|
||||
type=qtype,
|
||||
points=points,
|
||||
order=idx + 1,
|
||||
allow_photos=photos,
|
||||
max_photos=3 if photos else 0,
|
||||
requires_comment_on_fail=False
|
||||
)
|
||||
db.add(question)
|
||||
max_score += points
|
||||
|
||||
# Actualizar puntuación máxima del checklist
|
||||
checklist.max_score = max_score
|
||||
db.commit()
|
||||
|
||||
print(f'✅ Se agregaron {len(questions_data)} preguntas al checklist')
|
||||
print(f'✅ Puntuación máxima: {max_score} puntos')
|
||||
print(f'\nDesglose por sección:')
|
||||
|
||||
# Contar preguntas por sección
|
||||
from collections import Counter
|
||||
sections = Counter([s for s, _, _, _, _ in questions_data])
|
||||
for section, count in sections.items():
|
||||
section_points = sum(p for s, _, _, p, _ in questions_data if s == section)
|
||||
print(f' - {section}: {count} preguntas ({section_points} puntos)')
|
||||
|
||||
db.close()
|
||||
@@ -24,7 +24,12 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
|
||||
|
||||
def decode_access_token(token: str):
|
||||
try:
|
||||
print(f"Attempting to decode token: {token[:50]}...") # Debug
|
||||
print(f"Using SECRET_KEY: {settings.SECRET_KEY[:20]}...") # Debug
|
||||
print(f"Using ALGORITHM: {settings.ALGORITHM}") # Debug
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
print(f"Successfully decoded payload: {payload}") # Debug
|
||||
return payload
|
||||
except JWTError:
|
||||
except JWTError as e:
|
||||
print(f"JWT decode error: {e}") # Debug
|
||||
return None
|
||||
|
||||
@@ -34,14 +34,18 @@ def get_current_user(
|
||||
):
|
||||
token = credentials.credentials
|
||||
payload = decode_access_token(token)
|
||||
print(f"Token payload: {payload}") # Debug
|
||||
if payload is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Token inválido o expirado"
|
||||
)
|
||||
|
||||
user = db.query(models.User).filter(models.User.id == payload.get("sub")).first()
|
||||
user_id = int(payload.get("sub"))
|
||||
print(f"Looking for user ID: {user_id}") # Debug
|
||||
user = db.query(models.User).filter(models.User.id == user_id).first()
|
||||
if user is None:
|
||||
print(f"User not found with ID: {user_id}") # Debug
|
||||
raise HTTPException(status_code=404, detail="Usuario no encontrado")
|
||||
|
||||
return user
|
||||
@@ -79,7 +83,7 @@ def login(user_login: schemas.UserLogin, db: Session = Depends(get_db)):
|
||||
detail="Usuario o contraseña incorrectos"
|
||||
)
|
||||
|
||||
access_token = create_access_token(data={"sub": user.id, "role": user.role})
|
||||
access_token = create_access_token(data={"sub": str(user.id), "role": user.role})
|
||||
return {
|
||||
"access_token": access_token,
|
||||
"token_type": "bearer",
|
||||
@@ -254,7 +258,7 @@ def get_inspection(
|
||||
current_user: models.User = Depends(get_current_user)
|
||||
):
|
||||
inspection = db.query(models.Inspection).options(
|
||||
joinedload(models.Inspection.checklist),
|
||||
joinedload(models.Inspection.checklist).joinedload(models.Checklist.questions),
|
||||
joinedload(models.Inspection.mechanic),
|
||||
joinedload(models.Inspection.answers).joinedload(models.Answer.question),
|
||||
joinedload(models.Inspection.answers).joinedload(models.Answer.media_files)
|
||||
|
||||
@@ -167,11 +167,11 @@ class MediaFile(MediaFileBase):
|
||||
class ChecklistWithQuestions(Checklist):
|
||||
questions: List[Question] = []
|
||||
|
||||
class InspectionDetail(Inspection):
|
||||
checklist: Checklist
|
||||
mechanic: User
|
||||
answers: List[Answer] = []
|
||||
|
||||
class AnswerWithMedia(Answer):
|
||||
media_files: List[MediaFile] = []
|
||||
question: Question
|
||||
|
||||
class InspectionDetail(Inspection):
|
||||
checklist: ChecklistWithQuestions
|
||||
mechanic: User
|
||||
answers: List[AnswerWithMedia] = []
|
||||
|
||||
72
backend/create_checklist.py
Normal file
72
backend/create_checklist.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from app.core.database import SessionLocal
|
||||
from app.models import Checklist, Question
|
||||
|
||||
db = SessionLocal()
|
||||
|
||||
# Crear checklist
|
||||
checklist = Checklist(
|
||||
name='Mantenimiento Preventivo',
|
||||
description='Checklist estándar de mantenimiento preventivo',
|
||||
ai_mode='assisted',
|
||||
scoring_enabled=True,
|
||||
is_active=True,
|
||||
created_by=1
|
||||
)
|
||||
db.add(checklist)
|
||||
db.commit()
|
||||
db.refresh(checklist)
|
||||
|
||||
# Crear preguntas por sección
|
||||
questions_data = [
|
||||
# Sistema Eléctrico
|
||||
('Sistema Eléctrico', 'Estado de la batería', 'good_bad', 1, True),
|
||||
('Sistema Eléctrico', 'Bocina', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Luces (posición, cruce, carretera)', 'pass_fail', 1, False),
|
||||
('Sistema Eléctrico', 'Testigos en cuadro', 'pass_fail', 1, True),
|
||||
|
||||
# Frenos
|
||||
('Frenos', 'Frenos (pastillas, discos)', 'pass_fail', 2, True),
|
||||
('Frenos', 'Líquido de freno', 'pass_fail', 1, False),
|
||||
('Frenos', 'Porcentaje de humedad', 'numeric', 1, False),
|
||||
|
||||
# Motor
|
||||
('Motor', 'Nivel de aceite', 'pass_fail', 1, True),
|
||||
('Motor', 'Fugas de aceite', 'pass_fail', 2, True),
|
||||
('Motor', 'Filtro de aceite', 'status', 1, True),
|
||||
('Motor', 'Fugas de refrigerante', 'pass_fail', 2, True),
|
||||
|
||||
# Neumáticos
|
||||
('Neumáticos', 'Presión neumáticos', 'pass_fail', 1, False),
|
||||
('Neumáticos', 'Banda de rodadura', 'good_bad', 1, True),
|
||||
|
||||
# Suspensión
|
||||
('Suspensión', 'Amortiguadores', 'pass_fail', 2, True),
|
||||
('Suspensión', 'Cojinetes de ruedas', 'pass_fail', 1, False),
|
||||
|
||||
# Varios
|
||||
('Exterior', 'Estado carrocería', 'good_bad', 1, True),
|
||||
('Exterior', 'Escobillas limpiaparabrisas', 'pass_fail', 1, True),
|
||||
('Interior', 'Aire acondicionado', 'pass_fail', 1, False),
|
||||
('Pruebas', 'Prueba dinámica del vehículo', 'pass_fail', 2, False),
|
||||
]
|
||||
|
||||
max_score = 0
|
||||
for idx, (section, text, qtype, points, photos) in enumerate(questions_data):
|
||||
question = Question(
|
||||
checklist_id=checklist.id,
|
||||
section=section,
|
||||
text=text,
|
||||
type=qtype,
|
||||
points=points,
|
||||
order=idx + 1,
|
||||
allow_photos=photos,
|
||||
max_photos=3
|
||||
)
|
||||
db.add(question)
|
||||
max_score += points
|
||||
|
||||
checklist.max_score = max_score
|
||||
db.commit()
|
||||
|
||||
print(f'✅ Checklist creado con {len(questions_data)} preguntas')
|
||||
print(f'✅ Puntuación máxima: {max_score}')
|
||||
@@ -5,8 +5,10 @@ alembic==1.13.1
|
||||
psycopg2-binary==2.9.9
|
||||
pydantic==2.5.3
|
||||
pydantic-settings==2.1.0
|
||||
email-validator==2.1.0
|
||||
python-jose[cryptography]==3.3.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
passlib==1.7.4
|
||||
bcrypt==4.0.1
|
||||
python-multipart==0.0.6
|
||||
openai==1.10.0
|
||||
Pillow==10.2.0
|
||||
|
||||
Reference in New Issue
Block a user