From d44687649c5cb30486ac44e0013feaea7a663baa Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Thu, 11 Dec 2025 23:09:56 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87?= =?UTF-8?q?=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80?= =?UTF-8?q?=D0=B0=D1=82=20=D0=B2=D0=B8=D1=82=D1=80=D0=B8=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=8D=D0=BA=D0=B7=D0=B5=D0=BC=D0=BF=D0=BB=D1=8F=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BD=D0=B0=20=D0=B2=D0=B8=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D0=BD=D1=83=20=D0=BF=D1=80=D0=B8=20=D0=BE=D1=82=D0=BA=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема: При отмене заказа (completed → cancelled) резервы корректно возвращались в статус 'reserved', но ShowcaseItem оставались в статусе 'sold'. Из-за этого витринные букеты не отображались в POS после отмены заказа, хотя физически должны были вернуться на витрину. Решение: В существующий сигнал rollback_sale_on_status_change добавлена логика возврата витринных экземпляров на витрину: 1. После отката Sale и Reservation находим все ShowcaseItem, проданные в рамках отменяемого заказа (sold_order_item__order=instance) 2. Для каждого экземпляра: - Меняем status: sold → available - Очищаем sold_order_item = None - Очищаем sold_at = None - НЕ трогаем showcase и product_kit (букет остаётся на той же витрине) 3. Логируем количество возвращённых экземпляров Преимущества: - Элегантно: вся логика отката в одном месте (сигнал) - Транзакционно: откат Sale, Reservation и ShowcaseItem в одной транзакции - Универсально: работает для POS и обычных заказов - Без костылей: используем существующую архитектуру сигналов Теперь при отмене заказа витринный букет автоматически возвращается на витрину и снова виден в POS - как в реальной жизни. --- myproject/inventory/signals.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/myproject/inventory/signals.py b/myproject/inventory/signals.py index 5bfae3b..2a17b6c 100644 --- a/myproject/inventory/signals.py +++ b/myproject/inventory/signals.py @@ -474,6 +474,34 @@ def rollback_sale_on_status_change(sender, instance, created, **kwargs): f"⚠ Для заказа {instance.order_number} нет резервов в статусе 'converted_to_sale'" ) + # === Возвращаем витринные экземпляры обратно на витрину === + from inventory.models import ShowcaseItem + + # Находим все ShowcaseItem, проданные в рамках этого заказа + showcase_items = ShowcaseItem.objects.filter( + sold_order_item__order=instance, + status='sold' + ) + + showcase_items_count = showcase_items.count() + + if showcase_items_count > 0: + logger.info( + f"🔄 Возвращаем {showcase_items_count} витринных экземпляров обратно на витрину..." + ) + + # Возвращаем каждый экземпляр на витрину + for item in showcase_items: + item.status = 'available' + item.sold_order_item = None + item.sold_at = None + # showcase и product_kit не трогаем - букет остаётся на той же витрине + item.save(update_fields=['status', 'sold_order_item', 'sold_at', 'updated_at']) + + logger.info( + f"✓ {showcase_items_count} витринных экземпляров вернулись на витрину: sold → available" + ) + # === Обновляем is_returned === if is_cancellation: # Сценарий Б: устанавливаем is_returned = True