Исправлен поиск ShowcaseItem при переходе cancelled → completed
Проблема: - При отмене (cancelled) метод return_to_available() сбрасывает sold_order_item = None - При переходе cancelled → completed поиск ShowcaseItem по sold_order_item__order не находит букеты - Букеты оставались в статусе 'available' вместо 'sold' Решение: - inventory/signals.py: в сигнале create_sale_on_order_completion изменена логика поиска - Разделён поиск на два этапа: 1. Поиск по sold_order_item для букетов в 'reserved' (обычный flow) 2. Поиск по product_kit для букетов в 'available' (переход из cancelled) - Для букетов в 'available': ищем через product_kit + status='available' + sold_order_item__isnull=True - Вызываем mark_sold(order_item) для каждого найденного букета - Букет корректно переходит available → sold и привязывается к OrderItem Flow теперь работает: 1. draft → completed: ShowcaseItem reserved → sold ✅ 2. cancelled → completed: ShowcaseItem available → sold ✅ (ИСПРАВЛЕНО!) Защита от двойной продажи работает корректно.
This commit is contained in:
@@ -500,33 +500,64 @@ def create_sale_on_order_completion(sender, instance, created, **kwargs):
|
|||||||
# - в статусе 'available' (переход из отмены: cancelled → completed)
|
# - в статусе 'available' (переход из отмены: cancelled → completed)
|
||||||
from inventory.models import ShowcaseItem
|
from inventory.models import ShowcaseItem
|
||||||
|
|
||||||
|
# Сначала ищем по sold_order_item (для букетов в reserved)
|
||||||
showcase_items_to_finalize = ShowcaseItem.objects.filter(
|
showcase_items_to_finalize = ShowcaseItem.objects.filter(
|
||||||
sold_order_item__order=instance,
|
sold_order_item__order=instance,
|
||||||
status__in=['reserved', 'available']
|
status='reserved'
|
||||||
)
|
)
|
||||||
|
|
||||||
finalized_count = 0
|
finalized_count = 0
|
||||||
for showcase_item in showcase_items_to_finalize:
|
for showcase_item in showcase_items_to_finalize:
|
||||||
try:
|
try:
|
||||||
if showcase_item.status == 'reserved':
|
|
||||||
# Обычный flow: reserved → sold
|
# Обычный flow: reserved → sold
|
||||||
showcase_item.mark_sold_from_reserved()
|
showcase_item.mark_sold_from_reserved()
|
||||||
|
finalized_count += 1
|
||||||
logger.info(
|
logger.info(
|
||||||
f"✓ Витринный экземпляр #{showcase_item.id} финализирован: reserved → sold"
|
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
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"❌ Ошибка финализации ShowcaseItem #{showcase_item.id}: {e}"
|
f"❌ Ошибка финализации ShowcaseItem #{showcase_item.id}: {e}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Теперь ищем букеты в available (переход из cancelled)
|
||||||
|
# При отмене sold_order_item сбрасывается, поэтому ищем через product_kit
|
||||||
|
showcase_order_items = instance.items.filter(
|
||||||
|
product_kit__is_temporary=True,
|
||||||
|
product_kit__showcase__isnull=False
|
||||||
|
).select_related('product_kit')
|
||||||
|
|
||||||
|
for order_item in showcase_order_items:
|
||||||
|
kit = order_item.product_kit
|
||||||
|
|
||||||
|
# Находим ShowcaseItem этого комплекта в статусе 'available'
|
||||||
|
# Их sold_order_item = None после отмены, поэтому ищем через product_kit
|
||||||
|
available_items = ShowcaseItem.objects.filter(
|
||||||
|
product_kit=kit,
|
||||||
|
status='available',
|
||||||
|
sold_order_item__isnull=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if available_items.exists():
|
||||||
|
logger.info(
|
||||||
|
f" 🔄 Найдено {available_items.count()} ShowcaseItem комплекта '{kit.name}' в статусе 'available'. "
|
||||||
|
f"Финализируем: available → sold (из отмены)..."
|
||||||
|
)
|
||||||
|
|
||||||
|
for item in available_items:
|
||||||
|
try:
|
||||||
|
# Переход из отмены: available → sold (минуя reserved)
|
||||||
|
# Используем mark_sold() который работает с available
|
||||||
|
item.mark_sold(order_item)
|
||||||
|
finalized_count += 1
|
||||||
|
logger.info(
|
||||||
|
f" ✅ ShowcaseItem #{item.id}: available → sold (привязан к OrderItem #{order_item.id})"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(
|
||||||
|
f" ❌ Ошибка финализации ShowcaseItem #{item.id}: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
if finalized_count > 0:
|
if finalized_count > 0:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"🎉 Финализировано {finalized_count} витринных экземпляров для заказа {instance.order_number}"
|
f"🎉 Финализировано {finalized_count} витринных экземпляров для заказа {instance.order_number}"
|
||||||
|
|||||||
Reference in New Issue
Block a user