Files
orion/app/modules/tenancy/services/platform_service.py
Samir Boulahtit f20266167d
Some checks failed
CI / ruff (push) Failing after 7s
CI / pytest (push) Failing after 1s
CI / architecture (push) Failing after 9s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 8s
CI / docs (push) Has been skipped
fix(lint): auto-fix ruff violations and tune lint rules
- Auto-fixed 4,496 lint issues (import sorting, modern syntax, etc.)
- Added ignore rules for patterns intentional in this codebase:
  E402 (late imports), E712 (SQLAlchemy filters), B904 (raise from),
  SIM108/SIM105/SIM117 (readability preferences)
- Added per-file ignores for tests and scripts
- Excluded broken scripts/rename_terminology.py (has curly quotes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:10:42 +01:00

310 lines
8.0 KiB
Python

# app/modules/tenancy/services/platform_service.py
"""
Platform Service
Business logic for platform management in the Multi-Platform CMS.
Platforms represent different business offerings (OMS, Loyalty, Site Builder, Main Marketing).
Each platform has its own:
- Marketing pages (homepage, pricing, features)
- Store defaults (about, terms, privacy)
- Configuration and branding
"""
import logging
from dataclasses import dataclass
from sqlalchemy import func
from sqlalchemy.orm import Session
from app.modules.cms.models import ContentPage
from app.modules.tenancy.exceptions import (
PlatformNotFoundException,
)
from app.modules.tenancy.models import Platform, StorePlatform
logger = logging.getLogger(__name__)
@dataclass
class PlatformStats:
"""Platform statistics."""
platform_id: int
platform_code: str
platform_name: str
store_count: int
platform_pages_count: int
store_defaults_count: int
store_overrides_count: int = 0
published_pages_count: int = 0
draft_pages_count: int = 0
class PlatformService:
"""Service for platform operations."""
@staticmethod
def get_platform_by_code(db: Session, code: str) -> Platform:
"""
Get platform by code.
Args:
db: Database session
code: Platform code (oms, loyalty, main, etc.)
Returns:
Platform object
Raises:
PlatformNotFoundException: If platform not found
"""
platform = db.query(Platform).filter(Platform.code == code).first()
if not platform:
raise PlatformNotFoundException(code)
return platform
@staticmethod
def get_platform_by_code_optional(db: Session, code: str) -> Platform | None:
"""
Get platform by code, returns None if not found.
Args:
db: Database session
code: Platform code
Returns:
Platform object or None
"""
return db.query(Platform).filter(Platform.code == code).first()
@staticmethod
def get_platform_by_id(db: Session, platform_id: int) -> Platform:
"""
Get platform by ID.
Args:
db: Database session
platform_id: Platform ID
Returns:
Platform object
Raises:
PlatformNotFoundException: If platform not found
"""
platform = db.query(Platform).filter(Platform.id == platform_id).first()
if not platform:
raise PlatformNotFoundException(str(platform_id))
return platform
@staticmethod
def list_platforms(
db: Session, include_inactive: bool = False
) -> list[Platform]:
"""
List all platforms.
Args:
db: Database session
include_inactive: Include inactive platforms
Returns:
List of Platform objects
"""
query = db.query(Platform)
if not include_inactive:
query = query.filter(Platform.is_active == True)
return query.order_by(Platform.id).all()
@staticmethod
def get_store_count(db: Session, platform_id: int) -> int:
"""
Get count of stores on a platform.
Args:
db: Database session
platform_id: Platform ID
Returns:
Store count
"""
return (
db.query(func.count(StorePlatform.store_id))
.filter(StorePlatform.platform_id == platform_id)
.scalar()
or 0
)
@staticmethod
def get_platform_pages_count(db: Session, platform_id: int) -> int:
"""
Get count of platform marketing pages.
Args:
db: Database session
platform_id: Platform ID
Returns:
Platform pages count
"""
return (
db.query(func.count(ContentPage.id))
.filter(
ContentPage.platform_id == platform_id,
ContentPage.store_id is None,
ContentPage.is_platform_page == True,
)
.scalar()
or 0
)
@staticmethod
def get_store_defaults_count(db: Session, platform_id: int) -> int:
"""
Get count of store default pages.
Args:
db: Database session
platform_id: Platform ID
Returns:
Store defaults count
"""
return (
db.query(func.count(ContentPage.id))
.filter(
ContentPage.platform_id == platform_id,
ContentPage.store_id is None,
ContentPage.is_platform_page == False,
)
.scalar()
or 0
)
@staticmethod
def get_store_overrides_count(db: Session, platform_id: int) -> int:
"""
Get count of store override pages.
Args:
db: Database session
platform_id: Platform ID
Returns:
Store overrides count
"""
return (
db.query(func.count(ContentPage.id))
.filter(
ContentPage.platform_id == platform_id,
ContentPage.store_id is not None,
)
.scalar()
or 0
)
@staticmethod
def get_published_pages_count(db: Session, platform_id: int) -> int:
"""
Get count of published pages on a platform.
Args:
db: Database session
platform_id: Platform ID
Returns:
Published pages count
"""
return (
db.query(func.count(ContentPage.id))
.filter(
ContentPage.platform_id == platform_id,
ContentPage.is_published == True,
)
.scalar()
or 0
)
@staticmethod
def get_draft_pages_count(db: Session, platform_id: int) -> int:
"""
Get count of draft pages on a platform.
Args:
db: Database session
platform_id: Platform ID
Returns:
Draft pages count
"""
return (
db.query(func.count(ContentPage.id))
.filter(
ContentPage.platform_id == platform_id,
ContentPage.is_published == False,
)
.scalar()
or 0
)
@classmethod
def get_platform_stats(cls, db: Session, platform: Platform) -> PlatformStats:
"""
Get comprehensive statistics for a platform.
Args:
db: Database session
platform: Platform object
Returns:
PlatformStats dataclass
"""
return PlatformStats(
platform_id=platform.id,
platform_code=platform.code,
platform_name=platform.name,
store_count=cls.get_store_count(db, platform.id),
platform_pages_count=cls.get_platform_pages_count(db, platform.id),
store_defaults_count=cls.get_store_defaults_count(db, platform.id),
store_overrides_count=cls.get_store_overrides_count(db, platform.id),
published_pages_count=cls.get_published_pages_count(db, platform.id),
draft_pages_count=cls.get_draft_pages_count(db, platform.id),
)
@staticmethod
def update_platform(
db: Session, platform: Platform, update_data: dict
) -> Platform:
"""
Update platform fields.
Note: This method does NOT commit the transaction.
The caller (API endpoint) is responsible for committing.
Args:
db: Database session
platform: Platform to update
update_data: Dictionary of fields to update
Returns:
Updated Platform object (with pending changes)
"""
for field, value in update_data.items():
if hasattr(platform, field):
setattr(platform, field, value)
logger.info(f"[PLATFORMS] Updated platform: {platform.code}")
return platform
# Singleton instance for convenience
platform_service = PlatformService()