from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Text, JSON, Float from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) username = Column(String(50), unique=True, index=True, nullable=False) email = Column(String(100), unique=True, index=True) password_hash = Column(String(255), nullable=False) role = Column(String(20), nullable=False) # admin, mechanic full_name = Column(String(100)) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) # Relationships checklists_created = relationship("Checklist", back_populates="creator") inspections = relationship("Inspection", back_populates="mechanic") api_tokens = relationship("APIToken", back_populates="user", cascade="all, delete-orphan") class APIToken(Base): __tablename__ = "api_tokens" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) token = Column(String(100), unique=True, index=True, nullable=False) description = Column(String(200)) is_active = Column(Boolean, default=True) last_used_at = Column(DateTime(timezone=True)) created_at = Column(DateTime(timezone=True), server_default=func.now()) # Relationship user = relationship("User", back_populates="api_tokens") class Checklist(Base): __tablename__ = "checklists" id = Column(Integer, primary_key=True, index=True) name = Column(String(200), nullable=False) description = Column(Text) ai_mode = Column(String(20), default="off") # off, assisted, copilot scoring_enabled = Column(Boolean, default=True) max_score = Column(Integer, default=0) logo_url = Column(String(500)) is_active = Column(Boolean, default=True) created_by = Column(Integer, ForeignKey("users.id")) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # Relationships creator = relationship("User", back_populates="checklists_created") questions = relationship("Question", back_populates="checklist", cascade="all, delete-orphan") inspections = relationship("Inspection", back_populates="checklist") class Question(Base): __tablename__ = "questions" id = Column(Integer, primary_key=True, index=True) checklist_id = Column(Integer, ForeignKey("checklists.id"), nullable=False) section = Column(String(100)) # Sistema eléctrico, Frenos, etc text = Column(Text, nullable=False) type = Column(String(30), nullable=False) # pass_fail, good_bad, text, etc points = Column(Integer, default=1) options = Column(JSON) # Para multiple choice order = Column(Integer, default=0) allow_photos = Column(Boolean, default=True) max_photos = Column(Integer, default=3) requires_comment_on_fail = Column(Boolean, default=False) created_at = Column(DateTime(timezone=True), server_default=func.now()) # Relationships checklist = relationship("Checklist", back_populates="questions") answers = relationship("Answer", back_populates="question") class Inspection(Base): __tablename__ = "inspections" id = Column(Integer, primary_key=True, index=True) checklist_id = Column(Integer, ForeignKey("checklists.id"), nullable=False) mechanic_id = Column(Integer, ForeignKey("users.id"), nullable=False) # Datos de la OR or_number = Column(String(50)) work_order_number = Column(String(50)) # Datos del vehículo vehicle_plate = Column(String(20), nullable=False, index=True) vehicle_brand = Column(String(50)) vehicle_model = Column(String(100)) vehicle_km = Column(Integer) client_name = Column(String(200)) # Scoring score = Column(Integer, default=0) max_score = Column(Integer, default=0) percentage = Column(Float, default=0.0) flagged_items_count = Column(Integer, default=0) # Estado status = Column(String(20), default="draft") # draft, completed, inactive is_active = Column(Boolean, default=True) # Firma signature_data = Column(Text) # Base64 de la firma signed_at = Column(DateTime(timezone=True)) # Timestamps started_at = Column(DateTime(timezone=True), server_default=func.now()) completed_at = Column(DateTime(timezone=True)) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # Relationships checklist = relationship("Checklist", back_populates="inspections") mechanic = relationship("User", back_populates="inspections") answers = relationship("Answer", back_populates="inspection", cascade="all, delete-orphan") class Answer(Base): __tablename__ = "answers" id = Column(Integer, primary_key=True, index=True) inspection_id = Column(Integer, ForeignKey("inspections.id"), nullable=False) question_id = Column(Integer, ForeignKey("questions.id"), nullable=False) answer_value = Column(Text) # La respuesta del mecánico status = Column(String(20), default="ok") # ok, warning, critical, info points_earned = Column(Integer, default=0) comment = Column(Text) # Comentarios adicionales ai_analysis = Column(JSON) # Análisis de IA si aplica is_flagged = Column(Boolean, default=False) # Si requiere atención created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # Relationships inspection = relationship("Inspection", back_populates="answers") question = relationship("Question", back_populates="answers") media_files = relationship("MediaFile", back_populates="answer", cascade="all, delete-orphan") class MediaFile(Base): __tablename__ = "media_files" id = Column(Integer, primary_key=True, index=True) answer_id = Column(Integer, ForeignKey("answers.id"), nullable=False) file_path = Column(String(500), nullable=False) file_type = Column(String(20), default="image") # image, video caption = Column(Text) order = Column(Integer, default=0) uploaded_at = Column(DateTime(timezone=True), server_default=func.now()) # Relationships answer = relationship("Answer", back_populates="media_files") class AIConfiguration(Base): __tablename__ = "ai_configurations" id = Column(Integer, primary_key=True, index=True) provider = Column(String(50), nullable=False) # openai, gemini api_key = Column(Text, nullable=False) model_name = Column(String(100), nullable=False) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now())