Files
2026-06-20 15:01:44 +05:30

127 lines
5.8 KiB
Python

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)