from django.views.generic import ListView, DetailView, DetailView from programmer.mixins import MenuContextMixin, BreadcrumbMixin from .models import Product, ProductCategory, Configuration from django.shortcuts import get_object_or_404 from django.http import Http404 from programmer.forms import CallbackForm from .forms import OrderForm from django.contrib import messages from django.shortcuts import redirect from programmer.utils.email_notifications import send_order_notification, send_order_notification_async from django.utils.decorators import method_decorator from django.contrib.admin.views.decorators import staff_member_required class ProductListView(MenuContextMixin, BreadcrumbMixin, ListView): model = Product template_name = 'products/product_list.html' context_object_name = 'products' paginate_by = 12 def get_breadcrumbs(self): return [{'title': 'Продукты', 'url_name': None}] def get_queryset(self): qs = ( Product.objects .filter(is_published=True) .select_related('category') .prefetch_related('configurations') ) # Фильтр по категории category_slug = self.request.GET.get('category') if category_slug: self.current_category = get_object_or_404(ProductCategory, slug=category_slug) qs = qs.filter(category=self.current_category) else: self.current_category = None # Фильтр по конфигурации config_slug = self.request.GET.get('configuration') if config_slug: self.current_configuration = get_object_or_404(Configuration, slug=config_slug) qs = qs.filter(configurations=self.current_configuration) else: self.current_configuration = None # ordering уже задан в Meta, явный вызов order_by не нужен, # но оставляем для явности и возможного расширения сортировки return qs.order_by('-time_create') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['categories'] = ProductCategory.objects.all() context['configurations'] = Configuration.objects.all() context['current_category'] = self.current_category context['current_configuration'] = self.current_configuration context['title'] = "Продукты 1С | Модули и расширения | С.Н.А. Технологии" context['meta_description'] = ( "Готовые модули, расширения и программные продукты для 1С: Предприятие. " "Фильтрация по конфигурациям и категориям." ) context['meta_keywords'] = "1С модули, расширения 1С, программы 1С, купить 1С, продукты 1С" form = CallbackForm() if self.request.user.is_authenticated: if 'captcha' in form.fields: del form.fields['captcha'] context.update({ 'form': form, }) return context class ProductDetailView(MenuContextMixin, BreadcrumbMixin, DetailView): model = Product template_name = 'products/product_detail.html' context_object_name = 'product' def get_object(self, queryset=None): product = super().get_object(queryset=queryset) if not product.is_published: raise Http404("Продукт не найден") return product def get_breadcrumbs(self): product = self.object return [ {'title': 'Продукты', 'url_name': 'products:product_list'}, { 'title': product.category.name, 'url_name': 'products:product_list', 'extra_params': f'?category={product.category.slug}', }, {'title': product.title, 'url_name': None}, ] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) product = self.object context['title'] = product.get_seo_title() context['meta_description'] = product.get_seo_description() context['meta_keywords'] = ( f"1С, {product.category.name}, " f"{', '.join(c.name for c in product.configurations.all())}" ) # Форма заказа с предзаполнением для авторизованных initial = {} if self.request.user.is_authenticated: user = self.request.user initial['name'] = user.get_full_name() or user.username initial['email'] = user.email # Если есть профиль и телефон if hasattr(user, 'profile') and user.profile.phone: initial['phone'] = user.profile.phone order_form = OrderForm(initial=initial) order_form.fields['configuration'].queryset = product.configurations.all() context['order_form'] = order_form form = CallbackForm() if self.request.user.is_authenticated: if 'captcha' in form.fields: del form.fields['captcha'] context.update({ 'form': form, }) return context @method_decorator(staff_member_required, name='dispatch') class ProductDraftPreviewView(DetailView): model = Product template_name = 'products/product_detail.html' context_object_name = 'product' def get_queryset(self): # Показываем все продукты (включая неопубликованные) только для персонала return Product.objects.all() def order_create(request, slug): product = get_object_or_404(Product, slug=slug, is_published=True) if request.method == 'POST': form = OrderForm(request.POST) # Переопределяем queryset для поля configuration – только те, что связаны с продуктом form.fields['configuration'].queryset = product.configurations.all() if form.is_valid(): order = form.save(commit=False) order.product = product # Если пользователь авторизован, связываем заказ с ним if request.user.is_authenticated: order.user = request.user # Можно предзаполнить имя и email из профиля, если они пустые в форме if not order.name: order.name = request.user.get_full_name() or request.user.username if not order.email: order.email = request.user.email order.save() # Сохраняем выбранную конфигурацию (уже сохранена в форме) # success = send_order_notification(order) # if success: # order.notification_sent = True # order.save(update_fields=['notification_sent']) send_order_notification_async(order) messages.success(request, '✅ Ваш заказ принят! Мы свяжемся с вами в ближайшее время.') return redirect('products:product_detail', slug=slug) else: for field, errors in form.errors.items(): for error in errors: messages.error(request, f'❌ Ошибка в поле "{field}": {error}') return redirect('products:product_detail', slug=slug)