Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs. Co-authored-by: Cursor <cursoragent@cursor.com>
172 lines
8.9 KiB
Python
172 lines
8.9 KiB
Python
"""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"),)
|