# -*- coding: utf-8 -*- from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib import messages from django.shortcuts import render, redirect, get_object_or_404 from django.db.models import Count, Q from django.views.generic import ListView, CreateView, UpdateView, DeleteView, View from django.urls import reverse_lazy from django.utils.decorators import method_decorator from django.http import JsonResponse from inventory.models import Showcase, Reservation from inventory.forms_showcase import ShowcaseForm @method_decorator(login_required, name='dispatch') class ShowcaseListView(ListView): """ Список всех витрин с группировкой по складам. Отображает информацию о количестве активных резервов на каждой витрине. """ model = Showcase template_name = 'inventory/showcase/list.html' context_object_name = 'showcases' def get_queryset(self): """ Получаем витрины с аннотацией количества активных резервов. Сортируем по складу и названию. """ queryset = Showcase.objects.select_related('warehouse').annotate( active_reservations_count=Count( 'reservations', filter=Q(reservations__status='reserved') ) ).order_by('warehouse__name', 'name') # Фильтрация по складу, если указан GET-параметр warehouse_id = self.request.GET.get('warehouse') if warehouse_id: queryset = queryset.filter(warehouse_id=warehouse_id) # Фильтрация по статусу активности is_active = self.request.GET.get('is_active') if is_active == '1': queryset = queryset.filter(is_active=True) elif is_active == '0': queryset = queryset.filter(is_active=False) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = 'Витрины' # Добавляем информацию для фильтров from inventory.models import Warehouse context['warehouses'] = Warehouse.objects.filter(is_active=True).order_by('name') return context @method_decorator(login_required, name='dispatch') class ShowcaseCreateView(CreateView): """ Создание новой витрины. """ model = Showcase form_class = ShowcaseForm template_name = 'inventory/showcase/form.html' success_url = reverse_lazy('inventory:showcase-list') def form_valid(self, form): """Сохраняем витрину и показываем сообщение об успехе""" response = super().form_valid(form) messages.success( self.request, f'Витрина "{self.object.name}" успешно создана на складе "{self.object.warehouse.name}"' ) return response def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = 'Создание витрины' context['form_title'] = 'Новая витрина' context['submit_text'] = 'Создать витрину' return context @method_decorator(login_required, name='dispatch') class ShowcaseUpdateView(UpdateView): """ Редактирование существующей витрины. """ model = Showcase form_class = ShowcaseForm template_name = 'inventory/showcase/form.html' success_url = reverse_lazy('inventory:showcase-list') def form_valid(self, form): """Сохраняем изменения и показываем сообщение об успехе""" response = super().form_valid(form) messages.success( self.request, f'Витрина "{self.object.name}" успешно обновлена' ) return response def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = f'Редактирование витрины: {self.object.name}' context['form_title'] = f'Редактирование: {self.object.name}' context['submit_text'] = 'Сохранить изменения' # Добавляем информацию о резервах на витрине context['active_reservations_count'] = Reservation.objects.filter( showcase=self.object, status='reserved' ).count() return context @method_decorator(login_required, name='dispatch') class ShowcaseDeleteView(DeleteView): """ Удаление витрины с подтверждением. Проверяет наличие активных резервов перед удалением. """ model = Showcase template_name = 'inventory/showcase/delete.html' success_url = reverse_lazy('inventory:showcase-list') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['title'] = f'Удаление витрины: {self.object.name}' # Проверяем наличие активных резервов active_reservations = Reservation.objects.filter( showcase=self.object, status='reserved' ).select_related('product') context['active_reservations'] = active_reservations context['has_active_reservations'] = active_reservations.exists() return context def delete(self, request, *args, **kwargs): """Проверяем наличие активных резервов перед удалением""" showcase = self.get_object() # Проверка активных резервов active_reservations_count = Reservation.objects.filter( showcase=showcase, status='reserved' ).count() if active_reservations_count > 0: messages.error( request, f'Невозможно удалить витрину "{showcase.name}": ' f'на ней есть {active_reservations_count} активных резервов. ' 'Сначала освободите или продайте зарезервированные товары.' ) return redirect('inventory:showcase-delete', pk=showcase.pk) # Удаляем витрину showcase_name = showcase.name response = super().delete(request, *args, **kwargs) messages.success( request, f'Витрина "{showcase_name}" успешно удалена' ) return response @method_decorator(login_required, name='dispatch') class SetDefaultShowcaseView(LoginRequiredMixin, View): """ Установка витрины по умолчанию для её склада. Обрабатывает POST запрос от AJAX и возвращает JSON ответ. """ def post(self, request, pk): """ Установить витрину с заданным pk как витрину по умолчанию для её склада """ try: showcase = get_object_or_404(Showcase, pk=pk, is_active=True) # Установить эту витрину как по умолчанию # (метод save() в модели автоматически снимет флаг с других витрин этого склада) showcase.is_default = True showcase.save() return JsonResponse({ 'status': 'success', 'message': f'Витрина "{showcase.name}" на складе "{showcase.warehouse.name}" установлена по умолчанию', 'showcase_id': showcase.id, 'showcase_name': showcase.name, 'warehouse_id': showcase.warehouse.id, 'warehouse_name': showcase.warehouse.name }) except Showcase.DoesNotExist: return JsonResponse({ 'status': 'error', 'message': 'Витрина не найдена' }, status=404) except Exception as e: return JsonResponse({ 'status': 'error', 'message': f'Ошибка при установке витрины по умолчанию: {str(e)}' }, status=500)