# app/modules/tenancy/services/tenancy_widgets.py """ Tenancy dashboard widget provider. Provides widgets for tenancy-related data on admin dashboards. Implements the DashboardWidgetProviderProtocol. Widgets provided: - recent_stores: List of recently created stores with status """ import logging from sqlalchemy.orm import Session from app.modules.contracts.widgets import ( DashboardWidget, ListWidget, WidgetContext, WidgetListItem, ) logger = logging.getLogger(__name__) class TenancyWidgetProvider: """ Widget provider for tenancy module. Provides dashboard widgets for stores, users, and other tenancy data. """ @property def widgets_category(self) -> str: return "tenancy" def _get_store_status(self, store) -> str: """Determine widget status indicator for a store.""" if not store.is_active: return "neutral" if not store.is_verified: return "warning" return "success" def get_store_widgets( self, db: Session, store_id: int, context: WidgetContext | None = None, ) -> list[DashboardWidget]: """ Get tenancy widgets for a store dashboard. Tenancy module doesn't provide store-scoped widgets (stores don't see other stores). Args: db: Database session store_id: ID of the store context: Optional filtering/scoping context Returns: Empty list (no store-scoped tenancy widgets) """ # Tenancy widgets are platform/admin-only return [] def get_platform_widgets( self, db: Session, platform_id: int, context: WidgetContext | None = None, ) -> list[DashboardWidget]: """ Get tenancy widgets for the admin/platform dashboard. Args: db: Database session platform_id: ID of the platform context: Optional filtering/scoping context Returns: List of DashboardWidget objects for the platform """ from sqlalchemy.orm import joinedload from app.modules.tenancy.models import Store, StorePlatform limit = context.limit if context else 5 # Get store IDs for this platform store_ids_subquery = ( db.query(StorePlatform.store_id) .filter(StorePlatform.platform_id == platform_id) .subquery() ) # Get recent stores for this platform stores = ( db.query(Store) .options(joinedload(Store.merchant)) .filter(Store.id.in_(store_ids_subquery)) .order_by(Store.created_at.desc()) .limit(limit) .all() ) items = [ WidgetListItem( id=store.id, title=store.name, subtitle=store.store_code, status=self._get_store_status(store), timestamp=store.created_at, url=f"/admin/stores/{store.id}", metadata={ "store_code": store.store_code, "subdomain": store.subdomain, "is_active": store.is_active, "is_verified": store.is_verified, "merchant_name": store.merchant.name if store.merchant else None, }, ) for store in stores ] # Get total store count for platform total_count = ( db.query(Store) .filter(Store.id.in_(store_ids_subquery)) .count() ) return [ DashboardWidget( key="tenancy.recent_stores", widget_type="list", title="Recent Stores", category="tenancy", data=ListWidget( items=items, total_count=total_count, view_all_url="/admin/stores", ), icon="shopping-bag", description="Recently created store accounts", order=10, ) ] # Singleton instance tenancy_widget_provider = TenancyWidgetProvider() __all__ = ["TenancyWidgetProvider", "tenancy_widget_provider"]