From a1df188b2a6329bcb7b5cc998b946a6d1f68625d Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Sat, 8 Nov 2025 15:19:56 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=BE=20=D0=BF=D1=80=D0=B5=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=80?= =?UTF-8?q?=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=BF=D0=BB=D0=B5=D0=BA=D1=82=D0=BE=D0=B2=20=D0=B2=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=BD=D1=8B=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Views (products/views/productkit_views.py): - ProductKitMakePermanentView: view для преобразования временного комплекта * Доступен только для временных комплектов (is_temporary=True) * Позволяет отредактировать название, описание, категории, теги, цену * Вызывает метод make_permanent() модели * Перенаправляет на детальную страницу комплекта после успеха URLs (products/urls.py): - /products/kits//make-permanent/ - страница преобразования Templates: - productkit_make_permanent.html: форма преобразования с составом и ценой - order_detail.html: добавлена кнопка "Сделать постоянным" для временных комплектов Теперь флорист может: 1. Увидеть временный комплект в заказе с badge "Временный" 2. Нажать "Сделать постоянным" 3. Отредактировать название, добавить категории 4. Сохранить - комплект появится в каталоге 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../orders/templates/orders/order_detail.html | 4 + ..._is_temporary_productkit_order_and_more.py | 35 +++++ .../products/productkit_make_permanent.html | 148 ++++++++++++++++++ myproject/products/urls.py | 1 + myproject/products/views/productkit_views.py | 37 +++++ 5 files changed, 225 insertions(+) create mode 100644 myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py create mode 100644 myproject/products/templates/products/productkit_make_permanent.html diff --git a/myproject/orders/templates/orders/order_detail.html b/myproject/orders/templates/orders/order_detail.html index 08e88f1..6ed42d4 100644 --- a/myproject/orders/templates/orders/order_detail.html +++ b/myproject/orders/templates/orders/order_detail.html @@ -201,6 +201,10 @@ Временный
Создан специально для этого заказа +
+ + Сделать постоянным + {% endif %} {{ item.quantity }} diff --git a/myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py b/myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py new file mode 100644 index 0000000..42aa7d1 --- /dev/null +++ b/myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py @@ -0,0 +1,35 @@ +# Generated by Django 5.0.10 on 2025-11-08 11:52 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('orders', '0004_orderitem_is_custom_price'), + ('products', '0005_remove_kititem_notes'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='productkit', + name='is_temporary', + field=models.BooleanField(default=False, help_text='Временные комплекты не показываются в каталоге и создаются для конкретного заказа', verbose_name='Временный комплект'), + ), + migrations.AddField( + model_name='productkit', + name='order', + field=models.ForeignKey(blank=True, help_text='Заказ, для которого создан временный комплект', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='temporary_kits', to='orders.order', verbose_name='Заказ'), + ), + migrations.AddIndex( + model_name='productkit', + index=models.Index(fields=['is_temporary'], name='products_pr_is_temp_e407a2_idx'), + ), + migrations.AddIndex( + model_name='productkit', + index=models.Index(fields=['order'], name='products_pr_order_i_2b5675_idx'), + ), + ] diff --git a/myproject/products/templates/products/productkit_make_permanent.html b/myproject/products/templates/products/productkit_make_permanent.html new file mode 100644 index 0000000..1572862 --- /dev/null +++ b/myproject/products/templates/products/productkit_make_permanent.html @@ -0,0 +1,148 @@ +{% extends 'base.html' %} + +{% block title %}Преобразовать в постоянный комплект{% endblock %} + +{% block content %} +
+
+
+

Преобразовать временный комплект в постоянный

+

+ Этот комплект был создан специально для заказа. Вы можете добавить его в каталог, + отредактировав название, описание и добавив категории. +

