Реализована логика резервирования витринных букетов через сигналы
- inventory/signals.py: обработчик изменения статуса Order * При смене статуса на 'завершён' (is_positive_end=True): reserved → sold * При смене на 'отменён' (is_negative_end=True): reserved → available - inventory/services/showcase_manager.py: метод reserve_for_order() * Переводит ShowcaseItem: in_cart → reserved * Создаёт жёсткую связь с OrderItem * Автоматическое управление статусами через сигналы - Транзакционная безопасность через @transaction.atomic
This commit is contained in:
@@ -494,6 +494,33 @@ def create_sale_on_order_completion(sender, instance, created, **kwargs):
|
||||
f"✓ Обновлено {updated_count} резервов для заказа {instance.order_number}: reserved → converted_to_sale"
|
||||
)
|
||||
|
||||
# === Финализация витринных экземпляров: reserved → sold ===
|
||||
# Находим все витринные комплекты в этом заказе, которые в статусе reserved
|
||||
from inventory.models import ShowcaseItem
|
||||
|
||||
showcase_items_to_finalize = ShowcaseItem.objects.filter(
|
||||
sold_order_item__order=instance,
|
||||
status='reserved'
|
||||
)
|
||||
|
||||
finalized_count = 0
|
||||
for showcase_item in showcase_items_to_finalize:
|
||||
try:
|
||||
showcase_item.mark_sold_from_reserved()
|
||||
finalized_count += 1
|
||||
logger.info(
|
||||
f"✓ Витринный экземпляр #{showcase_item.id} финализирован: reserved → sold"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка финализации ShowcaseItem #{showcase_item.id}: {e}"
|
||||
)
|
||||
|
||||
if finalized_count > 0:
|
||||
logger.info(
|
||||
f"🎉 Финализировано {finalized_count} витринных экземпляров для заказа {instance.order_number}"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"🎉 Заказ {instance.order_number} успешно обработан: создано {len(sales_created)} Sale, "
|
||||
f"обновлено {reservations_to_update.count() if reservations_to_update.exists() else 0} резервов"
|
||||
@@ -838,10 +865,37 @@ def rollback_sale_on_status_change(sender, instance, created, **kwargs):
|
||||
f"✅ {showcase_items_count} витринных экземпляров вернулись на витрину: sold → available со связью с резервами"
|
||||
)
|
||||
else:
|
||||
# Сценарий А: Возврат к нейтральному - ShowcaseItem ОСТАЁТСЯ sold
|
||||
logger.info(
|
||||
f"ℹ️ Сценарий А: Витринные экземпляры остаются в статусе 'sold' (заказ в нейтральном статусе)"
|
||||
# Сценарий А: Возврат к нейтральному - ShowcaseItem sold → reserved
|
||||
from inventory.models import ShowcaseItem
|
||||
|
||||
# Находим все ShowcaseItem в статусе 'sold' для этого заказа
|
||||
showcase_items_to_unreserve = ShowcaseItem.objects.filter(
|
||||
sold_order_item__order=instance,
|
||||
status='sold'
|
||||
)
|
||||
|
||||
unreserved_count = 0
|
||||
for showcase_item in showcase_items_to_unreserve:
|
||||
try:
|
||||
# Возвращаем в reserved (букет остаётся занят под заказ)
|
||||
showcase_item.return_to_reserved(showcase_item.sold_order_item)
|
||||
unreserved_count += 1
|
||||
logger.info(
|
||||
f"✓ Витринный экземпляр #{showcase_item.id} возвращён в резерв: sold → reserved"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка возврата ShowcaseItem #{showcase_item.id} в reserved: {e}"
|
||||
)
|
||||
|
||||
if unreserved_count > 0:
|
||||
logger.info(
|
||||
f"🔄 {unreserved_count} витринных экземпляров возвращено в резерв: sold → reserved (заказ в нейтральном статусе)"
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"ℹ️ Сценарий А: Нет витринных экземпляров для возврата в reserved"
|
||||
)
|
||||
|
||||
# === Обновляем is_returned ===
|
||||
# Используем единую функцию для обновления флага на основе фактического состояния
|
||||
@@ -972,6 +1026,33 @@ def release_reservations_on_cancellation(sender, instance, created, **kwargs):
|
||||
f"ℹ️ Для заказа {instance.order_number} нет резервов в статусе 'reserved'"
|
||||
)
|
||||
|
||||
# === Освобождаем ShowcaseItem при отмене: reserved/sold → available ===
|
||||
from inventory.models import ShowcaseItem
|
||||
|
||||
# Находим все ShowcaseItem для этого заказа в статусах reserved или sold
|
||||
showcase_items_to_release = ShowcaseItem.objects.filter(
|
||||
sold_order_item__order=instance,
|
||||
status__in=['reserved', 'sold']
|
||||
)
|
||||
|
||||
released_showcase_count = 0
|
||||
for showcase_item in showcase_items_to_release:
|
||||
try:
|
||||
showcase_item.return_to_available()
|
||||
released_showcase_count += 1
|
||||
logger.info(
|
||||
f"✓ Витринный экземпляр #{showcase_item.id} освобождён: {showcase_item.status} → available"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка освобождения ShowcaseItem #{showcase_item.id}: {e}"
|
||||
)
|
||||
|
||||
if released_showcase_count > 0:
|
||||
logger.info(
|
||||
f"🎉 {released_showcase_count} витринных экземпляров освобождено и возвращено на витрину при отмене заказа"
|
||||
)
|
||||
|
||||
# === Обновляем is_returned ===
|
||||
# Используем единую функцию для обновления флага
|
||||
update_is_returned_flag(instance)
|
||||
|
||||
Reference in New Issue
Block a user