Исправлена логика освобождения резервов для витринных комплектов во всех сигналах
This commit is contained in:
@@ -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,26 +694,45 @@ 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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user