fix(billing): complete billing module — fix tier change, platform support, merchant portal
- Fix admin tier change: resolve tier_code→tier_id in update_subscription(), delegate to billing_service.change_tier() for Stripe-connected subs - Add platform support to admin tiers page: platform column, filter dropdown, platform selector in create/edit modal, platform_name in tier API response - Filter used platforms in create subscription modal on merchant detail page - Enrich merchant portal API responses with tier code, tier_name, platform_name - Add eager-load of platform relationship in get_merchant_subscription() - Remove stale store_name/store_code references from merchant templates - Add merchant tier change endpoint (POST /change-tier) and tier selector UI replacing broken requestUpgrade() button - Fix subscription detail link to use platform_id instead of sub.id Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
247
app/modules/customers/tests/unit/test_customer_model.py
Normal file
247
app/modules/customers/tests/unit/test_customer_model.py
Normal file
@@ -0,0 +1,247 @@
|
||||
# tests/unit/models/database/test_customer.py
|
||||
"""Unit tests for Customer and CustomerAddress database models."""
|
||||
|
||||
import pytest
|
||||
|
||||
from app.modules.customers.models.customer import Customer, CustomerAddress
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.database
|
||||
class TestCustomerModel:
|
||||
"""Test Customer model."""
|
||||
|
||||
def test_customer_creation(self, db, test_store):
|
||||
"""Test Customer model with store isolation."""
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="customer@example.com",
|
||||
hashed_password="hashed_password",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
customer_number="CUST001",
|
||||
is_active=True,
|
||||
)
|
||||
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
|
||||
assert customer.id is not None
|
||||
assert customer.store_id == test_store.id
|
||||
assert customer.email == "customer@example.com"
|
||||
assert customer.customer_number == "CUST001"
|
||||
assert customer.first_name == "John"
|
||||
assert customer.last_name == "Doe"
|
||||
assert customer.store.store_code == test_store.store_code
|
||||
|
||||
def test_customer_default_values(self, db, test_store):
|
||||
"""Test Customer model default values."""
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="defaults@example.com",
|
||||
hashed_password="hash",
|
||||
customer_number="CUST_DEFAULTS",
|
||||
)
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
|
||||
assert customer.is_active is True # Default
|
||||
assert customer.marketing_consent is False # Default
|
||||
assert customer.total_orders == 0 # Default
|
||||
assert customer.total_spent == 0 # Default
|
||||
|
||||
def test_customer_full_name_property(self, db, test_store):
|
||||
"""Test Customer full_name computed property."""
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="fullname@example.com",
|
||||
hashed_password="hash",
|
||||
customer_number="CUST_FULLNAME",
|
||||
first_name="Jane",
|
||||
last_name="Smith",
|
||||
)
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
|
||||
assert customer.full_name == "Jane Smith"
|
||||
|
||||
def test_customer_full_name_fallback_to_email(self, db, test_store):
|
||||
"""Test Customer full_name falls back to email when names not set."""
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="noname@example.com",
|
||||
hashed_password="hash",
|
||||
customer_number="CUST_NONAME",
|
||||
)
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
|
||||
assert customer.full_name == "noname@example.com"
|
||||
|
||||
def test_customer_optional_fields(self, db, test_store):
|
||||
"""Test Customer with optional fields."""
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="optional@example.com",
|
||||
hashed_password="hash",
|
||||
customer_number="CUST_OPT",
|
||||
phone="+352123456789",
|
||||
preferences={"language": "en", "currency": "EUR"},
|
||||
marketing_consent=True,
|
||||
)
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
|
||||
assert customer.phone == "+352123456789"
|
||||
assert customer.preferences == {"language": "en", "currency": "EUR"}
|
||||
assert customer.marketing_consent is True
|
||||
|
||||
def test_customer_store_relationship(self, db, test_store):
|
||||
"""Test Customer-Store relationship."""
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="relationship@example.com",
|
||||
hashed_password="hash",
|
||||
customer_number="CUST_REL",
|
||||
)
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
|
||||
assert customer.store is not None
|
||||
assert customer.store.id == test_store.id
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.database
|
||||
class TestCustomerAddressModel:
|
||||
"""Test CustomerAddress model."""
|
||||
|
||||
def test_customer_address_creation(self, db, test_store, test_customer):
|
||||
"""Test CustomerAddress model."""
|
||||
address = CustomerAddress(
|
||||
store_id=test_store.id,
|
||||
customer_id=test_customer.id,
|
||||
address_type="shipping",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
address_line_1="123 Main St",
|
||||
city="Luxembourg",
|
||||
postal_code="L-1234",
|
||||
country_name="Luxembourg",
|
||||
country_iso="LU",
|
||||
is_default=True,
|
||||
)
|
||||
|
||||
db.add(address)
|
||||
db.commit()
|
||||
db.refresh(address)
|
||||
|
||||
assert address.id is not None
|
||||
assert address.store_id == test_store.id
|
||||
assert address.customer_id == test_customer.id
|
||||
assert address.address_type == "shipping"
|
||||
assert address.is_default is True
|
||||
|
||||
def test_customer_address_types(self, db, test_store, test_customer):
|
||||
"""Test CustomerAddress with different address types."""
|
||||
shipping_address = CustomerAddress(
|
||||
store_id=test_store.id,
|
||||
customer_id=test_customer.id,
|
||||
address_type="shipping",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
address_line_1="123 Shipping St",
|
||||
city="Luxembourg",
|
||||
postal_code="L-1234",
|
||||
country_name="Luxembourg",
|
||||
country_iso="LU",
|
||||
)
|
||||
db.add(shipping_address)
|
||||
|
||||
billing_address = CustomerAddress(
|
||||
store_id=test_store.id,
|
||||
customer_id=test_customer.id,
|
||||
address_type="billing",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
address_line_1="456 Billing Ave",
|
||||
city="Luxembourg",
|
||||
postal_code="L-5678",
|
||||
country_name="Luxembourg",
|
||||
country_iso="LU",
|
||||
)
|
||||
db.add(billing_address)
|
||||
db.commit()
|
||||
|
||||
assert shipping_address.address_type == "shipping"
|
||||
assert billing_address.address_type == "billing"
|
||||
|
||||
def test_customer_address_optional_fields(self, db, test_store, test_customer):
|
||||
"""Test CustomerAddress with optional fields."""
|
||||
address = CustomerAddress(
|
||||
store_id=test_store.id,
|
||||
customer_id=test_customer.id,
|
||||
address_type="shipping",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
company="ACME Corp",
|
||||
address_line_1="123 Main St",
|
||||
address_line_2="Suite 100",
|
||||
city="Luxembourg",
|
||||
postal_code="L-1234",
|
||||
country_name="Luxembourg",
|
||||
country_iso="LU",
|
||||
)
|
||||
db.add(address)
|
||||
db.commit()
|
||||
db.refresh(address)
|
||||
|
||||
assert address.company == "ACME Corp"
|
||||
assert address.address_line_2 == "Suite 100"
|
||||
|
||||
def test_customer_address_default_values(self, db, test_store, test_customer):
|
||||
"""Test CustomerAddress default values."""
|
||||
address = CustomerAddress(
|
||||
store_id=test_store.id,
|
||||
customer_id=test_customer.id,
|
||||
address_type="shipping",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
address_line_1="123 Main St",
|
||||
city="Luxembourg",
|
||||
postal_code="L-1234",
|
||||
country_name="Luxembourg",
|
||||
country_iso="LU",
|
||||
)
|
||||
db.add(address)
|
||||
db.commit()
|
||||
db.refresh(address)
|
||||
|
||||
assert address.is_default is False # Default
|
||||
|
||||
def test_customer_address_relationships(self, db, test_store, test_customer):
|
||||
"""Test CustomerAddress relationships."""
|
||||
address = CustomerAddress(
|
||||
store_id=test_store.id,
|
||||
customer_id=test_customer.id,
|
||||
address_type="shipping",
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
address_line_1="123 Main St",
|
||||
city="Luxembourg",
|
||||
postal_code="L-1234",
|
||||
country_name="Luxembourg",
|
||||
country_iso="LU",
|
||||
)
|
||||
db.add(address)
|
||||
db.commit()
|
||||
db.refresh(address)
|
||||
|
||||
assert address.customer is not None
|
||||
assert address.customer.id == test_customer.id
|
||||
Reference in New Issue
Block a user