from __future__ import annotations from sqlalchemy import String, Boolean, Integer, ForeignKey, UniqueConstraint, Text, Float, Time from sqlalchemy.orm import Mapped, mapped_column from app.core.db.common import CommonBase class BranchSettings(CommonBase): __tablename__ = "branch_settings" __table_args__ = ( UniqueConstraint("branch_id", name="uq_branch_settings_branch"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) branch_id: Mapped[int] = mapped_column( ForeignKey("branches.id", ondelete="CASCADE"), index=True, ) # Identity address_line1: Mapped[str | None] = mapped_column(String(255), nullable=True) address_line2: Mapped[str | None] = mapped_column(String(255), nullable=True) city: Mapped[str | None] = mapped_column(String(100), nullable=True) state: Mapped[str | None] = mapped_column(String(100), nullable=True) pin_code: Mapped[str | None] = mapped_column(String(10), nullable=True) gstin: Mapped[str | None] = mapped_column(String(20), nullable=True) pan: Mapped[str | None] = mapped_column(String(10), nullable=True) letterhead_logo_path: Mapped[str | None] = mapped_column(String(500), nullable=True) letterhead_signature_path: Mapped[str | None] = mapped_column(String(500), nullable=True) letterhead_stamp_path: Mapped[str | None] = mapped_column(String(500), nullable=True) # Geolocation and attendance controls geo_address: Mapped[str | None] = mapped_column(String(500), nullable=True) latitude: Mapped[float | None] = mapped_column(Float, nullable=True) longitude: Mapped[float | None] = mapped_column(Float, nullable=True) attendance_geo_enabled: Mapped[bool] = mapped_column(Boolean, default=False) attendance_geo_radius_meters: Mapped[int] = mapped_column(Integer, default=100) attendance_ip_enabled: Mapped[bool] = mapped_column(Boolean, default=False) attendance_allowed_ip_csv: Mapped[str | None] = mapped_column(Text, nullable=True) # Working calendar and attendance timing rules working_days_csv: Mapped[str] = mapped_column(String(50), default="MON,TUE,WED,THU,FRI,SAT") holidays_json: Mapped[str] = mapped_column(Text, default="[]") timezone_locked: Mapped[bool] = mapped_column(Boolean, default=False) attendance_grace_minutes: Mapped[int] = mapped_column(Integer, default=10) attendance_half_day_after_time = mapped_column(Time, nullable=True) attendance_rule_enabled: Mapped[bool] = mapped_column(Boolean, default=True) # Email policy email_from_name: Mapped[str | None] = mapped_column(String(200), nullable=True) email_from_email: Mapped[str | None] = mapped_column(String(255), nullable=True) email_reply_to: Mapped[str | None] = mapped_column(String(255), nullable=True) default_cc_csv: Mapped[str | None] = mapped_column(String(500), nullable=True) default_bcc_csv: Mapped[str | None] = mapped_column(String(500), nullable=True) email_signature_html: Mapped[str | None] = mapped_column(Text, nullable=True) # Phase 7Q.2 - branding / billing presentation defaults invoice_footer_text: Mapped[str | None] = mapped_column(Text, nullable=True) bank_name: Mapped[str | None] = mapped_column(String(200), nullable=True) bank_account_name: Mapped[str | None] = mapped_column(String(200), nullable=True) bank_account_number: Mapped[str | None] = mapped_column(String(50), nullable=True) bank_ifsc: Mapped[str | None] = mapped_column(String(20), nullable=True) upi_id: Mapped[str | None] = mapped_column(String(100), nullable=True) # Storage policy storage_mode: Mapped[str] = mapped_column(String(20), default="local_only") folder_template: Mapped[str] = mapped_column( String(500), default="{root}/Clients/{client_code}/{fy}/{service}/", ) max_file_mb: Mapped[int] = mapped_column(Integer, default=25) allowed_ext_csv: Mapped[str] = mapped_column( String(500), default="pdf,jpg,jpeg,png,xlsx,xls,docx,zip", ) retention_years: Mapped[int] = mapped_column(Integer, default=8) # Security policy otp_required_roles_csv: Mapped[str] = mapped_column( String(200), default="Partner,System Admin", ) session_duration_minutes: Mapped[int] = mapped_column(Integer, default=480) lockout_attempts: Mapped[int] = mapped_column(Integer, default=5) lockout_minutes: Mapped[int] = mapped_column(Integer, default=15)