Files
orion/app/modules/customers/tests/unit/test_customer_metrics.py
Samir Boulahtit d7a383f3d7 test: add tests for merchant dashboard metrics and fix invoice template location
Move invoice PDF template from app/templates/invoices/ to
app/modules/orders/templates/invoices/ where InvoicePDFService expects it.
Expand invoice PDF tests to validate template path and existence.

Add unit tests for get_merchant_metrics() in tenancy, billing, and
customer metrics providers. Add unit tests for StatsAggregatorService
merchant methods. Add integration tests for the merchant dashboard
stats endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 21:46:34 +01:00

131 lines
4.0 KiB
Python

# app/modules/customers/tests/unit/test_customer_metrics.py
"""Unit tests for CustomerMetricsProvider.get_merchant_metrics."""
import uuid
import pytest
from app.modules.customers.models.customer import Customer
from app.modules.customers.services.customer_metrics import CustomerMetricsProvider
from app.modules.tenancy.models import Merchant, Store, User
@pytest.fixture
def cust_merchant(db):
"""Create a merchant for customer metrics tests."""
from middleware.auth import AuthManager
auth = AuthManager()
user = User(
email=f"custowner_{uuid.uuid4().hex[:8]}@test.com",
username=f"custowner_{uuid.uuid4().hex[:8]}",
hashed_password=auth.hash_password("pass123"),
role="merchant_owner",
is_active=True,
)
db.add(user)
db.flush()
merchant = Merchant(
name="Customer Metrics Merchant",
owner_user_id=user.id,
contact_email=user.email,
is_active=True,
is_verified=True,
)
db.add(merchant)
db.commit()
db.refresh(merchant)
return merchant
@pytest.fixture
def cust_stores(db, cust_merchant):
"""Create 2 stores for the merchant."""
stores = []
for i in range(2):
uid = uuid.uuid4().hex[:8].upper()
store = Store(
merchant_id=cust_merchant.id,
store_code=f"CSTORE_{uid}",
subdomain=f"cstore{uid.lower()}",
name=f"Cust Store {i}",
is_active=True,
is_verified=True,
)
db.add(store)
stores.append(store)
db.commit()
for s in stores:
db.refresh(s)
return stores
@pytest.fixture
def cust_customers(db, cust_stores):
"""Create customers across the merchant's stores."""
customers = []
# 3 customers in store 0
for i in range(3):
uid = uuid.uuid4().hex[:8]
c = Customer(
store_id=cust_stores[0].id,
email=f"cust_{uid}@test.com",
hashed_password="hashed", # noqa: SEC001
first_name=f"First{i}",
last_name=f"Last{i}",
customer_number=f"C{uid}",
is_active=True,
)
db.add(c)
customers.append(c)
# 2 customers in store 1
for i in range(2):
uid = uuid.uuid4().hex[:8]
c = Customer(
store_id=cust_stores[1].id,
email=f"cust_{uid}@test.com",
hashed_password="hashed", # noqa: SEC001
first_name=f"First{i}",
last_name=f"Last{i}",
customer_number=f"C{uid}",
is_active=True,
)
db.add(c)
customers.append(c)
db.commit()
return customers
@pytest.mark.unit
@pytest.mark.customers
class TestCustomerMetricsProviderMerchant:
"""Tests for CustomerMetricsProvider.get_merchant_metrics."""
def setup_method(self):
self.provider = CustomerMetricsProvider()
def test_total_customers_across_stores(self, db, cust_merchant, cust_stores, cust_customers):
"""Aggregates customers across all merchant stores."""
metrics = self.provider.get_merchant_metrics(db, cust_merchant.id)
by_key = {m.key: m.value for m in metrics}
assert by_key["customers.total"] == 5
def test_no_customers(self, db, cust_merchant, cust_stores):
"""Returns zero when stores have no customers."""
metrics = self.provider.get_merchant_metrics(db, cust_merchant.id)
by_key = {m.key: m.value for m in metrics}
assert by_key["customers.total"] == 0
def test_no_stores(self, db, cust_merchant):
"""Returns zero when merchant has no stores."""
metrics = self.provider.get_merchant_metrics(db, cust_merchant.id)
by_key = {m.key: m.value for m in metrics}
assert by_key["customers.total"] == 0
def test_nonexistent_merchant(self, db):
"""Returns zero for a non-existent merchant ID."""
metrics = self.provider.get_merchant_metrics(db, 999999)
by_key = {m.key: m.value for m in metrics}
assert by_key["customers.total"] == 0