Добавлен автоматический возврат витринных экземпляров на витрину при откате заказа

Проблема:
При отмене заказа (completed → cancelled) резервы корректно возвращались
в статус 'reserved', но ShowcaseItem оставались в статусе 'sold'.
Из-за этого витринные букеты не отображались в POS после отмены заказа,
хотя физически должны были вернуться на витрину.

Решение:
В существующий сигнал rollback_sale_on_status_change добавлена логика
возврата витринных экземпляров на витрину:

1. После отката Sale и Reservation находим все ShowcaseItem, проданные
   в рамках отменяемого заказа (sold_order_item__order=instance)

2. Для каждого экземпляра:
   - Меняем status: sold → available
   - Очищаем sold_order_item = None
   - Очищаем sold_at = None
   - НЕ трогаем showcase и product_kit (букет остаётся на той же витрине)

3. Логируем количество возвращённых экземпляров

Преимущества:
- Элегантно: вся логика отката в одном месте (сигнал)
- Транзакционно: откат Sale, Reservation и ShowcaseItem в одной транзакции
- Универсально: работает для POS и обычных заказов
- Без костылей: используем существующую архитектуру сигналов

Теперь при отмене заказа витринный букет автоматически возвращается
на витрину и снова виден в POS - как в реальной жизни.
This commit is contained in:
2025-12-11 23:09:56 +03:00
parent 4ce610985b
commit d44687649c

View File

@@ -474,6 +474,34 @@ def rollback_sale_on_status_change(sender, instance, created, **kwargs):
f"⚠ Для заказа {instance.order_number} нет резервов в статусе 'converted_to_sale'"
)
# === Возвращаем витринные экземпляры обратно на витрину ===
from inventory.models import ShowcaseItem
# Находим все ShowcaseItem, проданные в рамках этого заказа
showcase_items = ShowcaseItem.objects.filter(
sold_order_item__order=instance,
status='sold'
)
showcase_items_count = showcase_items.count()
if showcase_items_count > 0:
logger.info(
f"🔄 Возвращаем {showcase_items_count} витринных экземпляров обратно на витрину..."
)
# Возвращаем каждый экземпляр на витрину
for item in showcase_items:
item.status = 'available'
item.sold_order_item = None
item.sold_at = None
# showcase и product_kit не трогаем - букет остаётся на той же витрине
item.save(update_fields=['status', 'sold_order_item', 'sold_at', 'updated_at'])
logger.info(
f"{showcase_items_count} витринных экземпляров вернулись на витрину: sold → available"
)
# === Обновляем is_returned ===
if is_cancellation:
# Сценарий Б: устанавливаем is_returned = True