168 lines
6.3 KiB
Python
168 lines
6.3 KiB
Python
from sqlalchemy import Table, Column, Integer, String, Boolean, ForeignKey, DateTime, Text, Enum, JSON
|
|
from sqlalchemy.orm import relationship
|
|
from database import Base
|
|
import datetime
|
|
import enum
|
|
|
|
# Junction Tables
|
|
project_specialties = Table(
|
|
'project_specialties',
|
|
Base.metadata,
|
|
Column('project_id', Integer, ForeignKey('projects.id'), primary_key=True),
|
|
Column('specialty_id', Integer, ForeignKey('specialties.id'), primary_key=True)
|
|
)
|
|
|
|
project_contractors = Table(
|
|
'project_contractors',
|
|
Base.metadata,
|
|
Column('project_id', Integer, ForeignKey('projects.id'), primary_key=True),
|
|
Column('contractor_id', Integer, ForeignKey('contractors.id'), primary_key=True)
|
|
)
|
|
|
|
class UserRole(str, enum.Enum):
|
|
ADMIN = "admin"
|
|
DIRECTOR = "director"
|
|
SUPERVISOR = "supervisor"
|
|
COORDINATOR = "coordinator"
|
|
CONTRACTOR = "contractor"
|
|
CLIENT = "client"
|
|
|
|
class ActivityType(str, enum.Enum):
|
|
INSPECTION = "inspection"
|
|
MEETING = "meeting"
|
|
VIRTUAL_MEETING = "virtual_meeting"
|
|
COORDINATION = "coordination"
|
|
TEST = "test"
|
|
OTHER = "other"
|
|
|
|
class NCLevel(str, enum.Enum):
|
|
CRITICAL = "critical"
|
|
MAJOR = "major"
|
|
MINOR = "minor"
|
|
|
|
class NCType(str, enum.Enum):
|
|
HUMAN_ERROR = "Errores humanos"
|
|
PROCESS_FAILURE = "Fallas en los procesos"
|
|
DESIGN_ISSUE = "Problemas de diseño"
|
|
UNCONTROLLED_CHANGE = "Cambios no controlados"
|
|
COMMUNICATION_FAILURE = "Falta de comunicación"
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
email = Column(String, unique=True, index=True, nullable=False)
|
|
hashed_password = Column(String, nullable=False)
|
|
full_name = Column(String)
|
|
role = Column(Enum(UserRole), default=UserRole.SUPERVISOR)
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
class Project(Base):
|
|
__tablename__ = "projects"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, index=True, nullable=False)
|
|
code = Column(String, unique=True, index=True)
|
|
location = Column(String)
|
|
start_date = Column(DateTime)
|
|
end_date = Column(DateTime)
|
|
status = Column(String, default="active")
|
|
parent_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
|
|
|
|
# Relationships
|
|
parent = relationship("Project", remote_side=[id], back_populates="subprojects")
|
|
subprojects = relationship("Project", back_populates="parent")
|
|
activities = relationship("Activity", back_populates="project")
|
|
specialties = relationship("Specialty", secondary=project_specialties)
|
|
contractors = relationship("Contractor", secondary=project_contractors)
|
|
|
|
class Specialty(Base):
|
|
__tablename__ = "specialties"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, unique=True, nullable=False) # Civil, Mecánica, Eléctrica, SSOMA
|
|
|
|
class Contractor(Base):
|
|
__tablename__ = "contractors"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, nullable=False)
|
|
ruc = Column(String, unique=True)
|
|
contact_name = Column(String)
|
|
email = Column(String, nullable=True)
|
|
phone = Column(String, nullable=True)
|
|
address = Column(String, nullable=True)
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
specialty_id = Column(Integer, ForeignKey("specialties.id"), nullable=True)
|
|
parent_id = Column(Integer, ForeignKey("contractors.id"), nullable=True)
|
|
|
|
specialty = relationship("Specialty")
|
|
parent = relationship("Contractor", remote_side=[id], back_populates="subcontractors")
|
|
subcontractors = relationship("Contractor", back_populates="parent")
|
|
|
|
class Activity(Base):
|
|
__tablename__ = "activities"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
project_id = Column(Integer, ForeignKey("projects.id"))
|
|
specialty_id = Column(Integer, ForeignKey("specialties.id"))
|
|
contractor_id = Column(Integer, ForeignKey("contractors.id"), nullable=True)
|
|
user_id = Column(Integer, ForeignKey("users.id")) # Reporter
|
|
|
|
date = Column(DateTime, default=datetime.datetime.utcnow)
|
|
end_date = Column(DateTime, nullable=True)
|
|
type = Column(Enum(ActivityType), default=ActivityType.INSPECTION)
|
|
area = Column(String) # Frente de obra / Linea
|
|
description = Column(Text)
|
|
observations = Column(Text)
|
|
audio_transcription = Column(Text, nullable=True)
|
|
status = Column(String, default="completed")
|
|
|
|
project = relationship("Project", back_populates="activities")
|
|
specialty = relationship("Specialty")
|
|
contractor = relationship("Contractor")
|
|
reporter = relationship("User")
|
|
|
|
non_conformities = relationship("NonConformity", back_populates="activity")
|
|
evidences = relationship("Evidence", back_populates="activity")
|
|
|
|
class NonConformity(Base):
|
|
__tablename__ = "non_conformities"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
activity_id = Column(Integer, ForeignKey("activities.id"))
|
|
level = Column(Enum(NCLevel), default=NCLevel.MINOR)
|
|
description = Column(Text, nullable=False)
|
|
status = Column(String, default="open") # open, closed
|
|
|
|
# New Fields
|
|
due_date = Column(DateTime, nullable=True)
|
|
responsible_person = Column(String, nullable=True)
|
|
action_checklist = Column(JSON, nullable=True) # List of dicts {text: str, completed: bool}
|
|
nc_type = Column(Enum(NCType), nullable=True)
|
|
impact_description = Column(Text, nullable=True)
|
|
closure_description = Column(Text, nullable=True)
|
|
|
|
activity = relationship("Activity", back_populates="non_conformities")
|
|
evidences = relationship("Evidence", back_populates="non_conformity")
|
|
|
|
class Evidence(Base):
|
|
__tablename__ = "evidences"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
activity_id = Column(Integer, ForeignKey("activities.id"), nullable=True)
|
|
non_conformity_id = Column(Integer, ForeignKey("non_conformities.id"), nullable=True)
|
|
|
|
file_path = Column(String, nullable=False)
|
|
media_type = Column(String) # image, video, document
|
|
description = Column(String)
|
|
captured_at = Column(DateTime, default=datetime.datetime.utcnow)
|
|
|
|
# Transcription fields for audio
|
|
transcription = Column(Text, nullable=True)
|
|
transcription_status = Column(String, default="none") # none, pending, processing, completed, error
|
|
|
|
activity = relationship("Activity", back_populates="evidences")
|
|
non_conformity = relationship("NonConformity", back_populates="evidences")
|