Исправлены баги витринных комплектов: резервы и валидация восстановления заказов
This commit is contained in:
@@ -177,6 +177,8 @@ class Order(models.Model):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
from django.db import transaction
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
# Генерируем уникальный номер заказа при создании (начиная с 100 для 3-значного поиска)
|
||||
if not self.order_number:
|
||||
last_order = Order.objects.order_by('-order_number').first()
|
||||
@@ -185,6 +187,81 @@ class Order(models.Model):
|
||||
self.order_number = max(last_order.order_number + 1, 100)
|
||||
else:
|
||||
self.order_number = 100
|
||||
|
||||
# === ВАЛИДАЦИЯ: Проверяем доступность витринных комплектов ===
|
||||
# При переходе ИЗ cancelled к любому не-отменённому статусу
|
||||
if self.pk: # Только при редактировании
|
||||
try:
|
||||
# Получаем старый статус из БД
|
||||
old_instance = Order.objects.get(pk=self.pk)
|
||||
old_status = old_instance.status
|
||||
new_status = self.status
|
||||
|
||||
# Проверяем: переход от cancelled к не-cancelled?
|
||||
if (old_status and old_status.is_negative_end and
|
||||
new_status and not new_status.is_negative_end):
|
||||
|
||||
# Находим все витринные комплекты в этом заказе
|
||||
from orders.models import OrderItem
|
||||
showcase_items = OrderItem.objects.filter(
|
||||
order=self,
|
||||
product_kit__is_temporary=True,
|
||||
product_kit__showcase__isnull=False
|
||||
).select_related('product_kit')
|
||||
|
||||
if showcase_items.exists():
|
||||
# Проверяем доступность резервов для каждого комплекта
|
||||
from inventory.models import Reservation
|
||||
unavailable_kits = []
|
||||
|
||||
for item in showcase_items:
|
||||
kit = item.product_kit
|
||||
|
||||
# КРИТИЧНО: Ищем ВСЕ витринные резервы этого комплекта
|
||||
# Проверяем не привязаны ли они к ДРУГОМУ заказу (в ЛЮБОМ статусе)
|
||||
occupied_reservations = Reservation.objects.filter(
|
||||
product_kit=kit,
|
||||
showcase__isnull=False,
|
||||
order_item__isnull=False # Привязаны к какому-то заказу
|
||||
).exclude(
|
||||
order_item__order=self # Исключаем текущий заказ
|
||||
).select_related('order_item__order')
|
||||
|
||||
if occupied_reservations.exists():
|
||||
# Резервы заняты другим заказом - блокируем переход
|
||||
occupied_res = occupied_reservations.first()
|
||||
other_order_number = occupied_res.order_item.order.order_number
|
||||
other_order_status = occupied_res.order_item.order.status.name if occupied_res.order_item.order.status else 'неизвестен'
|
||||
|
||||
unavailable_kits.append(
|
||||
f"Витринный комплект '{kit.name}' занят заказом #{other_order_number} (статус: {other_order_status})"
|
||||
)
|
||||
else:
|
||||
# Проверяем что вообще есть резервы для этого комплекта
|
||||
any_reservations = Reservation.objects.filter(
|
||||
product_kit=kit,
|
||||
showcase__isnull=False
|
||||
).exists()
|
||||
|
||||
if not any_reservations:
|
||||
# Комплект демонтирован или удалён
|
||||
unavailable_kits.append(
|
||||
f"Витринный комплект '{kit.name}' больше не существует на витрине"
|
||||
)
|
||||
|
||||
# Если есть недоступные комплекты - блокируем переход
|
||||
if unavailable_kits:
|
||||
error_message = (
|
||||
f"Невозможно восстановить заказ #{self.order_number}. "
|
||||
f"Витринные комплекты уже проданы:\n\n" +
|
||||
"\n".join(f"\u2022 {msg}" for msg in unavailable_kits) +
|
||||
f"\n\nОтмените сначала соответствующие заказы или удалите эти позиции из заказа."
|
||||
)
|
||||
raise ValidationError(error_message)
|
||||
|
||||
except Order.DoesNotExist:
|
||||
# Заказ ещё не создан в БД (не должно произойти, но на всякий случай)
|
||||
pass
|
||||
|
||||
# Оборачиваем в транзакцию чтобы ValidationError в сигналах откатывал save()
|
||||
with transaction.atomic():
|
||||
|
||||
Reference in New Issue
Block a user