Рефакторинг: вынос логики онбординга тенанта в сервисный слой

Создан TenantOnboardingService как единый источник истины для:
- Активации заявки на регистрацию тенанта
- Создания Client, Domain, Subscription
- Инициализации системных данных (Customer, статусы, способы оплаты, склад, витрина)

Новые сервисы:
- TenantOnboardingService (tenants/services/onboarding.py)
- WarehouseService (inventory/services/warehouse_service.py)
- ShowcaseService (inventory/services/showcase_service.py)
- PaymentMethodService (orders/services/payment_method_service.py)

Рефакторинг:
- admin.py: 220 строк → 5 строк (делегирование сервису)
- init_tenant_data.py: 259 строк → 68 строк
- activate_registration.py: использует сервис
- Тесты обновлены для вызова сервиса напрямую

При создании тенанта автоматически создаются склад и витрина по умолчанию.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-30 14:52:55 +03:00
parent 658cd59511
commit b59ad725cb
13 changed files with 679 additions and 477 deletions

View File

@@ -9,6 +9,8 @@
4. Создание способов оплаты
5. Создание системных статусов заказов
6. Создание системного клиента
7. Создание склада по умолчанию
8. Создание витрины по умолчанию
"""
from django.test import TestCase, TransactionTestCase
from django.db import connection
@@ -19,6 +21,7 @@ from django_tenants.utils import schema_context
from tenants.models import Client, Domain, TenantRegistration
from orders.models import PaymentMethod, OrderStatus
from customers.models import Customer
from inventory.models import Warehouse, Showcase
User = get_user_model()
@@ -77,12 +80,9 @@ class TenantCreationIntegrationTest(TransactionTestCase):
status=TenantRegistration.STATUS_PENDING
)
# 2. Активируем заявку (как в админке)
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
# 2. Активируем заявку через сервис
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# 3. Проверяем что тенант создан
self.assertIsNotNone(tenant)
@@ -145,12 +145,9 @@ class TenantCreationIntegrationTest(TransactionTestCase):
status=TenantRegistration.STATUS_PENDING
)
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем статусы заказов
with schema_context('test_shop_statuses'):
statuses = OrderStatus.objects.all()
@@ -223,24 +220,86 @@ class TenantCreationIntegrationTest(TransactionTestCase):
phone='+375291111113',
status=TenantRegistration.STATUS_PENDING
)
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем системного клиента
with schema_context('test_shop_customers'):
system_customer = Customer.objects.filter(is_system_customer=True).first()
self.assertIsNotNone(
system_customer,
"Системный клиент не создан"
)
self.assertTrue(system_customer.is_system_customer)
self.assertEqual(system_customer.name, 'Анонимный клиент')
def test_new_tenant_gets_default_warehouse(self):
"""
Тест: Новый тенант получает склад по умолчанию.
"""
# Создаём и активируем тенант
registration = TenantRegistration.objects.create(
shop_name='Тестовый магазин склад',
schema_name='test_shop_warehouse',
owner_email='owner_warehouse@test.com',
owner_name='Тест Владелец Склад',
phone='+375291111118',
status=TenantRegistration.STATUS_PENDING
)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем склад по умолчанию
with schema_context('test_shop_warehouse'):
default_warehouse = Warehouse.objects.filter(is_default=True).first()
self.assertIsNotNone(
default_warehouse,
"Склад по умолчанию не создан"
)
self.assertTrue(default_warehouse.is_default)
self.assertTrue(default_warehouse.is_active)
self.assertTrue(default_warehouse.is_pickup_point)
self.assertEqual(default_warehouse.name, 'Основной склад')
def test_new_tenant_gets_default_showcase(self):
"""
Тест: Новый тенант получает витрину по умолчанию.
"""
# Создаём и активируем тенант
registration = TenantRegistration.objects.create(
shop_name='Тестовый магазин витрина',
schema_name='test_shop_showcase',
owner_email='owner_showcase@test.com',
owner_name='Тест Владелец Витрина',
phone='+375291111119',
status=TenantRegistration.STATUS_PENDING
)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем витрину по умолчанию
with schema_context('test_shop_showcase'):
default_showcase = Showcase.objects.filter(is_default=True).first()
self.assertIsNotNone(
default_showcase,
"Витрина по умолчанию не создана"
)
self.assertTrue(default_showcase.is_default)
self.assertTrue(default_showcase.is_active)
self.assertEqual(default_showcase.name, 'Основная витрина')
# Проверяем что витрина привязана к складу по умолчанию
self.assertIsNotNone(default_showcase.warehouse)
self.assertTrue(default_showcase.warehouse.is_default)
def test_new_tenant_gets_superuser(self):
"""
@@ -256,12 +315,9 @@ class TenantCreationIntegrationTest(TransactionTestCase):
status=TenantRegistration.STATUS_PENDING
)
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем суперпользователя
with schema_context('test_shop_admin'):
superuser = User.objects.filter(
@@ -290,12 +346,9 @@ class TenantCreationIntegrationTest(TransactionTestCase):
status=TenantRegistration.STATUS_PENDING
)
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем домен
domain = Domain.objects.filter(tenant=tenant).first()
@@ -325,12 +378,9 @@ class TenantCreationIntegrationTest(TransactionTestCase):
self.assertEqual(registration.status, TenantRegistration.STATUS_PENDING)
# Активируем
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Обновляем объект из БД
registration.refresh_from_db()
@@ -357,12 +407,9 @@ class TenantCreationIntegrationTest(TransactionTestCase):
status=TenantRegistration.STATUS_PENDING
)
from tenants.admin import TenantRegistrationAdmin
from django.contrib.admin.sites import AdminSite
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
tenant = admin._approve_registration(registration, self.admin_user)
from tenants.services import TenantOnboardingService
tenant = TenantOnboardingService.activate_registration(registration, self.admin_user)
# Проверяем тенант
self.assertIsNotNone(tenant)
self.assertTrue(tenant.is_active)
@@ -376,23 +423,34 @@ class TenantCreationIntegrationTest(TransactionTestCase):
# 1. Способы оплаты
payment_methods_count = PaymentMethod.objects.count()
self.assertEqual(payment_methods_count, 5, "Должно быть 5 способов оплаты")
# 2. Статусы заказов
order_statuses_count = OrderStatus.objects.count()
self.assertGreaterEqual(order_statuses_count, 3, "Должно быть минимум 3 статуса")
# 3. Системный клиент
system_customer = Customer.objects.filter(is_system_customer=True).first()
self.assertIsNotNone(system_customer, "Должен быть системный клиент")
# 4. Суперпользователь
superuser = User.objects.filter(email=settings.TENANT_ADMIN_EMAIL).first()
self.assertIsNotNone(superuser, "Должен быть суперпользователь")
# 5. Склад по умолчанию
default_warehouse = Warehouse.objects.filter(is_default=True).first()
self.assertIsNotNone(default_warehouse, "Должен быть склад по умолчанию")
self.assertTrue(default_warehouse.is_active)
# 6. Витрина по умолчанию
default_showcase = Showcase.objects.filter(is_default=True).first()
self.assertIsNotNone(default_showcase, "Должна быть витрина по умолчанию")
self.assertTrue(default_showcase.is_active)
self.assertEqual(default_showcase.warehouse, default_warehouse)
# Проверяем заявку
registration.refresh_from_db()
self.assertEqual(registration.status, TenantRegistration.STATUS_APPROVED)
print("\n" + "=" * 70)
print("✓ ПОЛНЫЙ ОНБОРДИНГ ТЕНАНТА ПРОШЁЛ УСПЕШНО")
print("=" * 70)
@@ -403,4 +461,6 @@ class TenantCreationIntegrationTest(TransactionTestCase):
print(f"Статусов заказов: {order_statuses_count}")
print(f"Системный клиент: ✓")
print(f"Суперпользователь: ✓")
print(f"Склад по умолчанию: ✓")
print(f"Витрина по умолчанию: ✓")
print("=" * 70)