Исправлена логика освобождения резервов для витринных комплектов во всех сигналах
This commit is contained in:
@@ -557,24 +557,42 @@ def release_reservations_on_cancellation(sender, instance, created, **kwargs):
|
|||||||
status='reserved'
|
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(
|
logger.info(
|
||||||
f"🔄 Переход к статусу '{current_status.name}' для заказа {instance.order_number}. "
|
f"🔄 Переход к статусу '{current_status.name}' для заказа {instance.order_number}. "
|
||||||
f"Освобождаем {reservations_count} резервов..."
|
f"Освобождаем {normal_count} обычных резервов..."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Обновляем резервы через .save() чтобы сработал сигнал обновления Stock
|
# Обновляем резервы через .save() чтобы сработал сигнал обновления Stock
|
||||||
for reservation in reservations:
|
for reservation in normal_reservations:
|
||||||
reservation.status = 'released'
|
reservation.status = 'released'
|
||||||
reservation.released_at = timezone.now()
|
reservation.released_at = timezone.now()
|
||||||
reservation.save(update_fields=['status', 'released_at'])
|
reservation.save(update_fields=['status', 'released_at'])
|
||||||
|
|
||||||
logger.info(
|
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(
|
logger.debug(
|
||||||
f"ℹ️ Для заказа {instance.order_number} нет резервов в статусе 'reserved'"
|
f"ℹ️ Для заказа {instance.order_number} нет резервов в статусе 'reserved'"
|
||||||
)
|
)
|
||||||
@@ -676,25 +694,44 @@ def release_stock_on_order_delete(sender, instance, **kwargs):
|
|||||||
|
|
||||||
Процесс:
|
Процесс:
|
||||||
1. Ищем все резервы для этого заказа ДО удаления
|
1. Ищем все резервы для этого заказа ДО удаления
|
||||||
2. Освобождаем резервы ПОСЛЕ успешного коммита транзакции
|
2. Освобождаем резервы ПОСЛЕ успешного коммита транзакции (кроме витринных комплектов)
|
||||||
3. Это гарантирует, что резервы освободятся только если удаление успешно
|
3. Это гарантирует, что резервы освободятся только если удаление успешно
|
||||||
|
|
||||||
|
ИСКЛЮЧЕНИЕ: Витринные временные комплекты (is_temporary=True, showcase!=null)
|
||||||
|
остаются в статусе 'reserved' даже при удалении заказа.
|
||||||
"""
|
"""
|
||||||
# Находим все резервы для этого заказа ДО удаления
|
# Находим все резервы для этого заказа ДО удаления
|
||||||
# Используем list() чтобы выполнить запрос сейчас, пока Order ещё существует
|
# Используем list() чтобы выполнить запрос сейчас, пока Order ещё существует
|
||||||
reservations_to_release = list(
|
all_reservations = list(
|
||||||
Reservation.objects.filter(
|
Reservation.objects.filter(
|
||||||
order_item__order=instance,
|
order_item__order=instance,
|
||||||
status='reserved'
|
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():
|
def release_reservations():
|
||||||
for res in reservations_to_release:
|
for res in normal_reservations:
|
||||||
res.status = 'released'
|
res.status = 'released'
|
||||||
res.released_at = timezone.now()
|
res.released_at = timezone.now()
|
||||||
res.save()
|
res.save()
|
||||||
|
|
||||||
|
# Витринные комплекты остаются зарезервированными, но отвязываем их от заказа
|
||||||
|
for res in showcase_reservations:
|
||||||
|
res.order_item = None
|
||||||
|
res.save(update_fields=['order_item'])
|
||||||
|
|
||||||
transaction.on_commit(release_reservations)
|
transaction.on_commit(release_reservations)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user