refactor: remove all backward compatibility code across 70 files
Some checks failed
Some checks failed
Clean up 28 backward compatibility instances identified in the codebase. The app is not live, so all shims are replaced with the target architecture: - Remove legacy Inventory.location column (use bin_location exclusively) - Remove dashboard _extract_metric_value helper (use flat metrics dict) - Remove legacy stat field duplicates (total_stores, total_imports, etc.) - Remove 13 re-export shims and class aliases across modules - Remove module-enabling JSON fallback (use PlatformModule junction table) - Remove menu_to_legacy_format() conversion (return dataclasses directly) - Remove title/description from MarketplaceProductBase schema - Clean billing convenience method docstrings - Clean test fixtures and backward-compat comments - Add PlatformModule seeding to init_production.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,9 +7,6 @@ enabled modules. Each module provides its own metrics via the MetricsProvider pr
|
||||
|
||||
Dashboard widgets are collected via the WidgetAggregator service, which discovers
|
||||
DashboardWidgetProvider implementations from all enabled modules.
|
||||
|
||||
For backward compatibility, this also falls back to the analytics stats_service
|
||||
for comprehensive statistics that haven't been migrated to the provider pattern yet.
|
||||
"""
|
||||
|
||||
import logging
|
||||
@@ -20,7 +17,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_admin_api
|
||||
from app.core.database import get_db
|
||||
from app.modules.contracts.widgets import BreakdownWidget, ListWidget
|
||||
from app.modules.contracts.widgets import BreakdownWidget, ListWidget, WidgetListItem
|
||||
from app.modules.core.schemas.dashboard import (
|
||||
AdminDashboardResponse,
|
||||
ImportStatsResponse,
|
||||
@@ -70,19 +67,7 @@ def _get_platform_id(request: Request, current_admin: UserContext) -> int:
|
||||
return 1
|
||||
|
||||
|
||||
def _extract_metric_value(
|
||||
metrics: dict[str, list], category: str, key: str, default: int | float = 0
|
||||
) -> int | float:
|
||||
"""Extract a specific metric value from categorized metrics."""
|
||||
if category not in metrics:
|
||||
return default
|
||||
for metric in metrics[category]:
|
||||
if metric.key == key:
|
||||
return metric.value
|
||||
return default
|
||||
|
||||
|
||||
def _widget_list_item_to_dict(item) -> dict[str, Any]:
|
||||
def _widget_list_item_to_dict(item: WidgetListItem) -> dict[str, Any]:
|
||||
"""Convert a WidgetListItem to a dictionary for API response."""
|
||||
return {
|
||||
"id": item.id,
|
||||
@@ -95,15 +80,14 @@ def _widget_list_item_to_dict(item) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _extract_widget_items(
|
||||
widgets: dict[str, list], category: str, key: str
|
||||
def _get_list_widget_items(
|
||||
widgets: dict[str, list], key: str
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Extract items from a list widget for backward compatibility."""
|
||||
if category not in widgets:
|
||||
return []
|
||||
for widget in widgets[category]:
|
||||
if widget.key == key and isinstance(widget.data, ListWidget):
|
||||
return [_widget_list_item_to_dict(item) for item in widget.data.items]
|
||||
"""Extract items from a list widget by key, searching all categories."""
|
||||
for category_widgets in widgets.values():
|
||||
for widget in category_widgets:
|
||||
if widget.key == key and isinstance(widget.data, ListWidget):
|
||||
return [_widget_list_item_to_dict(item) for item in widget.data.items]
|
||||
return []
|
||||
|
||||
|
||||
@@ -116,59 +100,32 @@ def get_admin_dashboard(
|
||||
"""Get admin dashboard with platform statistics (Admin only)."""
|
||||
platform_id = _get_platform_id(request, current_admin)
|
||||
|
||||
# Get aggregated metrics from all enabled modules
|
||||
metrics = stats_aggregator.get_admin_dashboard_stats(db=db, platform_id=platform_id)
|
||||
# Get flat metrics from all enabled modules
|
||||
metrics = stats_aggregator.get_admin_stats_flat(db=db, platform_id=platform_id)
|
||||
|
||||
# Get aggregated widgets from all enabled modules
|
||||
widgets = widget_aggregator.get_admin_dashboard_widgets(db=db, platform_id=platform_id)
|
||||
|
||||
# Extract user stats from tenancy module
|
||||
total_users = _extract_metric_value(metrics, "tenancy", "tenancy.total_users", 0)
|
||||
active_users = _extract_metric_value(metrics, "tenancy", "tenancy.active_users", 0)
|
||||
inactive_users = _extract_metric_value(metrics, "tenancy", "tenancy.inactive_users", 0)
|
||||
admin_users = _extract_metric_value(metrics, "tenancy", "tenancy.admin_users", 0)
|
||||
activation_rate = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.user_activation_rate", 0
|
||||
)
|
||||
|
||||
# Extract store stats from tenancy module
|
||||
total_stores = _extract_metric_value(metrics, "tenancy", "tenancy.total_stores", 0)
|
||||
verified_stores = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.verified_stores", 0
|
||||
)
|
||||
pending_stores = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.pending_stores", 0
|
||||
)
|
||||
inactive_stores = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.inactive_stores", 0
|
||||
)
|
||||
|
||||
# Extract recent_stores from tenancy widget (backward compatibility)
|
||||
recent_stores = _extract_widget_items(widgets, "tenancy", "tenancy.recent_stores")
|
||||
|
||||
# Extract recent_imports from marketplace widget (backward compatibility)
|
||||
recent_imports = _extract_widget_items(widgets, "marketplace", "marketplace.recent_imports")
|
||||
|
||||
return AdminDashboardResponse(
|
||||
platform={
|
||||
"name": "Multi-Tenant Ecommerce Platform",
|
||||
"version": "1.0.0",
|
||||
},
|
||||
users=UserStatsResponse(
|
||||
total_users=int(total_users),
|
||||
active_users=int(active_users),
|
||||
inactive_users=int(inactive_users),
|
||||
admin_users=int(admin_users),
|
||||
activation_rate=float(activation_rate),
|
||||
total_users=int(metrics.get("tenancy.total_users", 0)),
|
||||
active_users=int(metrics.get("tenancy.active_users", 0)),
|
||||
inactive_users=int(metrics.get("tenancy.inactive_users", 0)),
|
||||
admin_users=int(metrics.get("tenancy.admin_users", 0)),
|
||||
activation_rate=float(metrics.get("tenancy.user_activation_rate", 0)),
|
||||
),
|
||||
stores=StoreStatsResponse(
|
||||
total=int(total_stores),
|
||||
verified=int(verified_stores),
|
||||
pending=int(pending_stores),
|
||||
inactive=int(inactive_stores),
|
||||
total=int(metrics.get("tenancy.total_stores", 0)),
|
||||
verified=int(metrics.get("tenancy.verified_stores", 0)),
|
||||
pending=int(metrics.get("tenancy.pending_stores", 0)),
|
||||
inactive=int(metrics.get("tenancy.inactive_stores", 0)),
|
||||
),
|
||||
recent_stores=recent_stores,
|
||||
recent_imports=recent_imports,
|
||||
recent_stores=_get_list_widget_items(widgets, "tenancy.recent_stores"),
|
||||
recent_imports=_get_list_widget_items(widgets, "marketplace.recent_imports"),
|
||||
)
|
||||
|
||||
|
||||
@@ -181,37 +138,17 @@ def get_comprehensive_stats(
|
||||
"""Get comprehensive platform statistics (Admin only)."""
|
||||
platform_id = _get_platform_id(request, current_admin)
|
||||
|
||||
# Get aggregated metrics
|
||||
metrics = stats_aggregator.get_admin_dashboard_stats(db=db, platform_id=platform_id)
|
||||
|
||||
# Extract product stats from catalog module
|
||||
total_products = _extract_metric_value(metrics, "catalog", "catalog.total_products", 0)
|
||||
|
||||
# Extract marketplace stats
|
||||
unique_marketplaces = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.unique_marketplaces", 0
|
||||
)
|
||||
unique_brands = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.unique_brands", 0
|
||||
)
|
||||
|
||||
# Extract store stats
|
||||
unique_stores = _extract_metric_value(metrics, "tenancy", "tenancy.total_stores", 0)
|
||||
|
||||
# Extract inventory stats
|
||||
inventory_entries = _extract_metric_value(metrics, "inventory", "inventory.entries", 0)
|
||||
inventory_quantity = _extract_metric_value(
|
||||
metrics, "inventory", "inventory.total_quantity", 0
|
||||
)
|
||||
# Get flat metrics from all enabled modules
|
||||
metrics = stats_aggregator.get_admin_stats_flat(db=db, platform_id=platform_id)
|
||||
|
||||
return StatsResponse(
|
||||
total_products=int(total_products),
|
||||
unique_brands=int(unique_brands),
|
||||
total_products=int(metrics.get("catalog.total_products", 0)),
|
||||
unique_brands=int(metrics.get("marketplace.unique_brands", 0)),
|
||||
unique_categories=0, # TODO: Add category tracking
|
||||
unique_marketplaces=int(unique_marketplaces),
|
||||
unique_stores=int(unique_stores),
|
||||
total_inventory_entries=int(inventory_entries),
|
||||
total_inventory_quantity=int(inventory_quantity),
|
||||
unique_marketplaces=int(metrics.get("marketplace.unique_marketplaces", 0)),
|
||||
unique_stores=int(metrics.get("tenancy.total_stores", 0)),
|
||||
total_inventory_entries=int(metrics.get("inventory.entries", 0)),
|
||||
total_inventory_quantity=int(metrics.get("inventory.total_quantity", 0)),
|
||||
)
|
||||
|
||||
|
||||
@@ -261,89 +198,39 @@ def get_platform_statistics(
|
||||
"""Get comprehensive platform statistics (Admin only)."""
|
||||
platform_id = _get_platform_id(request, current_admin)
|
||||
|
||||
# Get aggregated metrics from all enabled modules
|
||||
metrics = stats_aggregator.get_admin_dashboard_stats(db=db, platform_id=platform_id)
|
||||
|
||||
# User stats from tenancy
|
||||
total_users = _extract_metric_value(metrics, "tenancy", "tenancy.total_users", 0)
|
||||
active_users = _extract_metric_value(metrics, "tenancy", "tenancy.active_users", 0)
|
||||
inactive_users = _extract_metric_value(metrics, "tenancy", "tenancy.inactive_users", 0)
|
||||
admin_users = _extract_metric_value(metrics, "tenancy", "tenancy.admin_users", 0)
|
||||
activation_rate = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.user_activation_rate", 0
|
||||
)
|
||||
|
||||
# Store stats from tenancy
|
||||
total_stores = _extract_metric_value(metrics, "tenancy", "tenancy.total_stores", 0)
|
||||
verified_stores = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.verified_stores", 0
|
||||
)
|
||||
pending_stores = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.pending_stores", 0
|
||||
)
|
||||
inactive_stores = _extract_metric_value(
|
||||
metrics, "tenancy", "tenancy.inactive_stores", 0
|
||||
)
|
||||
|
||||
# Product stats from catalog
|
||||
total_products = _extract_metric_value(metrics, "catalog", "catalog.total_products", 0)
|
||||
active_products = _extract_metric_value(
|
||||
metrics, "catalog", "catalog.active_products", 0
|
||||
)
|
||||
|
||||
# Order stats from orders
|
||||
total_orders = _extract_metric_value(metrics, "orders", "orders.total", 0)
|
||||
|
||||
# Import stats from marketplace
|
||||
total_imports = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.total_imports", 0
|
||||
)
|
||||
pending_imports = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.pending_imports", 0
|
||||
)
|
||||
processing_imports = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.processing_imports", 0
|
||||
)
|
||||
completed_imports = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.successful_imports", 0
|
||||
)
|
||||
failed_imports = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.failed_imports", 0
|
||||
)
|
||||
import_success_rate = _extract_metric_value(
|
||||
metrics, "marketplace", "marketplace.success_rate", 0
|
||||
)
|
||||
# Get flat metrics from all enabled modules
|
||||
metrics = stats_aggregator.get_admin_stats_flat(db=db, platform_id=platform_id)
|
||||
|
||||
return PlatformStatsResponse(
|
||||
users=UserStatsResponse(
|
||||
total_users=int(total_users),
|
||||
active_users=int(active_users),
|
||||
inactive_users=int(inactive_users),
|
||||
admin_users=int(admin_users),
|
||||
activation_rate=float(activation_rate),
|
||||
total_users=int(metrics.get("tenancy.total_users", 0)),
|
||||
active_users=int(metrics.get("tenancy.active_users", 0)),
|
||||
inactive_users=int(metrics.get("tenancy.inactive_users", 0)),
|
||||
admin_users=int(metrics.get("tenancy.admin_users", 0)),
|
||||
activation_rate=float(metrics.get("tenancy.user_activation_rate", 0)),
|
||||
),
|
||||
stores=StoreStatsResponse(
|
||||
total=int(total_stores),
|
||||
verified=int(verified_stores),
|
||||
pending=int(pending_stores),
|
||||
inactive=int(inactive_stores),
|
||||
total=int(metrics.get("tenancy.total_stores", 0)),
|
||||
verified=int(metrics.get("tenancy.verified_stores", 0)),
|
||||
pending=int(metrics.get("tenancy.pending_stores", 0)),
|
||||
inactive=int(metrics.get("tenancy.inactive_stores", 0)),
|
||||
),
|
||||
products=ProductStatsResponse(
|
||||
total_products=int(total_products),
|
||||
active_products=int(active_products),
|
||||
total_products=int(metrics.get("catalog.total_products", 0)),
|
||||
active_products=int(metrics.get("catalog.active_products", 0)),
|
||||
out_of_stock=0, # TODO: Implement
|
||||
),
|
||||
orders=OrderStatsBasicResponse(
|
||||
total_orders=int(total_orders),
|
||||
total_orders=int(metrics.get("orders.total", 0)),
|
||||
pending_orders=0, # TODO: Implement status tracking
|
||||
completed_orders=0, # TODO: Implement status tracking
|
||||
),
|
||||
imports=ImportStatsResponse(
|
||||
total=int(total_imports),
|
||||
pending=int(pending_imports),
|
||||
processing=int(processing_imports),
|
||||
completed=int(completed_imports),
|
||||
failed=int(failed_imports),
|
||||
success_rate=float(import_success_rate),
|
||||
total=int(metrics.get("marketplace.total_imports", 0)),
|
||||
pending=int(metrics.get("marketplace.pending_imports", 0)),
|
||||
processing=int(metrics.get("marketplace.processing_imports", 0)),
|
||||
completed=int(metrics.get("marketplace.successful_imports", 0)),
|
||||
failed=int(metrics.get("marketplace.failed_imports", 0)),
|
||||
success_rate=float(metrics.get("marketplace.success_rate", 0)),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -205,7 +205,9 @@ async def get_platform_menu_config(
|
||||
)
|
||||
|
||||
# Use user's preferred language, falling back to middleware-resolved language
|
||||
language = current_user.preferred_language or getattr(request.state, "language", "en")
|
||||
language = current_user.preferred_language or getattr(
|
||||
request.state, "language", "en"
|
||||
)
|
||||
|
||||
return _build_menu_config_response(
|
||||
items, frontend_type, language=language, platform_id=platform_id
|
||||
@@ -279,7 +281,10 @@ async def bulk_update_platform_menu_visibility(
|
||||
f"{len(update_data.visibility)} items for platform {platform.code} ({frontend_type.value})"
|
||||
)
|
||||
|
||||
return {"success": True, "message": f"Updated {len(update_data.visibility)} menu items"}
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Updated {len(update_data.visibility)} menu items",
|
||||
}
|
||||
|
||||
|
||||
@router.post("/platforms/{platform_id}/reset")
|
||||
@@ -334,7 +339,9 @@ async def get_user_menu_config(
|
||||
)
|
||||
|
||||
# Use user's preferred language, falling back to middleware-resolved language
|
||||
language = current_user.preferred_language or getattr(request.state, "language", "en")
|
||||
language = current_user.preferred_language or getattr(
|
||||
request.state, "language", "en"
|
||||
)
|
||||
|
||||
return _build_menu_config_response(
|
||||
items, FrontendType.ADMIN, language=language, user_id=current_user.id
|
||||
@@ -386,7 +393,9 @@ async def reset_user_menu_config(
|
||||
f"[MENU_CONFIG] Super admin {current_user.email} reset their personal menu config (hide all)"
|
||||
)
|
||||
|
||||
return MenuActionResponse(success=True, message="Menu configuration reset - all items hidden")
|
||||
return MenuActionResponse(
|
||||
success=True, message="Menu configuration reset - all items hidden"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/user/show-all", response_model=MenuActionResponse)
|
||||
@@ -486,22 +495,31 @@ async def get_rendered_admin_menu(
|
||||
)
|
||||
|
||||
# Use user's preferred language, falling back to middleware-resolved language
|
||||
language = current_user.preferred_language or getattr(request.state, "language", "en")
|
||||
language = current_user.preferred_language or getattr(
|
||||
request.state, "language", "en"
|
||||
)
|
||||
|
||||
# Translate section and item labels
|
||||
# menu is a list of DiscoveredMenuSection dataclasses
|
||||
sections = []
|
||||
for section in menu.get("sections", []):
|
||||
for section in menu:
|
||||
# Translate item labels
|
||||
translated_items = []
|
||||
for item in section.get("items", []):
|
||||
translated_item = item.copy()
|
||||
translated_item["label"] = _translate_label(item.get("label"), language)
|
||||
translated_items.append(translated_item)
|
||||
for item in section.items:
|
||||
translated_items.append(
|
||||
{
|
||||
"id": item.id,
|
||||
"label": _translate_label(item.label_key, language),
|
||||
"icon": item.icon,
|
||||
"url": item.route,
|
||||
"super_admin_only": item.is_super_admin_only,
|
||||
}
|
||||
)
|
||||
|
||||
sections.append(
|
||||
MenuSectionResponse(
|
||||
id=section["id"],
|
||||
label=_translate_label(section.get("label"), language),
|
||||
id=section.id,
|
||||
label=_translate_label(section.label_key, language),
|
||||
items=translated_items,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user