# -*- coding: utf-8 -*- from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from django.core.paginator import Paginator from django.http import JsonResponse from django.db import transaction from django.views.decorators.http import require_http_methods from .models import Order, OrderItem from .forms import OrderForm, OrderItemFormSet from .filters import OrderFilter from products.models import ProductKit, KitItem, Product def order_list(request): """ Список всех заказов с фильтрацией и поиском Использует django-filter для фильтрации данных """ # Базовый queryset с оптимизацией запросов orders = Order.objects.select_related( 'customer', 'delivery_address', 'pickup_shop' ).all() # Применяем фильтры через django-filter order_filter = OrderFilter(request.GET, queryset=orders) # Сортировка filtered_orders = order_filter.qs.order_by('-created_at') # Пагинация paginator = Paginator(filtered_orders, 25) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) context = { 'filter': order_filter, 'page_obj': page_obj, 'status_choices': Order.STATUS_CHOICES, } return render(request, 'orders/order_list.html', context) def order_detail(request, pk): """Детальная информация о заказе""" order = get_object_or_404( Order.objects.select_related('customer', 'delivery_address', 'pickup_shop', 'modified_by') .prefetch_related('items__product', 'items__product_kit', 'payments__created_by'), pk=pk ) context = { 'order': order, } return render(request, 'orders/order_detail.html', context) def order_create(request): """Создание нового заказа""" if request.method == 'POST': form = OrderForm(request.POST) formset = OrderItemFormSet(request.POST) if form.is_valid() and formset.is_valid(): order = form.save(commit=False) order.save() # Сохраняем позиции заказа formset.instance = order formset.save() # Пересчитываем итоговую сумму order.calculate_total() order.save() messages.success(request, f'Заказ #{order.order_number} успешно создан!') return redirect('orders:order-detail', pk=order.pk) else: messages.error(request, 'Пожалуйста, исправьте ошибки в форме.') else: form = OrderForm() formset = OrderItemFormSet() context = { 'form': form, 'formset': formset, 'title': 'Создание заказа', 'button_text': 'Создать заказ', } return render(request, 'orders/order_form.html', context) def order_update(request, pk): """Редактирование заказа""" order = get_object_or_404(Order, pk=pk) if request.method == 'POST': form = OrderForm(request.POST, instance=order) formset = OrderItemFormSet(request.POST, instance=order) if form.is_valid() and formset.is_valid(): order = form.save() formset.save() # Пересчитываем итоговую сумму order.calculate_total() order.save() messages.success(request, f'Заказ #{order.order_number} успешно обновлен!') return redirect('orders:order-detail', pk=order.pk) else: messages.error(request, 'Пожалуйста, исправьте ошибки в форме.') else: form = OrderForm(instance=order) formset = OrderItemFormSet(instance=order) context = { 'form': form, 'formset': formset, 'order': order, 'title': f'Редактирование заказа #{order.order_number}', 'button_text': 'Сохранить изменения', } return render(request, 'orders/order_form.html', context) def order_delete(request, pk): """Удаление заказа с подтверждением""" order = get_object_or_404(Order, pk=pk) if request.method == 'POST': order_number = order.order_number order.delete() messages.success(request, f'Заказ #{order_number} успешно удален.') return redirect('orders:order-list') context = { 'order': order, } return render(request, 'orders/order_confirm_delete.html', context) # === ВРЕМЕННЫЕ КОМПЛЕКТЫ === @require_http_methods(["POST"]) def create_temporary_kit(request): """ AJAX endpoint для создания временного комплекта. Используется при оформлении заказа для создания букета "на лету". Принимает JSON: { "name": "Букет для Анны", "description": "Красные розы и белые лилии", "order_id": 123, // опционально, если заказ уже создан "components": [ {"product_id": 1, "quantity": "5"}, {"product_id": 2, "quantity": "3"} ] } Возвращает JSON: { "success": true, "kit_id": 456, "kit_name": "Букет для Анны", "kit_sku": "KIT-000456", "kit_price": "1500.00", "message": "Временный комплект создан успешно" } """ import json from decimal import Decimal try: data = json.loads(request.body) name = data.get('name', '').strip() description = data.get('description', '').strip() order_id = data.get('order_id') components = data.get('components', []) # Валидация if not name: return JsonResponse({ 'success': False, 'error': 'Необходимо указать название комплекта' }, status=400) if not components or len(components) == 0: return JsonResponse({ 'success': False, 'error': 'Комплект должен содержать хотя бы один компонент' }, status=400) # Создаем временный комплект with transaction.atomic(): # Получаем заказ если указан order = None if order_id: try: order = Order.objects.get(pk=order_id) except Order.DoesNotExist: return JsonResponse({ 'success': False, 'error': f'Заказ #{order_id} не найден' }, status=404) # Создаем комплект kit = ProductKit.objects.create( name=name, description=description, is_temporary=True, is_active=True, order=order, price_adjustment_type='none' ) # Добавляем компоненты for component in components: product_id = component.get('product_id') quantity = component.get('quantity') if not product_id or not quantity: continue try: product = Product.objects.get(pk=product_id) KitItem.objects.create( kit=kit, product=product, quantity=Decimal(str(quantity)) ) except Product.DoesNotExist: # Пропускаем несуществующие товары continue except (ValueError, TypeError): # Пропускаем некорректные количества continue # Пересчитываем цену комплекта kit.recalculate_base_price() return JsonResponse({ 'success': True, 'kit_id': kit.id, 'kit_name': kit.name, 'kit_sku': kit.sku, 'kit_price': str(kit.actual_price), 'message': f'Временный комплект "{kit.name}" создан успешно' }) except json.JSONDecodeError: return JsonResponse({ 'success': False, 'error': 'Некорректный JSON' }, status=400) except Exception as e: return JsonResponse({ 'success': False, 'error': f'Ошибка при создании комплекта: {str(e)}' }, status=500)