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 теперь предлагает пользователю инициализировать системные данные после очистки
- Добавлена детальная информация о процессе очистки и инициализации данных
This commit is contained in:
2025-12-12 04:58:26 +03:00
parent 2d253584ba
commit e54d7d04d7
7 changed files with 399 additions and 14 deletions

View File

@@ -338,7 +338,7 @@ class KitItem(models.Model):
for priority in self.priorities.select_related('product').order_by('priority', 'id')
]
# Иначе возвращаем все товары из группы
return list(self.variant_group.products.filter(is_active=True))
return list(self.variant_group.products.filter(status='active'))
return []

View File

@@ -113,7 +113,7 @@ class KitCostCalculator:
product = kit_item.product
if not product and kit_item.variant_group:
# Берем первый продукт из группы вариантов
product = kit_item.variant_group.products.filter(is_active=True).first()
product = kit_item.variant_group.products.filter(status='active').first()
if product and product.cost_price:
item_cost = product.cost_price
@@ -163,7 +163,7 @@ class KitCostCalculator:
if not product and kit_item.variant_group:
# Берем первый активный продукт из группы вариантов
product = kit_item.variant_group.products.filter(is_active=True).first()
product = kit_item.variant_group.products.filter(status='active').first()
if kit_item.variant_group:
product_name = f"[Варианты] {kit_item.variant_group.name}"

View File

@@ -112,13 +112,13 @@ class ProductCategoryListView(LoginRequiredMixin, ListView):
result.append(tree_item)
# 2. Добавляем активные товары этой категории (отсортированные по имени)
products = category.products.filter(is_active=True).order_by('name')
products = category.products.filter(status='active').order_by('name')
for product in products:
product_item = TreeItem(product, 'product', depth + 1, category.pk)
result.append(product_item)
# 3. Добавляем активные наборы этой категории (отсортированные по имени)
kits = category.kits.filter(is_active=True).order_by('name')
kits = category.kits.filter(status='active').order_by('name')
for kit in kits:
kit_item = TreeItem(kit, 'kit', depth + 1, category.pk)
result.append(kit_item)
@@ -234,8 +234,8 @@ class ProductCategoryDetailView(LoginRequiredMixin, DetailView):
# Получаем дочерние категории
context['children_categories'] = self.object.children.filter(is_active=True)
# Получаем товары в категории
context['products'] = self.object.products.filter(is_active=True)[:20]
context['products_count'] = self.object.products.filter(is_active=True).count()
context['products'] = self.object.products.filter(status='active')[:20]
context['products_count'] = self.object.products.filter(status='active').count()
return context