from datetime import date, datetime from decimal import Decimal from sqlalchemy import Boolean, Date, DateTime, Integer, Numeric, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base from app.modules.business.constants import ( PriorityValue, RiskLevel, SourceSystem, StatusValue, ) from app.modules.business.models.common import TimestampMixin class Project(Base, TimestampMixin): __tablename__ = "projects" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), unique=True, index=True) name: Mapped[str] = mapped_column(String(255), index=True) owner: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) status: Mapped[str] = mapped_column(String(64), default=StatusValue.INITIATED, index=True) priority: Mapped[str] = mapped_column(String(32), default=PriorityValue.P2) progress_percent: Mapped[int] = mapped_column(Integer, default=0) risk_level: Mapped[str] = mapped_column(String(32), default=RiskLevel.LOW, index=True) budget_amount: Mapped[Decimal] = mapped_column(Numeric(14, 2), default=0) actual_amount: Mapped[Decimal] = mapped_column(Numeric(14, 2), default=0) source_contract_amount: Mapped[Decimal | None] = mapped_column( Numeric(16, 2), nullable=True ) source_project_investment_amount: Mapped[Decimal | None] = mapped_column( Numeric(16, 2), nullable=True ) start_date: Mapped[date | None] = mapped_column(Date, nullable=True) due_date: Mapped[date | None] = mapped_column(Date, nullable=True, index=True) description: Mapped[str | None] = mapped_column(Text, nullable=True) source_system: Mapped[str] = mapped_column(String(64), default=SourceSystem.INTERNAL) external_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) display_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) department_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) department_name: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) owner_employee_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) source_stage: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True) source_stage_label: Mapped[str | None] = mapped_column(String(128), nullable=True) source_archived: Mapped[bool] = mapped_column(Boolean, default=False, index=True) source_created_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) source_updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True) last_seen_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, index=True) class WorkTask(Base, TimestampMixin): __tablename__ = "work_tasks" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), unique=True, index=True) title: Mapped[str] = mapped_column(String(255), index=True) project_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) owner: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) status: Mapped[str] = mapped_column(String(64), default=StatusValue.TODO, index=True) priority: Mapped[str] = mapped_column(String(32), default=PriorityValue.P2) due_date: Mapped[date | None] = mapped_column(Date, nullable=True, index=True) completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) blocker: Mapped[str | None] = mapped_column(Text, nullable=True) description: Mapped[str | None] = mapped_column(Text, nullable=True) source_system: Mapped[str] = mapped_column(String(64), default=SourceSystem.INTERNAL) external_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) employee_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) source_created_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) source_updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True) last_seen_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, index=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, index=True)