Исправлен порядок обработки ShowcaseItem при переходе cancelled → completed
Проблема: - При переходе cancelled → completed срабатывали ОБА сигнала: 1. reserve_stock_on_uncancellation переводил ShowcaseItem: available → reserved 2. create_sale_on_order_completion искал букеты в available, но они уже в reserved 3. Букеты оставались в reserved вместо sold Решение: - inventory/signals.py: в reserve_stock_on_uncancellation добавлена проверка current_status.is_positive_end - Если текущий статус положительный финальный (completed) - ShowcaseItem НЕ трогаем - Оставляем в available для финализации в create_sale_on_order_completion - Если текущий статус нейтральный (draft/pending) - переводим available → reserved как раньше Flow теперь работает корректно: 1. cancelled → draft/pending: ShowcaseItem available → reserved ✅ 2. cancelled → completed: ShowcaseItem available → sold ✅ (ИСПРАВЛЕНО!) - reserve_stock_on_uncancellation пропускает (видит is_positive_end) - create_sale_on_order_completion финализирует: available → sold Защита от race condition между двумя сигналами.
This commit is contained in:
@@ -1236,37 +1236,47 @@ def reserve_stock_on_uncancellation(sender, instance, created, **kwargs):
|
|||||||
# === Возвращаем ShowcaseItem из available обратно в reserved ===
|
# === Возвращаем ShowcaseItem из available обратно в reserved ===
|
||||||
# При отмене (cancelled) ShowcaseItem переходит в 'available'.
|
# При отмене (cancelled) ShowcaseItem переходит в 'available'.
|
||||||
# При возврате к нейтральному статусу нужно вернуть в 'reserved'.
|
# При возврате к нейтральному статусу нужно вернуть в 'reserved'.
|
||||||
|
# НО: При переходе в положительный финальный статус - НЕ трогаем!
|
||||||
|
# (create_sale_on_order_completion сам переведёт available → sold)
|
||||||
from inventory.models import ShowcaseItem
|
from inventory.models import ShowcaseItem
|
||||||
|
|
||||||
# Находим все ShowcaseItem которые были освобождены при отмене
|
# Проверяем: если текущий статус положительный финальный, то пропускаем
|
||||||
# (у них sold_order_item сброшен в return_to_available, нужно найти через резервы)
|
if current_status.is_positive_end:
|
||||||
for order_item in showcase_order_items:
|
logger.info(
|
||||||
kit = order_item.product_kit
|
f"🔄 Переход к положительному финальному статусу '{current_status.name}'. "
|
||||||
|
f"ShowcaseItem остаются в 'available' для финализации в create_sale_on_order_completion."
|
||||||
# Находим ShowcaseItem этого комплекта в статусе 'available'
|
|
||||||
# Их sold_order_item = None, поэтому ищем через product_kit
|
|
||||||
available_items = ShowcaseItem.objects.filter(
|
|
||||||
product_kit=kit,
|
|
||||||
status='available',
|
|
||||||
sold_order_item__isnull=True
|
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# Переход к нейтральному статусу - возвращаем в reserved
|
||||||
|
# Находим все ShowcaseItem которые были освобождены при отмене
|
||||||
|
# (у них sold_order_item сброшен в return_to_available, нужно найти через резервы)
|
||||||
|
for order_item in showcase_order_items:
|
||||||
|
kit = order_item.product_kit
|
||||||
|
|
||||||
if available_items.exists():
|
# Находим ShowcaseItem этого комплекта в статусе 'available'
|
||||||
logger.info(
|
# Их sold_order_item = None, поэтому ищем через product_kit
|
||||||
f" 🔄 Найдено {available_items.count()} ShowcaseItem комплекта '{kit.name}' в статусе 'available'. "
|
available_items = ShowcaseItem.objects.filter(
|
||||||
f"Возвращаем в reserved..."
|
product_kit=kit,
|
||||||
|
status='available',
|
||||||
|
sold_order_item__isnull=True
|
||||||
)
|
)
|
||||||
|
|
||||||
for item in available_items:
|
if available_items.exists():
|
||||||
try:
|
logger.info(
|
||||||
item.return_to_reserved(order_item)
|
f" 🔄 Найдено {available_items.count()} ShowcaseItem комплекта '{kit.name}' в статусе 'available'. "
|
||||||
logger.info(
|
f"Возвращаем в reserved..."
|
||||||
f" ✅ ShowcaseItem #{item.id}: available → reserved (привязан к OrderItem #{order_item.id})"
|
)
|
||||||
)
|
|
||||||
except Exception as e:
|
for item in available_items:
|
||||||
logger.error(
|
try:
|
||||||
f" ❌ Ошибка возврата ShowcaseItem #{item.id} в reserved: {e}"
|
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)
|
@receiver(pre_delete, sender=Order)
|
||||||
|
|||||||
Reference in New Issue
Block a user