Реализовано управление активностью тегов товаров и комплектов
## Что сделано: ### 1. Фильтрация тегов по активности - ProductForm и ProductKitForm показывают только активные теги в селектах - ProductListView, ProductKitListView передают только активные теги в контекст фильтров ### 2. Отображение тегов на страницах товаров/комплектов - product_detail.html отображает только активные теги - productkit_detail.html отображает только активные теги ### 3. Логика отображения в деталях тега - Для активного тега: показываются только активные товары/комплекты - Для неактивного тега: показываются ВСЕ товары/комплекты (для возможности ручной очистки) ### 4. API endpoint для переключения статуса - Новый endpoint toggle_tag_status_api в api_views.py - POST /products/api/tags/<id>/toggle/ - Переключает is_active и возвращает новый статус ### 5. AJAX toggle switch в таблице тегов - Заменены бейджи на toggle switch в tag_list.html - Переключатель в 1.3x больше (масштабирование через CSS) - Мгновенное обновление без перезагрузки страницы - Показывает сообщение об успехе/ошибке ### 6. Связь в БД остаётся неизменной - При деактивации тег остаётся привязан к товарам в БД - Просто скрывается в интерфейсе - При реактивации вновь становится видимым 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ from django.urls import reverse_lazy
|
||||
from django.shortcuts import redirect
|
||||
from django.db import transaction
|
||||
|
||||
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto
|
||||
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto, Product, ProductVariantGroup
|
||||
from ..forms import ProductKitForm, KitItemFormSetCreate, KitItemFormSetUpdate
|
||||
from .utils import handle_photos
|
||||
|
||||
@@ -52,7 +52,7 @@ class ProductKitListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
# Данные для фильтров
|
||||
context['filters'] = {
|
||||
'categories': ProductCategory.objects.filter(is_active=True),
|
||||
'tags': ProductTag.objects.all(),
|
||||
'tags': ProductTag.objects.filter(is_active=True),
|
||||
'current': {
|
||||
'search': self.request.GET.get('search', ''),
|
||||
'category': self.request.GET.get('category', ''),
|
||||
@@ -146,10 +146,20 @@ class ProductKitCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateVi
|
||||
|
||||
if '-variant_group' in key and value:
|
||||
try:
|
||||
variant_group = ProductVariantGroup.objects.get(id=value)
|
||||
variant_group = ProductVariantGroup.objects.prefetch_related(
|
||||
'items__product'
|
||||
).get(id=value)
|
||||
|
||||
variant_price = variant_group.price or 0
|
||||
count = variant_group.items.count()
|
||||
|
||||
selected_variants[key] = {
|
||||
'id': variant_group.id,
|
||||
'text': variant_group.name
|
||||
'text': f"{variant_group.name} ({count} вариантов)",
|
||||
'price': str(variant_price),
|
||||
'actual_price': str(variant_price),
|
||||
'type': 'variant',
|
||||
'count': count
|
||||
}
|
||||
except ProductVariantGroup.DoesNotExist:
|
||||
pass
|
||||
@@ -248,9 +258,98 @@ class ProductKitUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateVi
|
||||
|
||||
if self.request.POST:
|
||||
context['kititem_formset'] = KitItemFormSetUpdate(self.request.POST, instance=self.object, prefix='kititem')
|
||||
|
||||
# При ошибке валидации - подготавливаем данные для Select2
|
||||
selected_products = {}
|
||||
selected_variants = {}
|
||||
|
||||
for key, value in self.request.POST.items():
|
||||
if '-product' in key and value:
|
||||
try:
|
||||
# Очищаем ID от префикса если есть
|
||||
numeric_value = value.split('_')[1] if '_' in value else value
|
||||
product = Product.objects.get(id=numeric_value)
|
||||
|
||||
text = product.name
|
||||
if product.sku:
|
||||
text += f" ({product.sku})"
|
||||
|
||||
actual_price = product.sale_price if product.sale_price else product.price
|
||||
selected_products[key] = {
|
||||
'id': product.id,
|
||||
'text': text,
|
||||
'price': str(product.price) if product.price else None,
|
||||
'actual_price': str(actual_price) if actual_price else '0'
|
||||
}
|
||||
except Product.DoesNotExist:
|
||||
pass
|
||||
|
||||
if '-variant_group' in key and value:
|
||||
try:
|
||||
variant_group = ProductVariantGroup.objects.prefetch_related(
|
||||
'items__product'
|
||||
).get(id=value)
|
||||
|
||||
variant_price = variant_group.price or 0
|
||||
count = variant_group.items.count()
|
||||
|
||||
selected_variants[key] = {
|
||||
'id': variant_group.id,
|
||||
'text': f"{variant_group.name} ({count} вариантов)",
|
||||
'price': str(variant_price),
|
||||
'actual_price': str(variant_price),
|
||||
'type': 'variant',
|
||||
'count': count
|
||||
}
|
||||
except ProductVariantGroup.DoesNotExist:
|
||||
pass
|
||||
|
||||
context['selected_products'] = selected_products
|
||||
context['selected_variants'] = selected_variants
|
||||
else:
|
||||
context['kititem_formset'] = KitItemFormSetUpdate(instance=self.object, prefix='kititem')
|
||||
|
||||
# Подготавливаем данные для предзагрузки в Select2
|
||||
selected_products = {}
|
||||
selected_variants = {}
|
||||
|
||||
for item in self.object.kit_items.all():
|
||||
form_prefix = f"kititem-{item.id}"
|
||||
|
||||
if item.product:
|
||||
product = item.product
|
||||
text = product.name
|
||||
if product.sku:
|
||||
text += f" ({product.sku})"
|
||||
|
||||
actual_price = product.sale_price if product.sale_price else product.price
|
||||
selected_products[f"{form_prefix}-product"] = {
|
||||
'id': product.id,
|
||||
'text': text,
|
||||
'price': str(product.price) if product.price else None,
|
||||
'actual_price': str(actual_price) if actual_price else '0'
|
||||
}
|
||||
|
||||
if item.variant_group:
|
||||
variant_group = ProductVariantGroup.objects.prefetch_related(
|
||||
'items__product'
|
||||
).get(id=item.variant_group.id)
|
||||
|
||||
variant_price = variant_group.price or 0
|
||||
count = variant_group.items.count()
|
||||
|
||||
selected_variants[f"{form_prefix}-variant_group"] = {
|
||||
'id': variant_group.id,
|
||||
'text': f"{variant_group.name} ({count} вариантов)",
|
||||
'price': str(variant_price),
|
||||
'actual_price': str(variant_price),
|
||||
'type': 'variant',
|
||||
'count': count
|
||||
}
|
||||
|
||||
context['selected_products'] = selected_products
|
||||
context['selected_variants'] = selected_variants
|
||||
|
||||
context['productkit_photos'] = self.object.photos.all().order_by('order', 'created_at')
|
||||
context['photos_count'] = self.object.photos.count()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user