"""Pricing, capabilities & bundles — Phase 10.4.""" from __future__ import annotations import uuid from decimal import Decimal from sqlalchemy import Index, Numeric, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.types import JSON from app.core.database import Base from app.models.base import ( ActorAuditMixin, OptimisticLockMixin, SoftDeleteMixin, TenantMixin, TimestampMixin, UUIDPrimaryKeyMixin, ) from app.models.types import ( CapabilityBundleStatus, CapabilityStatus, GUID, PricingRuleStatus, ) class PricingRule( Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, SoftDeleteMixin, ActorAuditMixin, OptimisticLockMixin, ): __tablename__ = "pricing_rules" organization_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) status: Mapped[PricingRuleStatus] = mapped_column( default=PricingRuleStatus.DRAFT, nullable=False ) base_amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), nullable=False) currency_code: Mapped[str] = mapped_column(String(3), nullable=False, default="IRR") rule_config: Mapped[dict | None] = mapped_column(JSON, nullable=True) metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) __table_args__ = ( UniqueConstraint("tenant_id", "code", name="uq_pricing_rules_tenant_code"), Index("ix_pricing_rules_tenant_status", "tenant_id", "status"), Index("ix_pricing_rules_tenant_deleted", "tenant_id", "is_deleted"), ) class CapabilityDefinition( Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, SoftDeleteMixin, ActorAuditMixin, OptimisticLockMixin, ): __tablename__ = "capability_definitions" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[str | None] = mapped_column(Text, nullable=True) status: Mapped[CapabilityStatus] = mapped_column( default=CapabilityStatus.ACTIVE, nullable=False ) metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) __table_args__ = ( UniqueConstraint( "tenant_id", "code", name="uq_capability_definitions_tenant_code" ), Index("ix_capability_definitions_tenant_deleted", "tenant_id", "is_deleted"), ) class CapabilityBundle( Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, SoftDeleteMixin, ActorAuditMixin, OptimisticLockMixin, ): __tablename__ = "capability_bundles" code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) status: Mapped[CapabilityBundleStatus] = mapped_column( default=CapabilityBundleStatus.DRAFT, nullable=False ) capability_codes: Mapped[list | None] = mapped_column(JSON, nullable=True) pricing_rule_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) __table_args__ = ( UniqueConstraint("tenant_id", "code", name="uq_capability_bundles_tenant_code"), Index("ix_capability_bundles_tenant_status", "tenant_id", "status"), Index("ix_capability_bundles_tenant_deleted", "tenant_id", "is_deleted"), )