+
+
+ +
+
+ +
+
+
Информация о комплекте
+
+
+
+ {% csrf_token %} + +
+ + {{ form.name }} + {% if form.name.errors %} +
+ {{ form.name.errors }} +
+ {% endif %} +
+ +
+ + {{ form.description }} + {% if form.description.errors %} +
+ {{ form.description.errors }} +
+ {% endif %} +
+ +
+ + {{ form.categories }} + {% if form.categories.errors %} +
+ {{ form.categories.errors }} +
+ {% endif %} + + Выберите категории, к которым относится этот комплект + +
+ +
+ + {{ form.tags }} + {% if form.tags.errors %} +
+ {{ form.tags.errors }} +
+ {% endif %} +
+ +
+ + {{ form.sale_price }} + {% if form.sale_price.errors %} +
+ {{ form.sale_price.errors }} +
+ {% endif %} + + Опционально. Если указано, комплект будет продаваться по этой цене. + +
+ +
+ + Отмена + + +
+
+
+
+
+ +
+ +
+
+
Состав комплекта
+
+
+ + + + + + + + + {% for kit_item in kit_items %} + + + + + {% endfor %} + +
ТоварКоличество
+ {% if kit_item.variant_group %} + [Варианты] {{ kit_item.variant_group.name }} + {% elif kit_item.product %} + {{ kit_item.product.name }} + {% endif %} + {{ kit_item.quantity }}
+
+
+ + +
+
+
Ценообразование
+
+
+
+
Базовая цена:
+
{{ kit.base_price }} руб.
+
+
+
Итоговая цена:
+
{{ kit.actual_price }} руб.
+
+
+
+
+
+
+{% endblock %} diff --git a/myproject/products/urls.py b/myproject/products/urls.py index 613cf68..8b5b394 100644 --- a/myproject/products/urls.py +++ b/myproject/products/urls.py @@ -26,6 +26,7 @@ urlpatterns = [ path('kits//', views.ProductKitDetailView.as_view(), name='productkit-detail'), path('kits//update/', views.ProductKitUpdateView.as_view(), name='productkit-update'), path('kits//delete/', views.ProductKitDeleteView.as_view(), name='productkit-delete'), + path('kits//make-permanent/', views.ProductKitMakePermanentView.as_view(), name='productkit-make-permanent'), # Photo management for ProductKit path('kits/photo//delete/', views.productkit_photo_delete, name='productkit-photo-delete'), diff --git a/myproject/products/views/productkit_views.py b/myproject/products/views/productkit_views.py index ae1c611..f6aa2e3 100644 --- a/myproject/products/views/productkit_views.py +++ b/myproject/products/views/productkit_views.py @@ -304,3 +304,40 @@ class ProductKitDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteVi def get_success_url(self): messages.success(self.request, f'Комплект "{self.object.name}" успешно удален!') return reverse_lazy('products:productkit-list') + + +class ProductKitMakePermanentView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): + """ + View для преобразования временного комплекта в постоянный. + Позволяет отредактировать название, добавить категории, теги перед сохранением. + """ + model = ProductKit + template_name = 'products/productkit_make_permanent.html' + context_object_name = 'kit' + permission_required = 'products.change_productkit' + fields = ['name', 'description', 'categories', 'tags', 'sale_price'] + + def get_queryset(self): + # Только временные комплекты можно преобразовать + return super().get_queryset().filter(is_temporary=True) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['kit_items'] = self.object.kit_items.all().select_related('product', 'variant_group') + context['productkit_photos'] = self.object.photos.all().order_by('order', 'created_at') + return context + + def form_valid(self, form): + # Преобразуем в постоянный + if self.object.make_permanent(): + messages.success( + self.request, + f'Комплект "{self.object.name}" преобразован в постоянный и теперь доступен в каталоге!' + ) + else: + messages.warning(self.request, f'Комплект "{self.object.name}" уже является постоянным.') + + return super().form_valid(form) + + def get_success_url(self): + return reverse_lazy('products:productkit-detail', kwargs={'pk': self.object.pk})