refactor(arch): eliminate all cross-module model imports in service layer
Some checks failed
CI / ruff (push) Successful in 9s
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / pytest (push) Has been cancelled

Enforce MOD-025/MOD-026 rules: zero top-level cross-module model imports
remain in any service file. All 66 files migrated using deferred import
patterns (method-body, _get_model() helpers, instance-cached self._Model)
and new cross-module service methods in tenancy. Documentation updated
with Pattern 6 (deferred imports), migration plan marked complete, and
violations status reflects 84→0 service-layer violations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-27 06:13:15 +01:00
parent e3a52f6536
commit 86e85a98b8
66 changed files with 2242 additions and 1295 deletions

View File

@@ -157,28 +157,35 @@ class CmsFeatureProvider:
platform_id: int,
) -> list[FeatureUsage]:
from app.modules.cms.models.content_page import ContentPage
from app.modules.tenancy.models import Store, StorePlatform
from app.modules.tenancy.services.platform_service import platform_service
from app.modules.tenancy.services.store_service import store_service
# Get store IDs for this merchant that are on the given platform
merchant_stores = store_service.get_stores_by_merchant_id(db, merchant_id)
store_ids = []
for s in merchant_stores:
pids = platform_service.get_active_platform_ids_for_store(db, s.id)
if platform_id in pids:
store_ids.append(s.id)
if not store_ids:
return [
FeatureUsage(feature_code="cms_pages_limit", current_count=0, label="Content pages"),
FeatureUsage(feature_code="cms_custom_pages_limit", current_count=0, label="Custom pages"),
]
# Aggregate content pages across all merchant's stores on this platform
pages_count = (
db.query(func.count(ContentPage.id))
.join(Store, ContentPage.store_id == Store.id)
.join(StorePlatform, Store.id == StorePlatform.store_id)
.filter(
Store.merchant_id == merchant_id,
StorePlatform.platform_id == platform_id,
)
.filter(ContentPage.store_id.in_(store_ids))
.scalar()
or 0
)
custom_count = (
db.query(func.count(ContentPage.id))
.join(Store, ContentPage.store_id == Store.id)
.join(StorePlatform, Store.id == StorePlatform.store_id)
.filter(
Store.merchant_id == merchant_id,
StorePlatform.platform_id == platform_id,
ContentPage.store_id.in_(store_ids),
ContentPage.is_custom == True, # noqa: E712
)
.scalar()

View File

@@ -147,18 +147,11 @@ class CMSMetricsProvider:
Aggregates content management data across all stores.
"""
from app.modules.cms.models import ContentPage, MediaFile, StoreTheme
from app.modules.tenancy.models import StorePlatform
from app.modules.tenancy.services.platform_service import platform_service
try:
# Get all store IDs for this platform using StorePlatform junction table
store_ids = (
db.query(StorePlatform.store_id)
.filter(
StorePlatform.platform_id == platform_id,
StorePlatform.is_active == True,
)
.subquery()
)
# Get all store IDs for this platform via platform service
store_ids = platform_service.get_store_ids_for_platform(db, platform_id)
# Content pages
total_pages = (

View File

@@ -60,22 +60,9 @@ class ContentPageService:
Returns:
Platform ID or None if no platform association found
"""
from app.modules.tenancy.models import StorePlatform
from app.modules.tenancy.services.platform_service import platform_service
primary_sp = (
db.query(StorePlatform)
.filter(StorePlatform.store_id == store_id, StorePlatform.is_primary.is_(True))
.first()
)
if primary_sp:
return primary_sp.platform_id
# Fallback: any active store_platform
any_sp = (
db.query(StorePlatform)
.filter(StorePlatform.store_id == store_id, StorePlatform.is_active.is_(True))
.first()
)
return any_sp.platform_id if any_sp else None
return platform_service.get_primary_platform_id_for_store(db, store_id)
@staticmethod
def resolve_platform_id_or_raise(db: Session, store_id: int) -> int:

View File

@@ -6,6 +6,8 @@ Business logic for store theme management.
Handles theme CRUD operations, preset application, and validation.
"""
from __future__ import annotations
import logging
import re
@@ -29,7 +31,6 @@ from app.modules.cms.services.theme_presets import (
get_preset_preview,
)
from app.modules.tenancy.exceptions import StoreNotFoundException
from app.modules.tenancy.models import Store
logger = logging.getLogger(__name__)
@@ -67,9 +68,9 @@ class StoreThemeService:
Raises:
StoreNotFoundException: If store not found
"""
store = (
db.query(Store).filter(Store.store_code == store_code.upper()).first()
)
from app.modules.tenancy.services.store_service import store_service
store = store_service.get_store_by_code(db, store_code)
if not store:
self.logger.warning(f"Store not found: {store_code}")