from __future__ import annotations from datetime import date, datetime, time from sqlalchemy import String, Boolean, Integer, Time, Date, DateTime, ForeignKey, UniqueConstraint, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.db.common import CommonBase class Tenant(CommonBase): __tablename__ = "tenants" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) code: Mapped[str] = mapped_column(String(50), unique=True, index=True) name: Mapped[str] = mapped_column(String(200)) is_active: Mapped[bool] = mapped_column(Boolean, default=True) firm_type: Mapped[str] = mapped_column(String(30), default="proprietorship") # partnership|proprietorship|individual # Tenant-level defaults default_timezone: Mapped[str] = mapped_column(String(64), default="Asia/Kolkata") default_session_duration_minutes: Mapped[int] = mapped_column(Integer, default=480) default_otp_required_roles_csv: Mapped[str] = mapped_column( String(200), default="Partner,System Admin", ) default_storage_mode: Mapped[str] = mapped_column( String(20), default="local_only", ) # local_only|cloud_only|hybrid # Phase 7Q.2 - firm branding defaults display_name: Mapped[str | None] = mapped_column(String(200), nullable=True) logo_path: Mapped[str | None] = mapped_column(String(500), nullable=True) favicon_path: Mapped[str | None] = mapped_column(String(500), nullable=True) primary_color: Mapped[str | None] = mapped_column(String(20), nullable=True) accent_color: Mapped[str | None] = mapped_column(String(20), nullable=True) website_url: Mapped[str | None] = mapped_column(String(255), nullable=True) contact_email: Mapped[str | None] = mapped_column(String(255), nullable=True) contact_mobile: Mapped[str | None] = mapped_column(String(50), nullable=True) class Branch(CommonBase): __tablename__ = "branches" __table_args__ = ( UniqueConstraint("tenant_id", "code", name="uq_branch_tenant_code"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) tenant_id: Mapped[int] = mapped_column( ForeignKey("tenants.id", ondelete="CASCADE"), index=True, ) code: Mapped[str] = mapped_column(String(50), index=True) name: Mapped[str] = mapped_column(String(200)) is_active: Mapped[bool] = mapped_column(Boolean, default=True) timezone: Mapped[str] = mapped_column(String(64), default="Asia/Kolkata") office_start_time: Mapped[time | None] = mapped_column(Time, nullable=True) office_end_time: Mapped[time | None] = mapped_column(Time, nullable=True) # Branch control flags allow_login: Mapped[bool] = mapped_column(Boolean, default=True) allow_new_assignments: Mapped[bool] = mapped_column(Boolean, default=True) is_head_office: Mapped[bool] = mapped_column(Boolean, default=False) # SMTP (credentials here; policy in BranchSettings) smtp_host: Mapped[str | None] = mapped_column(String(255), nullable=True) smtp_port: Mapped[int | None] = mapped_column(Integer, nullable=True) smtp_username: Mapped[str | None] = mapped_column(String(255), nullable=True) smtp_password: Mapped[str | None] = mapped_column(String(255), nullable=True) smtp_use_tls: Mapped[bool] = mapped_column(Boolean, default=True) # Local storage root for branch PC local_storage_path: Mapped[str | None] = mapped_column(String(500), nullable=True) class FinancialYear(CommonBase): __tablename__ = "financial_years" __table_args__ = ( UniqueConstraint("tenant_id", "year_code", name="uq_financial_year_tenant_code"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) tenant_id: Mapped[int] = mapped_column( ForeignKey("tenants.id", ondelete="CASCADE"), index=True, ) year_code: Mapped[str] = mapped_column(String(9), index=True) # e.g. 2025-26 assessment_year: Mapped[str] = mapped_column(String(9), index=True) # e.g. 2026-27 start_date: Mapped[date] = mapped_column(Date) end_date: Mapped[date] = mapped_column(Date) is_current: Mapped[bool] = mapped_column(Boolean, default=False, index=True) is_locked: Mapped[bool] = mapped_column(Boolean, default=False, index=True) locked_at_utc: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) locked_by_user_id: Mapped[int | None] = mapped_column( ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True, ) created_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow) updated_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow) class YearBackupExport(CommonBase): __tablename__ = "year_backup_exports" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) tenant_id: Mapped[int] = mapped_column( ForeignKey("tenants.id", ondelete="CASCADE"), index=True, ) financial_year_id: Mapped[int] = mapped_column( ForeignKey("financial_years.id", ondelete="CASCADE"), index=True, ) year_code: Mapped[str] = mapped_column(String(9), index=True) assessment_year: Mapped[str | None] = mapped_column(String(9), nullable=True, index=True) export_status: Mapped[str] = mapped_column(String(30), default="completed", index=True) export_file_path: Mapped[str] = mapped_column(String(1000)) file_size_bytes: Mapped[int] = mapped_column(Integer, default=0) manifest_json: Mapped[str | None] = mapped_column(Text, nullable=True) generated_by_user_id: Mapped[int | None] = mapped_column( ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True, ) generated_at_utc: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow)