from datetime import date, datetime from sqlalchemy import JSON, Date, DateTime, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.constants import ActorValue from app.core.database import Base from app.core.utils.time import utc_now from app.modules.business.constants import ( RiskLevel, StatusValue, ) from app.modules.business.models.common import TimestampMixin class RiskEvent(Base, TimestampMixin): __tablename__ = "risk_events" 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) risk_type: Mapped[str] = mapped_column(String(64), index=True) risk_level: Mapped[str] = mapped_column(String(32), default=RiskLevel.MEDIUM, index=True) status: Mapped[str] = mapped_column(String(32), default=StatusValue.OPEN, index=True) source_domain: Mapped[str] = mapped_column(String(128), index=True) source_record_id: Mapped[str | None] = mapped_column(String(128), nullable=True, 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) detected_at: Mapped[datetime] = mapped_column(DateTime, default=utc_now, index=True) due_date: Mapped[date | None] = mapped_column(Date, nullable=True, index=True) assigned_to: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) resolved_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) closed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) closed_reason: Mapped[str | None] = mapped_column(Text, nullable=True) review_summary: Mapped[str | None] = mapped_column(Text, nullable=True) description: Mapped[str | None] = mapped_column(Text, nullable=True) mitigation: Mapped[str | None] = mapped_column(Text, nullable=True) evidence: Mapped[dict | None] = mapped_column(JSON, nullable=True) class RiskEventAction(Base): __tablename__ = "risk_event_actions" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(64), unique=True, index=True) risk_event_id: Mapped[int] = mapped_column(Integer, index=True) action: Mapped[str] = mapped_column(String(64), index=True) actor: Mapped[str] = mapped_column(String(128), default=ActorValue.SYSTEM, index=True) from_status: Mapped[str | None] = mapped_column(String(32), nullable=True) to_status: Mapped[str | None] = mapped_column(String(32), nullable=True) assigned_to: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True) comment: Mapped[str | None] = mapped_column(Text, nullable=True) payload: Mapped[dict | None] = mapped_column(JSON, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=utc_now, index=True)