From 3b4785e2ad4d68c841fd73fc31f546a02b05d286 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Wed, 26 Nov 2025 06:27:27 +0300 Subject: [PATCH] Fix: Implement proper deletion of order items with confirmation dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes deletion functionality for order items across frontend and backend: - Remove restriction preventing deletion of last item - Add confirmation dialog before deletion - Properly track and send deleted item IDs to backend via autosave - Update backend to handle item deletion by ID instead of index - Fix visual feedback: deleted items are hidden immediately - Auto-recalculate total sum after deletion Technical changes: - order_form.html: Add confirmation dialog, trigger autosave on delete - autosave.js: Collect deleted item IDs, send to backend - draft_service.py: Process deleted_item_ids, update items by ID 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- myproject/orders/services/draft_service.py | 53 +++++++++++-------- myproject/orders/static/orders/js/autosave.js | 31 ++++++++--- .../orders/templates/orders/order_form.html | 50 +++++++++++------ myproject/products/views/api_views.py | 16 +++--- 4 files changed, 98 insertions(+), 52 deletions(-) diff --git a/myproject/orders/services/draft_service.py b/myproject/orders/services/draft_service.py index 45123c2..5d44958 100644 --- a/myproject/orders/services/draft_service.py +++ b/myproject/orders/services/draft_service.py @@ -208,6 +208,13 @@ class DraftOrderService: setattr(order, field, value) + # Обрабатываем удаление позиций заказа + if 'deleted_item_ids' in data: + deleted_ids = data['deleted_item_ids'] + if deleted_ids: + from ..models import OrderItem + OrderItem.objects.filter(id__in=deleted_ids, order=order).delete() + # Обрабатываем позиции заказа (items) if 'items' in data: # Импортируем модели @@ -216,18 +223,9 @@ class DraftOrderService: items_data = data['items'] - # Получаем существующие позиции - existing_items = list(order.items.all()) - - # Удаляем все существующие позиции, которых нет в новых данных - items_to_keep_count = len(items_data) - for i, existing_item in enumerate(existing_items): - if i >= items_to_keep_count: - # Удаляем лишние позиции - existing_item.delete() - - # Обновляем или создаём позиции - for index, item_data in enumerate(items_data): + # Обрабатываем каждую позицию + for item_data in items_data: + item_id = item_data.get('id') # ID существующей позиции (если есть) product_id = item_data.get('product_id') product_kit_id = item_data.get('product_kit_id') quantity = item_data.get('quantity', 1) @@ -275,17 +273,28 @@ class DraftOrderService: is_custom_price = False # Обновляем существующую позицию или создаём новую - if index < len(existing_items): - # Обновляем существующую - item = existing_items[index] - item.product = product - item.product_kit = product_kit - item.quantity = quantity - item.price = price - item.is_custom_price = is_custom_price - item.save() + if item_id: + # Обновляем существующую позицию + try: + item = OrderItem.objects.get(id=item_id, order=order) + item.product = product + item.product_kit = product_kit + item.quantity = quantity + item.price = price + item.is_custom_price = is_custom_price + item.save() + except OrderItem.DoesNotExist: + # Если позиция не найдена, создаём новую + OrderItem.objects.create( + order=order, + product=product, + product_kit=product_kit, + quantity=quantity, + price=price, + is_custom_price=is_custom_price + ) else: - # Создаём новую + # Создаём новую позицию OrderItem.objects.create( order=order, product=product, diff --git a/myproject/orders/static/orders/js/autosave.js b/myproject/orders/static/orders/js/autosave.js index 8e589fc..f1d918d 100644 --- a/myproject/orders/static/orders/js/autosave.js +++ b/myproject/orders/static/orders/js/autosave.js @@ -213,7 +213,7 @@ return; } - const fields = form.querySelectorAll('select, input[type="number"], input[type="checkbox"]'); + const fields = form.querySelectorAll('select, input[type="number"], input[type="text"], input[type="checkbox"]'); fields.forEach(field => { if (field.tagName === 'SELECT' || field.type === 'checkbox') { @@ -421,7 +421,9 @@ } // Собираем позиции заказа - data.items = collectOrderItems(); + const orderItemsData = collectOrderItems(); + data.items = orderItemsData.items; + data.deleted_item_ids = orderItemsData.deletedItemIds; // Флаг для пересчета итоговой суммы data.recalculate = true; @@ -434,13 +436,20 @@ */ function collectOrderItems() { const items = []; + const deletedItemIds = []; const itemForms = document.querySelectorAll('.order-item-form'); itemForms.forEach(form => { - // Пропускаем удаленные формы + // Проверяем, помечена ли форма на удаление const deleteCheckbox = form.querySelector('input[name$="-DELETE"]'); + const idField = form.querySelector('input[name$="-id"]'); + if (deleteCheckbox && deleteCheckbox.checked) { - return; + // Если форма помечена на удаление и имеет ID, добавляем в список удалённых + if (idField && idField.value) { + deletedItemIds.push(parseInt(idField.value)); + } + return; // Не добавляем в items } // Получаем выбранный товар/комплект @@ -459,9 +468,14 @@ const item = { quantity: quantityInput.value || '1', - price: priceInput.value || '0' + price: (priceInput.value || '0').replace(',', '.') }; + // Если есть ID (существующий товар), добавляем его + if (idField && idField.value) { + item.id = parseInt(idField.value); + } + // Определяем тип: товар или комплект if (itemValue.startsWith('product_')) { item.product_id = parseInt(itemValue.replace('product_', '')); @@ -472,7 +486,7 @@ items.push(item); }); - return items; + return { items, deletedItemIds }; } /** @@ -544,4 +558,9 @@ init(); } + // Экспортируем функцию scheduleAutosave в глобальную область + window.orderAutosave = { + scheduleAutosave: scheduleAutosave + }; + })(); diff --git a/myproject/orders/templates/orders/order_form.html b/myproject/orders/templates/orders/order_form.html index 328bf3c..ef65ea5 100644 --- a/myproject/orders/templates/orders/order_form.html +++ b/myproject/orders/templates/orders/order_form.html @@ -1,5 +1,6 @@ {% extends 'base.html' %} {% load static %} +{% load l10n %} {% block title %}{{ title }}{% endblock %} @@ -227,11 +228,11 @@
{% if item_form.instance.product %} - + {% elif item_form.instance.product_kit %} - + {% else %} - {{ item_form.price }} + {% endif %}