# tests/unit/services/test_order_metrics_customer.py """ Unit tests for OrderMetricsProvider customer metrics. Tests the get_customer_order_metrics method which provides customer-level order statistics using the MetricsProvider pattern. """ from datetime import UTC, datetime import pytest from app.modules.orders.models import Order from app.modules.orders.services.order_metrics import OrderMetricsProvider @pytest.fixture def order_metrics_provider(): """Create OrderMetricsProvider instance.""" return OrderMetricsProvider() @pytest.fixture def customer_with_orders(db, test_vendor, test_customer): """Create a customer with multiple orders for metrics testing.""" orders = [] first_name = test_customer.first_name or "Test" last_name = test_customer.last_name or "Customer" for i in range(3): order = Order( vendor_id=test_vendor.id, customer_id=test_customer.id, order_number=f"METRICS-{i:04d}", status="completed", channel="direct", order_date=datetime.now(UTC), subtotal_cents=1000 * (i + 1), # 1000, 2000, 3000 total_amount_cents=1000 * (i + 1), currency="EUR", # Customer info customer_email=test_customer.email, customer_first_name=first_name, customer_last_name=last_name, # Shipping address ship_first_name=first_name, ship_last_name=last_name, ship_address_line_1="123 Test St", ship_city="Luxembourg", ship_postal_code="L-1234", ship_country_iso="LU", # Billing address bill_first_name=first_name, bill_last_name=last_name, bill_address_line_1="123 Test St", bill_city="Luxembourg", bill_postal_code="L-1234", bill_country_iso="LU", ) db.add(order) orders.append(order) db.commit() for order in orders: db.refresh(order) return test_customer, orders @pytest.mark.unit class TestOrderMetricsProviderCustomerMetrics: """Tests for get_customer_order_metrics method.""" def test_get_customer_metrics_no_orders( self, db, order_metrics_provider, test_vendor, test_customer ): """Test metrics when customer has no orders.""" metrics = order_metrics_provider.get_customer_order_metrics( db=db, vendor_id=test_vendor.id, customer_id=test_customer.id, ) # Should return metrics even with no orders assert len(metrics) > 0 # Find total_orders metric total_orders_metric = next( (m for m in metrics if m.key == "customer.total_orders"), None ) assert total_orders_metric is not None assert total_orders_metric.value == 0 def test_get_customer_metrics_with_orders( self, db, order_metrics_provider, test_vendor, customer_with_orders ): """Test metrics when customer has orders.""" customer, orders = customer_with_orders metrics = order_metrics_provider.get_customer_order_metrics( db=db, vendor_id=test_vendor.id, customer_id=customer.id, ) # Check total orders total_orders = next( (m for m in metrics if m.key == "customer.total_orders"), None ) assert total_orders is not None assert total_orders.value == 3 # Check total spent (1000 + 2000 + 3000 = 6000 cents = 60.00) total_spent = next( (m for m in metrics if m.key == "customer.total_spent"), None ) assert total_spent is not None assert total_spent.value == 60.0 # Check average order value (6000 / 3 = 2000 cents = 20.00) avg_value = next( (m for m in metrics if m.key == "customer.avg_order_value"), None ) assert avg_value is not None assert avg_value.value == 20.0 def test_get_customer_metrics_has_required_fields( self, db, order_metrics_provider, test_vendor, customer_with_orders ): """Test that all required metric fields are present.""" customer, _ = customer_with_orders metrics = order_metrics_provider.get_customer_order_metrics( db=db, vendor_id=test_vendor.id, customer_id=customer.id, ) expected_keys = [ "customer.total_orders", "customer.total_spent", "customer.avg_order_value", "customer.last_order_date", "customer.first_order_date", ] metric_keys = [m.key for m in metrics] for key in expected_keys: assert key in metric_keys, f"Missing metric: {key}" def test_get_customer_metrics_has_labels_and_icons( self, db, order_metrics_provider, test_vendor, customer_with_orders ): """Test that metrics have display metadata.""" customer, _ = customer_with_orders metrics = order_metrics_provider.get_customer_order_metrics( db=db, vendor_id=test_vendor.id, customer_id=customer.id, ) for metric in metrics: assert metric.label, f"Metric {metric.key} missing label" assert metric.category == "customer_orders" def test_get_customer_metrics_wrong_vendor( self, db, order_metrics_provider, customer_with_orders ): """Test metrics with wrong vendor returns zero values.""" customer, _ = customer_with_orders metrics = order_metrics_provider.get_customer_order_metrics( db=db, vendor_id=99999, # Non-existent vendor customer_id=customer.id, ) total_orders = next( (m for m in metrics if m.key == "customer.total_orders"), None ) assert total_orders is not None assert total_orders.value == 0