from sqlalchemy import Column, String, Integer, Enum, DateTime, ForeignKey, UniqueConstraint from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base import enum class DependencyType(str, enum.Enum): """ Task dependency types for Gantt chart. FS (Finish-to-Start): Predecessor must finish before successor starts (most common) SS (Start-to-Start): Predecessor must start before successor starts FF (Finish-to-Finish): Predecessor must finish before successor finishes SF (Start-to-Finish): Predecessor must start before successor finishes (rare) """ FS = "FS" # Finish-to-Start SS = "SS" # Start-to-Start FF = "FF" # Finish-to-Finish SF = "SF" # Start-to-Finish class TaskDependency(Base): """ Represents a dependency relationship between two tasks. The predecessor task affects when the successor task can be scheduled, based on the dependency_type. This is used for Gantt chart visualization and date validation. """ __tablename__ = "pjctrl_task_dependencies" __table_args__ = ( UniqueConstraint('predecessor_id', 'successor_id', name='uq_predecessor_successor'), ) id = Column(String(36), primary_key=True) predecessor_id = Column( String(36), ForeignKey("pjctrl_tasks.id", ondelete="CASCADE"), nullable=False, index=True ) successor_id = Column( String(36), ForeignKey("pjctrl_tasks.id", ondelete="CASCADE"), nullable=False, index=True ) dependency_type = Column( Enum("FS", "SS", "FF", "SF", name="dependency_type_enum"), default="FS", nullable=False ) lag_days = Column(Integer, default=0, nullable=False) created_at = Column(DateTime, server_default=func.now(), nullable=False) # Relationships predecessor = relationship( "Task", foreign_keys=[predecessor_id], back_populates="successors" ) successor = relationship( "Task", foreign_keys=[successor_id], back_populates="predecessors" )