"""Phase 5.10 — Financial Reporting & BI domain models.""" from __future__ import annotations import uuid from datetime import date, datetime from decimal import Decimal from sqlalchemy import Boolean, Date, DateTime, Index, Integer, Numeric, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base from app.models.base import TenantMixin, TimestampMixin, UUIDPrimaryKeyMixin from app.models.types import GUID, ReportExportFormat, ReportStatus, ReportType class FinancialReport(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "financial_reports" report_type: Mapped[ReportType] = mapped_column(nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) fiscal_period_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) fiscal_year_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) generated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) status: Mapped[ReportStatus] = mapped_column(default=ReportStatus.GENERATED, nullable=False) report_data: Mapped[str | None] = mapped_column(Text, nullable=True) generated_by: Mapped[str | None] = mapped_column(String(100), nullable=True) __table_args__ = ( Index("ix_financial_reports_tenant_type", "tenant_id", "report_type"), ) class ReportTemplate(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "report_templates" name: Mapped[str] = mapped_column(String(255), nullable=False) report_type: Mapped[ReportType] = mapped_column(nullable=False) template_config: Mapped[str] = mapped_column(Text, nullable=False) is_system: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) __table_args__ = (UniqueConstraint("tenant_id", "name", name="uq_report_template_tenant_name"),) class Dashboard(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "dashboards" name: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[str | None] = mapped_column(Text, nullable=True) dashboard_type: Mapped[str] = mapped_column(String(50), nullable=False) layout_config: Mapped[str | None] = mapped_column(Text, nullable=True) is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) __table_args__ = (UniqueConstraint("tenant_id", "name", name="uq_dashboard_tenant_name"),) class DashboardWidget(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "dashboard_widgets" dashboard_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) widget_type: Mapped[str] = mapped_column(String(50), nullable=False) title: Mapped[str] = mapped_column(String(255), nullable=False) config: Mapped[str | None] = mapped_column(Text, nullable=True) position: Mapped[int] = mapped_column(Integer, default=0, nullable=False) class KPI(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "kpis" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) kpi_type: Mapped[str] = mapped_column(String(50), nullable=False) current_value: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) target_value: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) calculated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_kpi_tenant_code"),) class ReportSnapshot(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "report_snapshots" report_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) snapshot_date: Mapped[date] = mapped_column(Date, nullable=False) snapshot_data: Mapped[str] = mapped_column(Text, nullable=False) class ScheduledReport(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "scheduled_reports" template_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) report_type: Mapped[ReportType] = mapped_column(nullable=False) schedule_cron: Mapped[str] = mapped_column(String(100), nullable=False) recipients: Mapped[str | None] = mapped_column(Text, nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) last_run_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) class ReportExport(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "report_exports" report_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) export_format: Mapped[ReportExportFormat] = mapped_column(nullable=False) file_path: Mapped[str | None] = mapped_column(String(500), nullable=True) exported_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) exported_by: Mapped[str | None] = mapped_column(String(100), nullable=True) class ReportHistory(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "report_history" report_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) action: Mapped[str] = mapped_column(String(50), nullable=False) actor_user_id: Mapped[str] = mapped_column(String(100), nullable=False) class ReportConfiguration(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "report_configurations" key: Mapped[str] = mapped_column(String(100), nullable=False) value: Mapped[str | None] = mapped_column(Text, nullable=True) __table_args__ = (UniqueConstraint("tenant_id", "key", name="uq_report_config_tenant_key"),)