From 6c497bbde3480ebe6998cb2071c83fe9b3f19fec Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Mon, 5 Jan 2026 09:23:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B1=D0=B0=D0=B3:=20ShowcaseItem=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BD=D0=BE=20=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D0=B8=D1=82=20available=20=E2=86=92=20sold=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20cancelled=20=E2=86=92=20completed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема: - При переходе заказа cancelled → completed витринный букет оставался в статусе 'available' - Логика финализации искала только ShowcaseItem в статусе 'reserved' - НО при отмене (cancelled) ShowcaseItem переходит в 'available', а не остаётся в 'reserved' - Итог: букет не финализировался, оставался свободным вместо проданного Решение: - inventory/signals.py: в сигнале create_sale_on_order_completion обновлена логика финализации - Теперь ищем ShowcaseItem в статусах ['reserved', 'available'] - Для статуса 'reserved': вызываем mark_sold_from_reserved() (обычный flow) - Для статуса 'available': вызываем mark_sold() (переход из отмены cancelled → completed) - Оба метода корректно переводят букет в 'sold' и устанавливают sold_at Flow переходов: 1. Обычный: draft → completed: ShowcaseItem reserved → sold ✅ 2. Из отмены: cancelled → completed: ShowcaseItem available → sold ✅ (ИСПРАВЛЕНО) --- myproject/inventory/signals.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/myproject/inventory/signals.py b/myproject/inventory/signals.py index 7021bfc..611fbd8 100644 --- a/myproject/inventory/signals.py +++ b/myproject/inventory/signals.py @@ -494,23 +494,34 @@ def create_sale_on_order_completion(sender, instance, created, **kwargs): f"✓ Обновлено {updated_count} резервов для заказа {instance.order_number}: reserved → converted_to_sale" ) - # === Финализация витринных экземпляров: reserved → sold === - # Находим все витринные комплекты в этом заказе, которые в статусе reserved + # === Финализация витринных экземпляров: reserved/available → sold === + # Находим все витринные комплекты в этом заказе: + # - в статусе 'reserved' (обычный flow: создание черновика → завершение) + # - в статусе 'available' (переход из отмены: cancelled → completed) from inventory.models import ShowcaseItem showcase_items_to_finalize = ShowcaseItem.objects.filter( sold_order_item__order=instance, - status='reserved' + status__in=['reserved', 'available'] ) finalized_count = 0 for showcase_item in showcase_items_to_finalize: try: - showcase_item.mark_sold_from_reserved() + if showcase_item.status == 'reserved': + # Обычный flow: reserved → sold + showcase_item.mark_sold_from_reserved() + logger.info( + f"✓ Витринный экземпляр #{showcase_item.id} финализирован: reserved → sold" + ) + elif showcase_item.status == 'available': + # Переход из отмены: available → sold (минуя reserved) + # Используем mark_sold() который работает с available + showcase_item.mark_sold(showcase_item.sold_order_item) + logger.info( + f"✓ Витринный экземпляр #{showcase_item.id} финализирован: available → sold (из отмены)" + ) finalized_count += 1 - logger.info( - f"✓ Витринный экземпляр #{showcase_item.id} финализирован: reserved → sold" - ) except Exception as e: logger.error( f"❌ Ошибка финализации ShowcaseItem #{showcase_item.id}: {e}"