Исправлено создание резервов при сохранении заказов
Проблема #1: Резервы не создавались при создании заказа - Order сохранялся БЕЗ items → сигнал reserve_stock_on_order_create не мог создать резервы (items.all() был пустой) - OrderItem создавались ПОСЛЕ, но сигнал уже отработал Решение #1: Создание резервов через сигнал OrderItem - Доработан сигнал update_reservation_on_item_change - Убрано раннее возвращение для created=True - Теперь резервы создаются при добавлении OrderItem (любым способом) - Работает для всех сценариев: * Создание заказа с товарами * Добавление товаров при редактировании * Изменение количества Проблема #2: Риск расхождений при удалении заказа - Сигнал pre_delete освобождал резервы ДО удаления - Если удаление падало с ошибкой → резервы освобождены, Order не удалён - Возникало расхождение данных Решение #2: transaction.on_commit для освобождения резервов - Добавлен @transaction.atomic к сигналу release_stock_on_order_delete - Резервы получаются ДО удаления через list() - Освобождение происходит через transaction.on_commit() - Резервы освобождаются ТОЛЬКО если удаление успешно - Гарантия целостности данных Изменённые файлы: - myproject/inventory/signals.py - оба сигнала исправлены - RESERVATION_FIX.md - полная документация
This commit is contained in:
@@ -390,41 +390,51 @@ def rollback_sale_on_status_change(sender, instance, created, **kwargs):
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=Order)
|
||||
@transaction.atomic
|
||||
def release_stock_on_order_delete(sender, instance, **kwargs):
|
||||
"""
|
||||
Сигнал: При удалении/отмене заказа освободить резервы.
|
||||
|
||||
Процесс:
|
||||
1. Ищем все резервы для этого заказа
|
||||
2. Меняем статус резерва на 'released'
|
||||
3. Фиксируем время освобождения
|
||||
1. Ищем все резервы для этого заказа ДО удаления
|
||||
2. Освобождаем резервы ПОСЛЕ успешного коммита транзакции
|
||||
3. Это гарантирует, что резервы освободятся только если удаление успешно
|
||||
"""
|
||||
# Находим все резервы для этого заказа
|
||||
reservations = Reservation.objects.filter(
|
||||
order_item__order=instance,
|
||||
status='reserved'
|
||||
# Находим все резервы для этого заказа ДО удаления
|
||||
# Используем list() чтобы выполнить запрос сейчас, пока Order ещё существует
|
||||
reservations_to_release = list(
|
||||
Reservation.objects.filter(
|
||||
order_item__order=instance,
|
||||
status='reserved'
|
||||
)
|
||||
)
|
||||
|
||||
# Освобождаем каждый резерв
|
||||
for res in reservations:
|
||||
res.status = 'released'
|
||||
res.released_at = timezone.now()
|
||||
res.save()
|
||||
# Освобождаем резервы ПОСЛЕ успешного коммита транзакции
|
||||
# Это гарантирует целостность: резервы освободятся только если удаление прошло успешно
|
||||
def release_reservations():
|
||||
for res in reservations_to_release:
|
||||
res.status = 'released'
|
||||
res.released_at = timezone.now()
|
||||
res.save()
|
||||
|
||||
transaction.on_commit(release_reservations)
|
||||
|
||||
|
||||
@receiver(post_save, sender=OrderItem)
|
||||
def update_reservation_on_item_change(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Сигнал: Если изменилось количество товара в позиции заказа,
|
||||
обновить резерв.
|
||||
Сигнал: При создании или изменении позиции заказа управляем резервами.
|
||||
|
||||
Процесс:
|
||||
1. Если это новая позиция - игнорируем (резерв уже создан через Order)
|
||||
2. Если изменилось количество - обновляем резерв или создаем новый
|
||||
"""
|
||||
if created:
|
||||
return # Новые позиции обрабатываются через Order signal
|
||||
1. Ищем существующий резерв для этой позиции
|
||||
2. Если резерв ЕСТЬ - обновляем количество
|
||||
3. Если резерва НЕТ - создаем новый
|
||||
|
||||
Покрывает все сценарии:
|
||||
- Создание заказа с товарами → создаёт резервы
|
||||
- Редактирование + добавление товаров → создаёт резервы для новых
|
||||
- Изменение количества → обновляет резервы
|
||||
"""
|
||||
# Получаем резерв для этой позиции в статусе 'reserved'
|
||||
reservation = Reservation.objects.filter(
|
||||
order_item=instance,
|
||||
@@ -432,11 +442,12 @@ def update_reservation_on_item_change(sender, instance, created, **kwargs):
|
||||
).first()
|
||||
|
||||
if reservation:
|
||||
# Резерв существует - обновляем его
|
||||
# Резерв существует - обновляем его количество
|
||||
reservation.quantity = Decimal(str(instance.quantity))
|
||||
reservation.save()
|
||||
else:
|
||||
# Резерва нет - создаем новый
|
||||
# Это происходит при создании нового OrderItem (через форму или при редактировании)
|
||||
warehouse = instance.order.pickup_warehouse or Warehouse.objects.filter(is_active=True).first()
|
||||
|
||||
if warehouse:
|
||||
|
||||
Reference in New Issue
Block a user