""" KPI 範本 Model """ from datetime import datetime from typing import Optional, List, TYPE_CHECKING from sqlalchemy import String, Integer, Boolean, DateTime, Text, ForeignKey, JSON from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.database import Base if TYPE_CHECKING: from app.models.kpi_item import KPIItem class KPITemplate(Base): """KPI 範本""" __tablename__ = "KPI_D_templates" id: Mapped[int] = mapped_column(primary_key=True) code: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) name: Mapped[str] = mapped_column(String(200), nullable=False) category: Mapped[str] = mapped_column(String(50), nullable=False) # financial, customer, internal, learning description: Mapped[Optional[str]] = mapped_column(Text) default_weight: Mapped[int] = mapped_column(Integer, default=20) level0_desc: Mapped[str] = mapped_column(Text, nullable=False) level1_desc: Mapped[str] = mapped_column(Text, nullable=False) level2_desc: Mapped[str] = mapped_column(Text, nullable=False) level3_desc: Mapped[str] = mapped_column(Text, nullable=False) level4_desc: Mapped[str] = mapped_column(Text, nullable=False) applicable_roles: Mapped[Optional[str]] = mapped_column(JSON) # JSON array for MySQL applicable_depts: Mapped[Optional[str]] = mapped_column(JSON) # JSON array for MySQL is_active: Mapped[bool] = mapped_column(Boolean, default=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships kpi_items: Mapped[List["KPIItem"]] = relationship("KPIItem", back_populates="template") preset_items: Mapped[List["KPIPresetItem"]] = relationship("KPIPresetItem", back_populates="template") def __repr__(self) -> str: return f"" class KPIPreset(Base): """KPI 預設組合""" __tablename__ = "KPI_D_presets" id: Mapped[int] = mapped_column(primary_key=True) code: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) name: Mapped[str] = mapped_column(String(200), nullable=False) description: Mapped[Optional[str]] = mapped_column(Text) applicable_roles: Mapped[Optional[str]] = mapped_column(JSON) # JSON array for MySQL applicable_depts: Mapped[Optional[str]] = mapped_column(JSON) # JSON array for MySQL is_active: Mapped[bool] = mapped_column(Boolean, default=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships items: Mapped[List["KPIPresetItem"]] = relationship( "KPIPresetItem", back_populates="preset", cascade="all, delete-orphan" ) def __repr__(self) -> str: return f"" class KPIPresetItem(Base): """KPI 預設項目""" __tablename__ = "KPI_D_preset_items" id: Mapped[int] = mapped_column(primary_key=True) preset_id: Mapped[int] = mapped_column(ForeignKey("KPI_D_presets.id", ondelete="CASCADE"), nullable=False) template_id: Mapped[int] = mapped_column(ForeignKey("KPI_D_templates.id"), nullable=False) default_weight: Mapped[int] = mapped_column(Integer, nullable=False) is_mandatory: Mapped[bool] = mapped_column(Boolean, default=False) sort_order: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) # Relationships preset: Mapped["KPIPreset"] = relationship("KPIPreset", back_populates="items") template: Mapped["KPITemplate"] = relationship("KPITemplate", back_populates="preset_items") def __repr__(self) -> str: return f""