# app/modules/tenancy/models/store_platform.py """ StorePlatform junction table for many-to-many relationship between Store and Platform. A store CAN belong to multiple platforms (e.g., both OMS and Loyalty Program). Each membership can have: - Platform-specific subscription tier - Custom subdomain for that platform - Platform-specific settings - Active/inactive status """ from datetime import UTC, datetime from sqlalchemy import ( JSON, Boolean, Column, DateTime, ForeignKey, Index, Integer, String, UniqueConstraint, ) from sqlalchemy.orm import relationship from app.core.database import Base from models.database.base import TimestampMixin class StorePlatform(Base, TimestampMixin): """ Junction table linking stores to platforms. Allows a store to: - Subscribe to multiple platforms (OMS + Loyalty) - Have different tiers per platform - Have platform-specific subdomains - Store platform-specific settings Example: - Store "Orion" is on OMS platform (Professional tier) - Store "Orion" is also on Loyalty platform (Basic tier) """ __tablename__ = "store_platforms" id = Column(Integer, primary_key=True, index=True) # ======================================================================== # Foreign Keys # ======================================================================== store_id = Column( Integer, ForeignKey("stores.id", ondelete="CASCADE"), nullable=False, index=True, comment="Reference to the store", ) platform_id = Column( Integer, ForeignKey("platforms.id", ondelete="CASCADE"), nullable=False, index=True, comment="Reference to the platform", ) tier_id = Column( Integer, ForeignKey("subscription_tiers.id", ondelete="SET NULL"), nullable=True, index=True, comment="Platform-specific subscription tier", ) # ======================================================================== # Membership Status # ======================================================================== is_active = Column( Boolean, default=True, nullable=False, comment="Whether the store is active on this platform", ) is_primary = Column( Boolean, default=False, nullable=False, comment="Whether this is the store's primary platform", ) # ======================================================================== # Platform-Specific Configuration # ======================================================================== custom_subdomain = Column( String(100), nullable=True, comment="Platform-specific subdomain (if different from main subdomain)", ) settings = Column( JSON, nullable=True, default=dict, comment="Platform-specific store settings", ) # ======================================================================== # Timestamps # ======================================================================== joined_at = Column( DateTime(timezone=True), default=lambda: datetime.now(UTC), nullable=False, comment="When the store joined this platform", ) # ======================================================================== # Relationships # ======================================================================== store = relationship( "Store", back_populates="store_platforms", ) platform = relationship( "Platform", back_populates="store_platforms", ) tier = relationship( "SubscriptionTier", foreign_keys=[tier_id], ) # ======================================================================== # Constraints & Indexes # ======================================================================== __table_args__ = ( # Each store can only be on a platform once UniqueConstraint( "store_id", "platform_id", name="uq_store_platform", ), # Performance indexes Index( "idx_store_platform_active", "store_id", "platform_id", "is_active", ), Index( "idx_store_platform_primary", "store_id", "is_primary", ), ) # ======================================================================== # Properties # ======================================================================== @property def tier_code(self) -> str | None: """Get the tier code for this platform membership.""" return self.tier.code if self.tier else None @property def tier_name(self) -> str | None: """Get the tier name for this platform membership.""" return self.tier.name if self.tier else None def __repr__(self) -> str: return ( f"" ) __all__ = ["StorePlatform"]