from __future__ import annotations from datetime import date, datetime from sqlalchemy import Boolean, Date, DateTime, Float, ForeignKey, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.db.common import CommonBase class AccountingTDSRule(CommonBase): __tablename__ = "accounting_tds_rules" __table_args__ = ( UniqueConstraint("tenant_id", "rule_code", "effective_from", name="uq_accounting_tds_rule_version"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), index=True) rule_code: Mapped[str] = mapped_column(String(80), nullable=False) name: Mapped[str] = mapped_column(String(200), nullable=False) statutory_reference: Mapped[str] = mapped_column(String(160), default="Income-tax Act, 2025 - section 393(1)") legacy_section: Mapped[str | None] = mapped_column(String(40), nullable=True) nature_keywords: Mapped[str] = mapped_column(Text, default="") effective_from: Mapped[date] = mapped_column(Date, nullable=False) effective_to: Mapped[date | None] = mapped_column(Date, nullable=True) threshold_mode: Mapped[str] = mapped_column(String(30), default="ANNUAL") single_threshold: Mapped[float] = mapped_column(Float, default=0.0) aggregate_threshold: Mapped[float] = mapped_column(Float, default=0.0) rate_individual_huf: Mapped[float] = mapped_column(Float, default=0.0) rate_other: Mapped[float] = mapped_column(Float, default=0.0) no_pan_rate: Mapped[float] = mapped_column(Float, default=20.0) deduct_on_excess_only: Mapped[bool] = mapped_column(Boolean, default=False) applies_to_purchases: Mapped[bool] = mapped_column(Boolean, default=False) applies_to_expenses: Mapped[bool] = mapped_column(Boolean, default=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True) is_system_default: Mapped[bool] = mapped_column(Boolean, default=True) updated_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True) created_at_utc: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at_utc: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) class AccountingTDSPostingInstruction(CommonBase): __tablename__ = "accounting_tds_posting_instructions" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id", ondelete="CASCADE"), index=True) client_id: Mapped[int] = mapped_column(ForeignKey("clients.id", ondelete="CASCADE"), index=True) rule_id: Mapped[int | None] = mapped_column(ForeignKey("accounting_tds_rules.id", ondelete="SET NULL"), nullable=True) company_guid: Mapped[str | None] = mapped_column(String(255), nullable=True) company_name: Mapped[str | None] = mapped_column(String(255), nullable=True) source_voucher_number: Mapped[str | None] = mapped_column(String(120), nullable=True) source_voucher_date: Mapped[date | None] = mapped_column(Date, nullable=True) party_ledger: Mapped[str] = mapped_column(String(255), nullable=False) tds_ledger: Mapped[str] = mapped_column(String(255), nullable=False, default="TDS Payable") taxable_base: Mapped[float] = mapped_column(Float, default=0.0) expected_tds: Mapped[float] = mapped_column(Float, default=0.0) actual_tds: Mapped[float] = mapped_column(Float, default=0.0) liability_amount: Mapped[float] = mapped_column(Float, default=0.0) statutory_reference: Mapped[str | None] = mapped_column(String(160), nullable=True) narration: Mapped[str | None] = mapped_column(Text, nullable=True) erp_reference: Mapped[str | None] = mapped_column(String(80), nullable=True, unique=True) status: Mapped[str] = mapped_column(String(30), default="prepared", index=True) tally_voucher_id: Mapped[str | None] = mapped_column(String(120), nullable=True) prepared_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True) approved_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True) posted_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True) prepared_at_utc: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) approved_at_utc: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) posted_at_utc: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)