refactor: fix architecture violations with provider patterns and dependency inversion
Major changes: - Add AuditProvider protocol for cross-module audit logging - Move customer order operations to orders module (dependency inversion) - Add customer order metrics via MetricsProvider pattern - Fix missing db parameter in get_admin_context() calls - Move ProductMedia relationship to catalog module (proper ownership) - Add marketplace breakdown stats to marketplace_widgets New files: - contracts/audit.py - AuditProviderProtocol - core/services/audit_aggregator.py - Aggregates audit providers - monitoring/services/audit_provider.py - Monitoring audit implementation - orders/services/customer_order_service.py - Customer order operations - orders/routes/api/vendor_customer_orders.py - Customer order endpoints - catalog/services/product_media_service.py - Product media service - Architecture documentation for patterns Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -302,6 +302,111 @@ class OrderMetricsProvider:
|
||||
return []
|
||||
|
||||
|
||||
def get_customer_order_metrics(
|
||||
self,
|
||||
db: Session,
|
||||
vendor_id: int,
|
||||
customer_id: int,
|
||||
context: MetricsContext | None = None,
|
||||
) -> list[MetricValue]:
|
||||
"""
|
||||
Get order metrics for a specific customer.
|
||||
|
||||
This is an entity-level method (not dashboard-level) that provides
|
||||
order statistics for a specific customer. Used by customer detail pages.
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
vendor_id: Vendor ID (for ownership verification)
|
||||
customer_id: Customer ID
|
||||
context: Optional filtering context
|
||||
|
||||
Returns:
|
||||
List of MetricValue objects for this customer's order activity
|
||||
"""
|
||||
from app.modules.orders.models import Order
|
||||
|
||||
try:
|
||||
# Base query for customer orders
|
||||
base_query = db.query(Order).filter(
|
||||
Order.customer_id == customer_id,
|
||||
Order.vendor_id == vendor_id,
|
||||
)
|
||||
|
||||
# Total orders
|
||||
total_orders = base_query.count()
|
||||
|
||||
# Revenue stats
|
||||
revenue_query = db.query(
|
||||
func.sum(Order.total_amount_cents).label("total_spent_cents"),
|
||||
func.avg(Order.total_amount_cents).label("avg_order_cents"),
|
||||
func.max(Order.created_at).label("last_order_date"),
|
||||
func.min(Order.created_at).label("first_order_date"),
|
||||
).filter(
|
||||
Order.customer_id == customer_id,
|
||||
Order.vendor_id == vendor_id,
|
||||
)
|
||||
|
||||
stats = revenue_query.first()
|
||||
|
||||
total_spent_cents = stats.total_spent_cents or 0
|
||||
avg_order_cents = stats.avg_order_cents or 0
|
||||
last_order_date = stats.last_order_date
|
||||
first_order_date = stats.first_order_date
|
||||
|
||||
# Convert cents to currency
|
||||
total_spent = total_spent_cents / 100
|
||||
avg_order_value = avg_order_cents / 100 if avg_order_cents else 0.0
|
||||
|
||||
return [
|
||||
MetricValue(
|
||||
key="customer.total_orders",
|
||||
value=total_orders,
|
||||
label="Total Orders",
|
||||
category="customer_orders",
|
||||
icon="shopping-bag",
|
||||
description="Total orders placed by this customer",
|
||||
),
|
||||
MetricValue(
|
||||
key="customer.total_spent",
|
||||
value=round(total_spent, 2),
|
||||
label="Total Spent",
|
||||
category="customer_orders",
|
||||
icon="currency-euro",
|
||||
unit="EUR",
|
||||
description="Total amount spent by this customer",
|
||||
),
|
||||
MetricValue(
|
||||
key="customer.avg_order_value",
|
||||
value=round(avg_order_value, 2),
|
||||
label="Avg Order Value",
|
||||
category="customer_orders",
|
||||
icon="calculator",
|
||||
unit="EUR",
|
||||
description="Average order value for this customer",
|
||||
),
|
||||
MetricValue(
|
||||
key="customer.last_order_date",
|
||||
value=last_order_date.isoformat() if last_order_date else "",
|
||||
label="Last Order",
|
||||
category="customer_orders",
|
||||
icon="calendar",
|
||||
description="Date of most recent order",
|
||||
),
|
||||
MetricValue(
|
||||
key="customer.first_order_date",
|
||||
value=first_order_date.isoformat() if first_order_date else "",
|
||||
label="First Order",
|
||||
category="customer_orders",
|
||||
icon="calendar-plus",
|
||||
description="Date of first order",
|
||||
),
|
||||
]
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to get customer order metrics: {e}")
|
||||
return []
|
||||
|
||||
|
||||
# Singleton instance
|
||||
order_metrics_provider = OrderMetricsProvider()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user