diff --git a/myproject/orders/models/order.py b/myproject/orders/models/order.py index 9e32dee..7d2cfc8 100644 --- a/myproject/orders/models/order.py +++ b/myproject/orders/models/order.py @@ -178,6 +178,8 @@ class Order(models.Model): def save(self, *args, **kwargs): from django.db import transaction from django.core.exceptions import ValidationError + import logging + logger = logging.getLogger(__name__) # Генерируем уникальный номер заказа при создании (начиная с 100 для 3-значного поиска) if not self.order_number: @@ -188,6 +190,65 @@ class Order(models.Model): else: self.order_number = 100 + # === АВТОМАТИЧЕСКИЙ ПРОМЕЖУТОЧНЫЙ ПЕРЕХОД: cancelled → draft → completed === + # При прямом переходе из отрицательного (cancelled) в положительный (completed) статус, + # делаем промежуточный переход через нейтральный статус 'draft'. + # Это гарантирует корректную работу всех сигналов: + # 1. cancelled → draft: витринные букеты available → reserved + # 2. draft → completed: резервы и букеты корректно финализируются в sold + if self.pk: # Только при редактировании + try: + old_instance = Order.objects.get(pk=self.pk) + old_status = old_instance.status + new_status = self.status + + # Проверяем: переход от отрицательного к положительному? + if (old_status and old_status.is_negative_end and + new_status and new_status.is_positive_end): + + logger.info( + f"🔄 Заказ #{self.order_number}: Обнаружен прямой переход " + f"{old_status.name} (отрицательный) → {new_status.name} (положительный). " + f"Выполняем автоматический промежуточный переход через 'draft'..." + ) + + # Получаем статус 'draft' + try: + draft_status = OrderStatus.objects.get(code='draft', is_system=True) + except OrderStatus.DoesNotExist: + raise ValidationError( + f"Невозможно выполнить переход из '{old_status.name}' в '{new_status.name}': " + f"системный статус 'draft' не найден. Обратитесь к администратору." + ) + + # Сохраняем целевой статус для второго шага + target_status = new_status + + # ШАГ 1: cancelled → draft + logger.info(f" 📍 Шаг 1/2: {old_status.name} → draft") + self.status = draft_status + with transaction.atomic(): + super().save(*args, **kwargs) + + # Обновляем old_instance для следующего шага + old_instance.refresh_from_db() + + # ШАГ 2: draft → completed + logger.info(f" 📍 Шаг 2/2: draft → {target_status.name}") + self.status = target_status + with transaction.atomic(): + super().save(*args, **kwargs) + + logger.info( + f"✅ Заказ #{self.order_number}: Промежуточный переход завершён успешно. " + f"Итоговый статус: {target_status.name}" + ) + return # Выходим, т.к. save() уже вызван дважды + + except Order.DoesNotExist: + # Заказ ещё не создан в БД (не должно произойти, но на всякий случай) + pass + # === ВАЛИДАЦИЯ: Проверяем доступность витринных комплектов === # При переходе ИЗ cancelled к любому не-отменённому статусу if self.pk: # Только при редактировании