Исправлен баг: ShowcaseItem теперь возвращается в reserved при переходе из отрицательного статуса в нейтральный

Проблема:
- При отмене заказа (cancelled) ShowcaseItem переходил в 'available'
- При возврате из cancelled в нейтральный статус (draft/pending) резервы привязывались обратно
- НО ShowcaseItem оставался в 'available', что позволяло добавить букет в другой заказ
- Итог: один физический букет в двух заказах

Решение:
- inventory/signals.py: в сигнале reserve_stock_on_uncancellation добавлена логика
- При переходе cancelled → нейтральный:
  * Находим ShowcaseItem витринных комплектов в статусе 'available'
  * Вызываем return_to_reserved(order_item) для каждого экземпляра
  * ShowcaseItem: available → reserved (привязан к OrderItem)
- Теперь букет корректно возвращается в резерв и недоступен на витрине

Lifecycle при откате отмены:
1. cancelled: ShowcaseItem = available, резервы отвязаны
2. cancelled → draft/pending: ShowcaseItem = reserved, резервы привязаны
3. Букет остаётся за заказом, защищён от двойной продажи
This commit is contained in:
2026-01-05 09:09:41 +03:00
parent a1f5557036
commit 366ead7404

View File

@@ -1190,6 +1190,41 @@ def reserve_stock_on_uncancellation(sender, instance, created, **kwargs):
logger.info(
f"✅ Обработано {showcase_items_count} витринных комплектов"
)
# === Возвращаем ShowcaseItem из available обратно в reserved ===
# При отмене (cancelled) ShowcaseItem переходит в 'available'.
# При возврате к нейтральному статусу нужно вернуть в 'reserved'.
from inventory.models import ShowcaseItem
# Находим все ShowcaseItem которые были освобождены при отмене
# (у них sold_order_item сброшен в return_to_available, нужно найти через резервы)
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"Возвращаем в reserved..."
)
for item in available_items:
try:
item.return_to_reserved(order_item)
logger.info(
f" ✅ ShowcaseItem #{item.id}: available → reserved (привязан к OrderItem #{order_item.id})"
)
except Exception as e:
logger.error(
f" ❌ Ошибка возврата ShowcaseItem #{item.id} в reserved: {e}"
)
@receiver(pre_delete, sender=Order)