Исправлена логика освобождения резервов для витринных комплектов во всех сигналах

This commit is contained in:
2025-12-08 18:15:41 +03:00
parent 5d24b1cd6e
commit 5b03a95b5a

View File

@@ -557,24 +557,42 @@ def release_reservations_on_cancellation(sender, instance, created, **kwargs):
status='reserved'
)
reservations_count = reservations.count()
# Исключаем витринные временные комплекты - они остаются на витрине
showcase_kit_reservations = reservations.filter(
product_kit__is_temporary=True,
product_kit__showcase__isnull=False
)
if reservations_count > 0:
# Освобождаем только обычные резервы
normal_reservations = reservations.exclude(
id__in=showcase_kit_reservations.values_list('id', flat=True)
)
normal_count = normal_reservations.count()
showcase_count = showcase_kit_reservations.count()
if normal_count > 0:
logger.info(
f"🔄 Переход к статусу '{current_status.name}' для заказа {instance.order_number}. "
f"Освобождаем {reservations_count} резервов..."
f"Освобождаем {normal_count} обычных резервов..."
)
# Обновляем резервы через .save() чтобы сработал сигнал обновления Stock
for reservation in reservations:
for reservation in normal_reservations:
reservation.status = 'released'
reservation.released_at = timezone.now()
reservation.save(update_fields=['status', 'released_at'])
logger.info(
f"✅ Освобождено {reservations_count} резервов: reserved → released"
f"✅ Освобождено {normal_count} обычных резервов: reserved → released"
)
else:
if showcase_count > 0:
logger.info(
f" Найдено {showcase_count} резервов витринных комплектов - остаются в reserved (на витрине)"
)
if normal_count == 0 and showcase_count == 0:
logger.debug(
f" Для заказа {instance.order_number} нет резервов в статусе 'reserved'"
)
@@ -676,25 +694,44 @@ def release_stock_on_order_delete(sender, instance, **kwargs):
Процесс:
1. Ищем все резервы для этого заказа ДО удаления
2. Освобождаем резервы ПОСЛЕ успешного коммита транзакции
2. Освобождаем резервы ПОСЛЕ успешного коммита транзакции (кроме витринных комплектов)
3. Это гарантирует, что резервы освободятся только если удаление успешно
ИСКЛЮЧЕНИЕ: Витринные временные комплекты (is_temporary=True, showcase!=null)
остаются в статусе 'reserved' даже при удалении заказа.
"""
# Находим все резервы для этого заказа ДО удаления
# Используем list() чтобы выполнить запрос сейчас, пока Order ещё существует
reservations_to_release = list(
all_reservations = list(
Reservation.objects.filter(
order_item__order=instance,
status='reserved'
)
).select_related('product_kit')
)
# Разделяем на витринные комплекты и обычные резервы
showcase_reservations = [
r for r in all_reservations
if r.product_kit and r.product_kit.is_temporary and r.product_kit.showcase
]
normal_reservations = [
r for r in all_reservations
if r not in showcase_reservations
]
# Освобождаем резервы ПОСЛЕ успешного коммита транзакции
# Освобождаем только обычные резервы ПОСЛЕ успешного коммита транзакции
# Это гарантирует целостность: резервы освободятся только если удаление прошло успешно
def release_reservations():
for res in reservations_to_release:
for res in normal_reservations:
res.status = 'released'
res.released_at = timezone.now()
res.save()
# Витринные комплекты остаются зарезервированными, но отвязываем их от заказа
for res in showcase_reservations:
res.order_item = None
res.save(update_fields=['order_item'])
transaction.on_commit(release_reservations)