Files
octopus/myproject/tenants/management/commands/init_tenant_data.py
Andrey Smakotin e54d7d04d7 feat: Добавлены команды управления данными тенантов и исправлены фильтры по статусу товаров
Добавлено:
- Команда clear_tenant_data для полной очистки данных тенанта без удаления схемы
  * Очищает все таблицы через TRUNCATE CASCADE
  * Сбрасывает ID-последовательности
  * Сохраняет схему БД и запись Client
  * Поддержка флага --noinput для автоматизации

- Команда init_tenant_data для инициализации системных данных тенанта
  * Создаёт системного клиента (АНОНИМНЫЙ ПОКУПАТЕЛЬ для POS)
  * Создаёт 8 системных статусов заказов
  * Создаёт 5 системных способов оплаты
  * Поддержка флага --reset для пересоздания данных

Исправлено:
- Заменены устаревшие фильтры is_active на status='active' для Product и ProductKit
  * products/views/category_views.py: исправлены фильтры в build_category_tree и get_context_data
  * products/services/kit_pricing.py: исправлены фильтры при получении товаров из variant_group
  * products/models/kits.py: исправлен фильтр в get_available_products
  * Устранена ошибка FieldError при работе со списком категорий

Улучшено:
- Команда clear_tenant_data теперь предлагает пользователю инициализировать системные данные после очистки
- Добавлена детальная информация о процессе очистки и инициализации данных
2025-12-12 04:58:26 +03:00

186 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
Management команда для инициализации всех системных данных тенанта.
Создаёт:
- Системного клиента (анонимный покупатель для POS)
- Системные статусы заказов
- Системные способы оплаты
Использование:
# Инициализация для конкретного тенанта
python manage.py init_tenant_data --schema=anatol
# С флагом --reset для пересоздания данных
python manage.py init_tenant_data --schema=anatol --reset
"""
from django.core.management.base import BaseCommand
from django.db import connection
from django_tenants.utils import get_tenant_model, schema_context
class Command(BaseCommand):
help = 'Инициализация всех системных данных тенанта (клиент, статусы, способы оплаты)'
def add_arguments(self, parser):
parser.add_argument(
'--schema',
type=str,
required=True,
help='Имя схемы БД тенанта (пример: anatol)'
)
parser.add_argument(
'--reset',
action='store_true',
help='Удалить и пересоздать все системные данные'
)
def handle(self, *args, **options):
schema_name = options.get('schema')
reset = options.get('reset', False)
# Проверяем что тенант существует
Tenant = get_tenant_model()
try:
tenant = Tenant.objects.get(schema_name=schema_name)
except Tenant.DoesNotExist:
self.stdout.write(self.style.ERROR(f'\nОШИБКА: Тенант со схемой "{schema_name}" не найден\n'))
return
self.stdout.write(self.style.SUCCESS('\n=== Инициализация системных данных тенанта ===\n'))
self.stdout.write(f'Тенант: {tenant.name} ({schema_name})\n')
# Переключаемся на схему тенанта
with schema_context(schema_name):
# 1. Создаём системного клиента
self.stdout.write('\n' + '='*70)
self.stdout.write('[1] Создание системного клиента...')
self.stdout.write('='*70)
from customers.models import Customer
if reset:
# Удаляем существующего системного клиента
system_customers = Customer.objects.filter(email="system@pos.customer")
if system_customers.exists():
count = system_customers.count()
system_customers.delete()
self.stdout.write(self.style.WARNING(f' Удалено системных клиентов: {count}'))
try:
system_customer, created = Customer.get_or_create_system_customer()
if created:
self.stdout.write(self.style.SUCCESS(f' ✓ Системный клиент создан: {system_customer.name}'))
self.stdout.write(f' Email: {system_customer.email}')
self.stdout.write(f' ID: {system_customer.id}')
else:
self.stdout.write(self.style.WARNING(f' • Системный клиент уже существует: {system_customer.name}'))
self.stdout.write(f' ID: {system_customer.id}')
except Exception as e:
self.stdout.write(self.style.ERROR(f' ✗ Ошибка при создании системного клиента: {e}'))
# 2. Создаём системные статусы заказов
self.stdout.write('\n' + '='*70)
self.stdout.write('[2] Создание системных статусов заказов...')
self.stdout.write('='*70)
from orders.models import OrderStatus
from orders.services.order_status_service import OrderStatusService
if reset:
count = OrderStatus.objects.filter(is_system=True).count()
if count > 0:
OrderStatus.objects.filter(is_system=True).delete()
self.stdout.write(self.style.WARNING(f' Удалено системных статусов: {count}'))
try:
OrderStatusService.create_default_statuses()
statuses = OrderStatus.objects.filter(is_system=True).order_by('order')
self.stdout.write(self.style.SUCCESS(f' ✓ Создано системных статусов: {statuses.count()}'))
for status in statuses:
end_type = ''
if status.is_positive_end:
end_type = ' [Успешный]'
elif status.is_negative_end:
end_type = ' [Отрицательный]'
self.stdout.write(f' - {status.name:<20} ({status.code:<15}){end_type}')
except Exception as e:
self.stdout.write(self.style.ERROR(f' ✗ Ошибка при создании статусов: {e}'))
# 3. Создаём системные способы оплаты
self.stdout.write('\n' + '='*70)
self.stdout.write('[3] Создание системных способов оплаты...')
self.stdout.write('='*70)
from orders.models import PaymentMethod
if reset:
count = PaymentMethod.objects.filter(is_system=True).count()
if count > 0:
PaymentMethod.objects.filter(is_system=True).delete()
self.stdout.write(self.style.WARNING(f' Удалено системных способов оплаты: {count}'))
payment_methods = [
{
'code': 'account_balance',
'name': 'С баланса счёта',
'description': 'Оплата из кошелька клиента',
'is_system': True,
'order': 0
},
{
'code': 'cash',
'name': 'Наличными',
'description': 'Оплата наличными деньгами',
'is_system': True,
'order': 1
},
{
'code': 'card',
'name': 'Картой',
'description': 'Оплата банковской картой',
'is_system': True,
'order': 2
},
{
'code': 'online',
'name': 'Онлайн',
'description': 'Онлайн оплата через платежную систему',
'is_system': True,
'order': 3
},
{
'code': 'legal_entity',
'name': 'Безнал от ЮРЛИЦ',
'description': 'Безналичный расчёт от юридических лиц',
'is_system': True,
'order': 4
},
]
created_count = 0
try:
for method_data in payment_methods:
method, created = PaymentMethod.objects.get_or_create(
code=method_data['code'],
defaults=method_data
)
if created:
created_count += 1
self.stdout.write(self.style.SUCCESS(f' ✓ Создан способ оплаты: {method.name}'))
else:
self.stdout.write(self.style.WARNING(f' • Уже существует: {method.name}'))
self.stdout.write(self.style.SUCCESS(f'\n Готово! Создано {created_count} новых способов оплаты.'))
except Exception as e:
self.stdout.write(self.style.ERROR(f' ✗ Ошибка при создании способов оплаты: {e}'))
# Итоговое сообщение
self.stdout.write('\n' + '='*70)
self.stdout.write(self.style.SUCCESS('УСПЕХ: Инициализация системных данных завершена!'))
self.stdout.write('='*70)
self.stdout.write('\nТенант готов к работе.\n')