feat: Add Product Kit creation and editing functionality with new views and templates.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -506,6 +506,9 @@
|
|||||||
<a href="{% url 'products:productkit-detail' object.pk %}" class="btn btn-outline-secondary">
|
<a href="{% url 'products:productkit-detail' object.pk %}" class="btn btn-outline-secondary">
|
||||||
Отмена
|
Отмена
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{% url 'products:productkit-create' %}?copy_from={{ object.pk }}" class="btn btn-warning text-white mx-2">
|
||||||
|
<i class="bi bi-files me-1"></i>Копировать комплект
|
||||||
|
</a>
|
||||||
<button type="submit" class="btn btn-primary px-4">
|
<button type="submit" class="btn btn-primary px-4">
|
||||||
<i class="bi bi-check-circle me-1"></i>Сохранить изменения
|
<i class="bi bi-check-circle me-1"></i>Сохранить изменения
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from django.shortcuts import redirect
|
|||||||
from django.db import transaction, IntegrityError
|
from django.db import transaction, IntegrityError
|
||||||
|
|
||||||
from user_roles.mixins import ManagerOwnerRequiredMixin
|
from user_roles.mixins import ManagerOwnerRequiredMixin
|
||||||
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto, Product, ProductVariantGroup, BouquetName
|
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto, Product, ProductVariantGroup, BouquetName, ProductSalesUnit
|
||||||
from ..forms import ProductKitForm, KitItemFormSetCreate, KitItemFormSetUpdate
|
from ..forms import ProductKitForm, KitItemFormSetCreate, KitItemFormSetUpdate
|
||||||
from .utils import handle_photos
|
from .utils import handle_photos
|
||||||
|
|
||||||
@@ -97,6 +97,28 @@ class ProductKitCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Create
|
|||||||
form_class = ProductKitForm
|
form_class = ProductKitForm
|
||||||
template_name = 'products/productkit_create.html'
|
template_name = 'products/productkit_create.html'
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
initial = super().get_initial()
|
||||||
|
copy_id = self.request.GET.get('copy_from')
|
||||||
|
if copy_id:
|
||||||
|
try:
|
||||||
|
kit = ProductKit.objects.get(pk=copy_id)
|
||||||
|
initial.update({
|
||||||
|
'name': f"{kit.name} (Копия)",
|
||||||
|
'description': kit.description,
|
||||||
|
'short_description': kit.short_description,
|
||||||
|
'categories': list(kit.categories.values_list('pk', flat=True)),
|
||||||
|
'tags': list(kit.tags.values_list('pk', flat=True)),
|
||||||
|
'sale_price': kit.sale_price,
|
||||||
|
'price_adjustment_type': kit.price_adjustment_type,
|
||||||
|
'price_adjustment_value': kit.price_adjustment_value,
|
||||||
|
'external_category': kit.external_category,
|
||||||
|
'status': 'active', # Default to active for new kits
|
||||||
|
})
|
||||||
|
except ProductKit.DoesNotExist:
|
||||||
|
pass
|
||||||
|
return initial
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Обрабатываем POST данные и очищаем ID товаров/комплектов от префиксов.
|
Обрабатываем POST данные и очищаем ID товаров/комплектов от префиксов.
|
||||||
@@ -132,7 +154,6 @@ class ProductKitCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Create
|
|||||||
context['kititem_formset'] = KitItemFormSetCreate(self.request.POST, prefix='kititem')
|
context['kititem_formset'] = KitItemFormSetCreate(self.request.POST, prefix='kititem')
|
||||||
|
|
||||||
# При ошибке валидации: извлекаем выбранные товары для предзагрузки в Select2
|
# При ошибке валидации: извлекаем выбранные товары для предзагрузки в Select2
|
||||||
from ..models import Product, ProductVariantGroup, ProductSalesUnit
|
|
||||||
selected_products = {}
|
selected_products = {}
|
||||||
selected_variants = {}
|
selected_variants = {}
|
||||||
selected_sales_units = {}
|
selected_sales_units = {}
|
||||||
@@ -195,7 +216,86 @@ class ProductKitCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Create
|
|||||||
context['selected_variants'] = selected_variants
|
context['selected_variants'] = selected_variants
|
||||||
context['selected_sales_units'] = selected_sales_units
|
context['selected_sales_units'] = selected_sales_units
|
||||||
else:
|
else:
|
||||||
context['kititem_formset'] = KitItemFormSetCreate(prefix='kititem')
|
# COPY KIT LOGIC
|
||||||
|
copy_id = self.request.GET.get('copy_from')
|
||||||
|
initial_items = []
|
||||||
|
selected_products = {}
|
||||||
|
selected_variants = {}
|
||||||
|
selected_sales_units = {}
|
||||||
|
|
||||||
|
if copy_id:
|
||||||
|
try:
|
||||||
|
source_kit = ProductKit.objects.get(pk=copy_id)
|
||||||
|
for item in source_kit.kit_items.all():
|
||||||
|
item_data = {
|
||||||
|
'quantity': item.quantity,
|
||||||
|
# Delete flag is false by default
|
||||||
|
}
|
||||||
|
|
||||||
|
form_prefix = f"kititem-{len(initial_items)}"
|
||||||
|
|
||||||
|
if item.product:
|
||||||
|
item_data['product'] = item.product
|
||||||
|
# Select2 prefill
|
||||||
|
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.sales_unit:
|
||||||
|
item_data['sales_unit'] = item.sales_unit
|
||||||
|
# Select2 prefill
|
||||||
|
sales_unit = item.sales_unit
|
||||||
|
text = f"{sales_unit.name} ({sales_unit.product.name})"
|
||||||
|
actual_price = sales_unit.sale_price if sales_unit.sale_price else sales_unit.price
|
||||||
|
selected_sales_units[f"{form_prefix}-sales_unit"] = {
|
||||||
|
'id': sales_unit.id,
|
||||||
|
'text': text,
|
||||||
|
'price': str(sales_unit.price) if sales_unit.price else None,
|
||||||
|
'actual_price': str(actual_price) if actual_price else '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.variant_group:
|
||||||
|
item_data['variant_group'] = item.variant_group
|
||||||
|
# Select2 prefill
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
initial_items.append(item_data)
|
||||||
|
except ProductKit.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if initial_items:
|
||||||
|
context['kititem_formset'] = KitItemFormSetCreate(
|
||||||
|
prefix='kititem',
|
||||||
|
initial=initial_items
|
||||||
|
)
|
||||||
|
context['kititem_formset'].extra = len(initial_items)
|
||||||
|
else:
|
||||||
|
context['kititem_formset'] = KitItemFormSetCreate(prefix='kititem')
|
||||||
|
|
||||||
|
# Pass Select2 data to context
|
||||||
|
context['selected_products'] = selected_products
|
||||||
|
context['selected_variants'] = selected_variants
|
||||||
|
context['selected_sales_units'] = selected_sales_units
|
||||||
|
|
||||||
# Количество названий букетов в базе
|
# Количество названий букетов в базе
|
||||||
context['bouquet_names_count'] = BouquetName.objects.count()
|
context['bouquet_names_count'] = BouquetName.objects.count()
|
||||||
|
|||||||
Reference in New Issue
Block a user