feat: Add product kit creation view and its corresponding template.

This commit is contained in:
2026-01-25 00:50:38 +03:00
parent 41e6c33683
commit 6cd0a945de
2 changed files with 81 additions and 1 deletions

View File

@@ -1373,12 +1373,38 @@
reader.readAsDataURL(file); reader.readAsDataURL(file);
}); });
} else { } else {
photoPreviewContainer.style.display = 'none'; photoPreviewContainer.style.display = 'none'; // Only hide if no source photos too (will check later)
photoPreview.innerHTML = ''; photoPreview.innerHTML = '';
// Re-render source photos if they exist and we just cleared new files
if (document.querySelectorAll('.source-photo-item').length > 0) {
photoPreviewContainer.style.display = 'block';
}
} }
}); });
} }
// Render source photos if present
{% if source_photos %}
photoPreviewContainer.style.display = 'block';
{% for photo in source_photos %}
(function () {
const col = document.createElement('div');
col.className = 'col-4 col-md-3 col-lg-2 source-photo-item';
col.innerHTML = `
<div class="card position-relative border-0 shadow-sm">
<img src="{{ photo.image.url }}" class="card-img-top" alt="Source Photo">
<button type="button" class="btn btn-sm btn-danger position-absolute top-0 end-0 m-1" onclick="this.closest('.col-4').remove();">
<i class="bi bi-x"></i>
</button>
<input type="hidden" name="copied_photos" value="{{ photo.id }}">
</div>
`;
photoPreview.appendChild(col);
})();
{% endfor %}
{% endif %}
window.removePhoto = function (index) { window.removePhoto = function (index) {
selectedFiles.splice(index, 1); selectedFiles.splice(index, 1);
const dataTransfer = new DataTransfer(); const dataTransfer = new DataTransfer();

View File

@@ -12,6 +12,7 @@ from user_roles.mixins import ManagerOwnerRequiredMixin
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto, Product, ProductVariantGroup, BouquetName, ProductSalesUnit 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
import os
class ProductKitListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, ListView): class ProductKitListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, ListView):
@@ -296,6 +297,17 @@ class ProductKitCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Create
context['selected_products'] = selected_products context['selected_products'] = selected_products
context['selected_variants'] = selected_variants context['selected_variants'] = selected_variants
context['selected_sales_units'] = selected_sales_units context['selected_sales_units'] = selected_sales_units
# Pass source photos if copying
if copy_id:
try:
source_kit = ProductKit.objects.prefetch_related('photos').get(pk=copy_id)
photos = source_kit.photos.all().order_by('order')
print(f"DEBUG: Found {photos.count()} source photos for kit {copy_id}")
context['source_photos'] = photos
except ProductKit.DoesNotExist:
print(f"DEBUG: Source kit {copy_id} not found")
pass
# Количество названий букетов в базе # Количество названий букетов в базе
context['bouquet_names_count'] = BouquetName.objects.count() context['bouquet_names_count'] = BouquetName.objects.count()
@@ -335,6 +347,48 @@ class ProductKitCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Create
# Обработка фотографий # Обработка фотографий
handle_photos(self.request, self.object, ProductKitPhoto, 'kit') handle_photos(self.request, self.object, ProductKitPhoto, 'kit')
# Handle copied photos
copied_photo_ids = self.request.POST.getlist('copied_photos')
print(f"DEBUG: copied_photo_ids in POST: {copied_photo_ids}")
if copied_photo_ids:
from django.core.files.base import ContentFile
original_photos = ProductKitPhoto.objects.filter(id__in=copied_photo_ids)
print(f"DEBUG: Found {original_photos.count()} original photos to copy")
# Get max order from existing photos (uploaded via handle_photos)
from django.db.models import Max
max_order = self.object.photos.aggregate(Max('order'))['order__max']
next_order = 0 if max_order is None else max_order + 1
print(f"DEBUG: Starting order for copies: {next_order}")
for photo in original_photos:
try:
# Open the original image file
if photo.image:
print(f"DEBUG: Processing photo {photo.id}: {photo.image.name}")
with photo.image.open('rb') as f:
image_content = f.read()
# Create a new ContentFile
new_image_name = f"copy_{self.object.id}_{os.path.basename(photo.image.name)}"
print(f"DEBUG: New image name: {new_image_name}")
# Create new photo instance
new_photo = ProductKitPhoto(kit=self.object, order=next_order)
# Save the image file (this also saves the model instance)
new_photo.image.save(new_image_name, ContentFile(image_content))
print(f"DEBUG: Successfully saved copy for photo {photo.id}")
next_order += 1
else:
print(f"DEBUG: Photo {photo.id} has no image file")
except Exception as e:
print(f"Error copying photo {photo.id}: {e}")
import traceback
traceback.print_exc()
continue
messages.success( messages.success(
self.request, self.request,
f'Комплект "{self.object.name}" успешно создан!' f'Комплект "{self.object.name}" успешно создан!'