Создан 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>
126 lines
5.7 KiB
Python
126 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Management команда для ручной активации заявки на регистрацию тенанта.
|
||
|
||
Использование:
|
||
python manage.py activate_registration <schema_name>
|
||
|
||
Пример:
|
||
python manage.py activate_registration mixflowers
|
||
"""
|
||
from django.core.management.base import BaseCommand, CommandError
|
||
from django.conf import settings
|
||
from tenants.models import TenantRegistration, Client, Domain
|
||
|
||
|
||
class Command(BaseCommand):
|
||
help = 'Активировать заявку на регистрацию тенанта вручную'
|
||
|
||
def add_arguments(self, parser):
|
||
parser.add_argument(
|
||
'schema_name',
|
||
type=str,
|
||
help='Schema name заявки для активации'
|
||
)
|
||
parser.add_argument(
|
||
'--force',
|
||
action='store_true',
|
||
help='Принудительная активация (пересоздать тенант если уже существует)'
|
||
)
|
||
|
||
def handle(self, *args, **options):
|
||
schema_name = options['schema_name']
|
||
force = options.get('force', False)
|
||
|
||
# Ищем заявку
|
||
try:
|
||
registration = TenantRegistration.objects.get(schema_name=schema_name)
|
||
except TenantRegistration.DoesNotExist:
|
||
raise CommandError(f'Заявка с schema_name "{schema_name}" не найдена')
|
||
|
||
self._print_registration_info(registration)
|
||
|
||
# Проверяем статус
|
||
if registration.status == TenantRegistration.STATUS_APPROVED and not force:
|
||
self.stdout.write(self.style.WARNING('Эта заявка уже была одобрена!'))
|
||
if registration.tenant:
|
||
self.stdout.write(f'Связанный тенант: {registration.tenant.name} (ID: {registration.tenant.id})')
|
||
return
|
||
else:
|
||
self.stdout.write(self.style.WARNING('Но тенант не был создан. Используйте --force для пересоздания'))
|
||
if not self._confirm('Продолжить с --force?'):
|
||
return
|
||
force = True
|
||
|
||
# Проверяем существование тенанта
|
||
existing_client = Client.objects.filter(schema_name=schema_name).first()
|
||
if existing_client and not force:
|
||
raise CommandError(
|
||
f'Тенант с schema_name "{schema_name}" уже существует (ID: {existing_client.id}). '
|
||
'Используйте --force для пересоздания (ОПАСНО: удалит все данные!)'
|
||
)
|
||
|
||
# Если force - удаляем старый тенант
|
||
if force and existing_client:
|
||
self._delete_existing_tenant(existing_client)
|
||
|
||
# Активация через сервис
|
||
self._activate(registration)
|
||
|
||
def _print_registration_info(self, registration):
|
||
"""Вывод информации о заявке."""
|
||
self.stdout.write(f'Найдена заявка: {registration.shop_name} ({registration.schema_name})')
|
||
self.stdout.write(f'Статус: {registration.get_status_display()}')
|
||
self.stdout.write(f'Email: {registration.owner_email}')
|
||
self.stdout.write('')
|
||
|
||
def _delete_existing_tenant(self, client):
|
||
"""Удаление существующего тенанта."""
|
||
self.stdout.write(self.style.WARNING(f'Удаление существующего тенанта {client.id}...'))
|
||
try:
|
||
client.subscription.delete()
|
||
except Exception:
|
||
pass
|
||
Domain.objects.filter(tenant=client).delete()
|
||
client.delete()
|
||
self.stdout.write(self.style.SUCCESS('Старый тенант удален'))
|
||
|
||
def _activate(self, registration):
|
||
"""Активация заявки через сервис."""
|
||
self.stdout.write('')
|
||
self.stdout.write(self.style.WARNING('НАЧИНАЮ АКТИВАЦИЮ...'))
|
||
self.stdout.write('')
|
||
|
||
try:
|
||
from tenants.services import TenantOnboardingService
|
||
client = TenantOnboardingService.activate_registration(registration, admin_user=None)
|
||
|
||
# Выводим результат
|
||
domain = Domain.objects.filter(tenant=client, is_primary=True).first()
|
||
domain_base = settings.TENANT_DOMAIN_BASE
|
||
if ':' in domain_base:
|
||
domain_base = domain_base.split(':')[0]
|
||
domain_name = f"{registration.schema_name}.{domain_base}"
|
||
|
||
self.stdout.write('')
|
||
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||
self.stdout.write(self.style.SUCCESS('АКТИВАЦИЯ ЗАВЕРШЕНА УСПЕШНО!'))
|
||
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||
self.stdout.write('')
|
||
self.stdout.write(f'Магазин: {client.name}')
|
||
self.stdout.write(f'Schema: {client.schema_name}')
|
||
self.stdout.write(f'Домен: http://{domain_name}:8000/')
|
||
self.stdout.write(f'Подписка до: {client.subscription.expires_at.strftime("%Y-%m-%d")} ({client.subscription.days_left()} дней)')
|
||
self.stdout.write('')
|
||
|
||
except Exception as e:
|
||
self.stdout.write(self.style.ERROR(f'ОШИБКА: {str(e)}'))
|
||
import traceback
|
||
self.stdout.write(traceback.format_exc())
|
||
raise CommandError('Активация не удалась')
|
||
|
||
def _confirm(self, question):
|
||
"""Запрос подтверждения у пользователя."""
|
||
answer = input(f'{question} (yes/no): ')
|
||
return answer.lower() in ['yes', 'y', 'да']
|