"""Report Template and Report Instance models for the Report Generator plugin.""" from __future__ import annotations import uuid from sqlalchemy import ForeignKey, Index, String, Text from sqlalchemy.dialects.postgresql import UUID as PGUUID from sqlalchemy.orm import Mapped, mapped_column from app.core.db import Base, TenantMixin class ReportTemplate(Base, TenantMixin): """Report template entity — Jinja2 or SQL template, tenant-scoped, soft-deletable.""" __tablename__ = "report_templates" __table_args__ = ( Index("ix_report_templates_tenant", "tenant_id"), Index("ix_report_templates_name", "name"), ) id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) name: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[str] = mapped_column(Text, nullable=False, default="") template_type: Mapped[str] = mapped_column( String(50), nullable=False, default="jinja2" ) content: Mapped[str] = mapped_column(Text, nullable=False) output_format: Mapped[str] = mapped_column( String(50), nullable=False, default="csv" ) created_by: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False) class ReportInstance(Base, TenantMixin): """Report instance entity — a generated report, tenant-scoped.""" __tablename__ = "report_instances" __table_args__ = ( Index("ix_report_instances_tenant", "tenant_id"), Index("ix_report_instances_template", "template_id"), Index("ix_report_instances_status", "status"), ) id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) template_id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), ForeignKey("report_templates.id", ondelete="CASCADE"), nullable=False, ) status: Mapped[str] = mapped_column( String(50), nullable=False, default="pending" ) output_path: Mapped[str | None] = mapped_column( String(1024), nullable=True ) error_message: Mapped[str | None] = mapped_column(Text, nullable=True) created_by: Mapped[uuid.UUID] = mapped_column(PGUUID(as_uuid=True), nullable=False)