# models/database/vendor_platform.py """ VendorPlatform junction table for many-to-many relationship between Vendor and Platform. A vendor 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 VendorPlatform(Base, TimestampMixin): """ Junction table linking vendors to platforms. Allows a vendor to: - Subscribe to multiple platforms (OMS + Loyalty) - Have different tiers per platform - Have platform-specific subdomains - Store platform-specific settings Example: - Vendor "WizaMart" is on OMS platform (Professional tier) - Vendor "WizaMart" is also on Loyalty platform (Basic tier) """ __tablename__ = "vendor_platforms" id = Column(Integer, primary_key=True, index=True) # ======================================================================== # Foreign Keys # ======================================================================== vendor_id = Column( Integer, ForeignKey("vendors.id", ondelete="CASCADE"), nullable=False, index=True, comment="Reference to the vendor", ) 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 vendor is active on this platform", ) is_primary = Column( Boolean, default=False, nullable=False, comment="Whether this is the vendor'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 vendor settings", ) # ======================================================================== # Timestamps # ======================================================================== joined_at = Column( DateTime(timezone=True), default=lambda: datetime.now(UTC), nullable=False, comment="When the vendor joined this platform", ) # ======================================================================== # Relationships # ======================================================================== vendor = relationship( "Vendor", back_populates="vendor_platforms", ) platform = relationship( "Platform", back_populates="vendor_platforms", ) tier = relationship( "SubscriptionTier", foreign_keys=[tier_id], ) # ======================================================================== # Constraints & Indexes # ======================================================================== __table_args__ = ( # Each vendor can only be on a platform once UniqueConstraint( "vendor_id", "platform_id", name="uq_vendor_platform", ), # Performance indexes Index( "idx_vendor_platform_active", "vendor_id", "platform_id", "is_active", ), Index( "idx_vendor_platform_primary", "vendor_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"" )