- Schema: add merchant_id/prospect_id with model_validator requiring at least one. Remove from-prospect endpoint (unified into POST /sites) - Service: rewrite create() — if merchant_id use it directly, if prospect_id auto-create merchant from prospect data. Remove system merchant hack entirely. Extract _create_merchant_from_prospect helper. - Simplify accept_proposal() — merchant already exists at creation, only creates subscription and marks prospect converted - Tests: update all create calls with merchant_id, replace from-prospect tests with prospect_id + validation tests Closes docs/proposals/hosting-site-creation-fix.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
188 lines
5.1 KiB
Python
188 lines
5.1 KiB
Python
# app/modules/hosting/tests/conftest.py
|
|
"""
|
|
Module-specific fixtures for hosting tests.
|
|
Core fixtures (db, client, etc.) are inherited from the root conftest.py.
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import UTC, datetime, timedelta
|
|
|
|
import pytest
|
|
|
|
from app.modules.hosting.models import (
|
|
ClientService,
|
|
ClientServiceStatus,
|
|
HostedSite,
|
|
HostedSiteStatus,
|
|
ServiceType,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def hosting_platform(db):
|
|
"""Ensure a 'hosting' platform exists for hosted site creation."""
|
|
from app.modules.tenancy.models import Platform
|
|
|
|
platform = db.query(Platform).filter(Platform.code == "hosting").first()
|
|
if not platform:
|
|
platform = Platform(
|
|
code="hosting",
|
|
name="Hosting Platform",
|
|
is_active=True,
|
|
is_public=False,
|
|
default_language="fr",
|
|
supported_languages=["fr", "en", "de"],
|
|
)
|
|
db.add(platform)
|
|
db.commit()
|
|
db.refresh(platform)
|
|
return platform
|
|
|
|
|
|
@pytest.fixture
|
|
def system_user(db):
|
|
"""Create a system user for the HostWizard System merchant."""
|
|
from app.modules.tenancy.models import User
|
|
|
|
user = User(
|
|
email=f"system-{uuid.uuid4().hex[:8]}@hostwizard.lu",
|
|
username=f"system_{uuid.uuid4().hex[:8]}",
|
|
first_name="System",
|
|
last_name="User",
|
|
hashed_password="not-a-real-hash", # noqa: SEC001
|
|
role="super_admin",
|
|
is_active=True,
|
|
)
|
|
db.add(user)
|
|
db.commit()
|
|
db.refresh(user)
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def system_merchant(db, system_user):
|
|
"""Ensure the HostWizard System merchant exists."""
|
|
from app.modules.tenancy.models import Merchant
|
|
|
|
merchant = db.query(Merchant).filter(Merchant.name == "HostWizard System").first()
|
|
if not merchant:
|
|
merchant = Merchant(
|
|
name="HostWizard System",
|
|
contact_email="system@hostwizard.lu",
|
|
owner_user_id=system_user.id,
|
|
is_active=True,
|
|
is_verified=True,
|
|
)
|
|
db.add(merchant)
|
|
db.commit()
|
|
db.refresh(merchant)
|
|
return merchant
|
|
|
|
|
|
@pytest.fixture
|
|
def hosted_site(db, hosting_platform, system_merchant):
|
|
"""Create a hosted site in DRAFT status with its backing store."""
|
|
from app.modules.hosting.services.hosted_site_service import hosted_site_service
|
|
|
|
unique = uuid.uuid4().hex[:8]
|
|
site = hosted_site_service.create(
|
|
db,
|
|
{
|
|
"business_name": f"Test Business {unique}",
|
|
"merchant_id": system_merchant.id,
|
|
"contact_name": "John Doe",
|
|
"contact_email": f"john-{unique}@example.com",
|
|
"contact_phone": "+352 123 456",
|
|
"internal_notes": "Test site",
|
|
},
|
|
)
|
|
db.commit()
|
|
db.refresh(site)
|
|
return site
|
|
|
|
|
|
@pytest.fixture
|
|
def hosted_site_poc_ready(db, hosted_site):
|
|
"""Create a hosted site in POC_READY status."""
|
|
from app.modules.hosting.services.hosted_site_service import hosted_site_service
|
|
|
|
site = hosted_site_service.mark_poc_ready(db, hosted_site.id)
|
|
db.commit()
|
|
db.refresh(site)
|
|
return site
|
|
|
|
|
|
@pytest.fixture
|
|
def hosted_site_proposal_sent(db, hosted_site_poc_ready):
|
|
"""Create a hosted site in PROPOSAL_SENT status."""
|
|
from app.modules.hosting.services.hosted_site_service import hosted_site_service
|
|
|
|
site = hosted_site_service.send_proposal(
|
|
db, hosted_site_poc_ready.id, notes="Test proposal"
|
|
)
|
|
db.commit()
|
|
db.refresh(site)
|
|
return site
|
|
|
|
|
|
@pytest.fixture
|
|
def client_service_domain(db, hosted_site):
|
|
"""Create a domain client service for a hosted site."""
|
|
service = ClientService(
|
|
hosted_site_id=hosted_site.id,
|
|
service_type=ServiceType.DOMAIN,
|
|
name="test-domain.lu",
|
|
status=ClientServiceStatus.ACTIVE,
|
|
billing_period="annual",
|
|
price_cents=2500,
|
|
currency="EUR",
|
|
domain_name="test-domain.lu",
|
|
registrar="Namecheap",
|
|
expires_at=datetime.now(UTC) + timedelta(days=365),
|
|
auto_renew=True,
|
|
)
|
|
db.add(service)
|
|
db.commit()
|
|
db.refresh(service)
|
|
return service
|
|
|
|
|
|
@pytest.fixture
|
|
def client_service_email(db, hosted_site):
|
|
"""Create an email client service for a hosted site."""
|
|
service = ClientService(
|
|
hosted_site_id=hosted_site.id,
|
|
service_type=ServiceType.EMAIL,
|
|
name="Email Hosting",
|
|
status=ClientServiceStatus.ACTIVE,
|
|
billing_period="monthly",
|
|
price_cents=500,
|
|
currency="EUR",
|
|
mailbox_count=5,
|
|
auto_renew=True,
|
|
)
|
|
db.add(service)
|
|
db.commit()
|
|
db.refresh(service)
|
|
return service
|
|
|
|
|
|
@pytest.fixture
|
|
def client_service_expiring(db, hosted_site):
|
|
"""Create a client service expiring within 30 days."""
|
|
service = ClientService(
|
|
hosted_site_id=hosted_site.id,
|
|
service_type=ServiceType.SSL,
|
|
name="SSL Certificate",
|
|
status=ClientServiceStatus.ACTIVE,
|
|
billing_period="annual",
|
|
price_cents=0,
|
|
currency="EUR",
|
|
expires_at=datetime.now(UTC) + timedelta(days=15),
|
|
auto_renew=True,
|
|
)
|
|
db.add(service)
|
|
db.commit()
|
|
db.refresh(service)
|
|
return service
|