"""Phase 5.8 — Fixed Assets domain models.""" from __future__ import annotations import uuid from datetime import date from decimal import Decimal from sqlalchemy import Boolean, Date, 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 AssetStatus, DepreciationMethod, GUID class AssetCategory(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_categories" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) default_useful_life_months: Mapped[int] = mapped_column(Integer, default=60, nullable=False) default_depreciation_method: Mapped[DepreciationMethod] = mapped_column( default=DepreciationMethod.STRAIGHT_LINE, nullable=False ) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_asset_category_tenant_code"),) class AssetGroup(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_groups" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_asset_group_tenant_code"),) class Asset(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "assets" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) group_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) serial_number: Mapped[str | None] = mapped_column(String(100), nullable=True) location: Mapped[str | None] = mapped_column(String(255), nullable=True) department_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) cost_center_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) project_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) acquisition_date: Mapped[date | None] = mapped_column(Date, nullable=True) acquisition_cost: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False) current_book_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False) residual_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False) useful_life_months: Mapped[int] = mapped_column(Integer, default=60, nullable=False) depreciation_method: Mapped[DepreciationMethod] = mapped_column( default=DepreciationMethod.STRAIGHT_LINE, nullable=False ) status: Mapped[AssetStatus] = mapped_column(default=AssetStatus.DRAFT, nullable=False) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) __table_args__ = ( UniqueConstraint("tenant_id", "code", name="uq_asset_tenant_code"), Index("ix_assets_tenant_status", "tenant_id", "status"), ) class AssetDepreciation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_depreciations" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) fiscal_period_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) depreciation_date: Mapped[date] = mapped_column(Date, nullable=False) amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) accumulated_depreciation: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) book_value_after: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) __table_args__ = (Index("ix_asset_depreciation_asset", "tenant_id", "asset_id"),) class DepreciationSchedule(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "depreciation_schedules" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) period_number: Mapped[int] = mapped_column(Integer, nullable=False) schedule_date: Mapped[date] = mapped_column(Date, nullable=False) amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) is_posted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) class AssetTransfer(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_transfers" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) transfer_date: Mapped[date] = mapped_column(Date, nullable=False) from_location: Mapped[str | None] = mapped_column(String(255), nullable=True) to_location: Mapped[str | None] = mapped_column(String(255), nullable=True) from_department_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) to_department_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) class AssetDisposal(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_disposals" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) disposal_date: Mapped[date] = mapped_column(Date, nullable=False) disposal_type: Mapped[str] = mapped_column(String(50), nullable=False) sale_amount: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) gain_loss: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) class AssetRevaluation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_revaluations" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) revaluation_date: Mapped[date] = mapped_column(Date, nullable=False) old_book_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) new_book_value: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) difference: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) class AssetImpairment(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_impairments" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) impairment_date: Mapped[date] = mapped_column(Date, nullable=False) impairment_amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) reason: Mapped[str | None] = mapped_column(Text, nullable=True) voucher_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) class AssetAccountingProfile(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_accounting_profiles" name: Mapped[str] = mapped_column(String(255), nullable=False) category_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) asset_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) depreciation_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) accumulated_depreciation_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) disposal_gain_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) disposal_loss_account_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) class AssetHistory(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_history" asset_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) event_type: Mapped[str] = mapped_column(String(50), nullable=False) event_date: Mapped[date] = mapped_column(Date, nullable=False) description: Mapped[str | None] = mapped_column(Text, nullable=True) before_value: Mapped[str | None] = mapped_column(Text, nullable=True) after_value: Mapped[str | None] = mapped_column(Text, nullable=True) __table_args__ = (Index("ix_asset_history_asset", "tenant_id", "asset_id"),) class AssetLocation(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin): __tablename__ = "asset_locations" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) __table_args__ = (UniqueConstraint("tenant_id", "code", name="uq_asset_location_tenant_code"),)