"""Report and analytics models.""" from datetime import datetime from uuid import UUID, uuid4 from sqlalchemy import String, ForeignKey, Text, JSON from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base class Report(Base): __tablename__ = "reports" id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4) tenant_id: Mapped[UUID] = mapped_column( ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False ) name: Mapped[str] = mapped_column(String(255), nullable=False) type: Mapped[str] = mapped_column(String(50), nullable=False) config: Mapped[dict] = mapped_column(JSON, default=dict) schedule: Mapped[str | None] # Cron expression or null for one-time last_run_at: Mapped[datetime | None] next_run_at: Mapped[datetime | None] created_by: Mapped[UUID | None] = mapped_column(ForeignKey("users.id")) created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow) # Relationships tenant: Mapped["Tenant"] = relationship(back_populates="reports") runs: Mapped[list["ReportRun"]] = relationship( back_populates="report", cascade="all, delete-orphan" ) def __repr__(self) -> str: return f"" class ReportRunStatus(str, Enum): RUNNING = "running" COMPLETED = "completed" FAILED = "failed" class ReportRun(Base): __tablename__ = "report_runs" id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4) report_id: Mapped[UUID] = mapped_column( ForeignKey("reports.id", ondelete="CASCADE"), nullable=False ) status: Mapped[ReportRunStatus] = mapped_column(default=ReportRunStatus.RUNNING) result_url: Mapped[str | None] = mapped_column(Text) error_message: Mapped[str | None] = mapped_column(Text) started_at: Mapped[datetime] = mapped_column(default=datetime.utcnow) completed_at: Mapped[datetime | None] # Relationships report: Mapped["Report"] = relationship(back_populates="runs") def __repr__(self) -> str: return f""