• Пункт 1

Для решения данной задачи я бы применил абстрактные модели django.

class AbstractState(models.Model):

class Meta:
    abstract = True

@classmethod
def get(cls, state_id):
    return cls.objects.get(pk=state_id)class 


DeliveryState(AbstractState):

class Meta:
    verbose_name = "Состояние доставки"
    verbose_name_plural = "Состояния доставок"

STATE_NEW = 1  # Новая
STATE_ISSUED = 2  # Выдана курьеру
STATE_DELIVERED = 3  # Доставлена
STATE_HANDED = 4  # Курьер сдал
STATE_REFUSED = 5  # Отказ
STATE_PAID_REFUSED = 6  # Отказ с оплатой курьеру
STATE_COMPLETE = 7  # Завершена
STATE_NONE = 8  # Не определено

Соответсвенно, теперь сможем работать так:

delivery_state = DeliveryState.get(DeliveryState.STATE_NEW)

  • Пункт 2

Для решения данной задачи используем сигналы pre-save и post-save.

@receiver(pre_save, sender=Lead)
    def validate_lead_state_transition(sender, instance, **kwargs):
        if instance.pk:
            # Получаем предыдущее состояние объекта из базы данных
            previous_state = Lead.objects.get(pk=instance.pk).state_id
    
    # Определяем возможные переходы между состояниями
    valid_transitions = {
        LeadState.STATE_NEW: [LeadState.STATE_IN_PROGRESS],
        LeadState.STATE_IN_PROGRESS: [LeadState.STATE_POSTPONED, LeadState.STATE_DONE],
        LeadState.STATE_POSTPONED: [LeadState.STATE_IN_PROGRESS, LeadState.STATE_DONE],
        LeadState.STATE_DONE: []
    }
    
    # Проверяем, является ли запрошенный переход допустимым
    if instance.state_id not in valid_transitions[previous_state]:
        raise ValueError("Недопустимый переход состояния")

@receiver(post_save, sender=Lead)
def perform_lead_state_transition(sender, instance, **kwargs):
    if instance.pk:
        # Получаем предыдущее состояние объекта из базы данных
        previous_state = Lead.objects.get(pk=instance.pk).state_id
    
    # Определяем действия, связанные с каждым переходом состояния
    state_actions = {
        (LeadState.STATE_NEW, LeadState.STATE_IN_PROGRESS): instance.method1,
        (LeadState.STATE_IN_PROGRESS, LeadState.STATE_POSTPONED): instance.method2,
        (LeadState.STATE_IN_PROGRESS, LeadState.STATE_DONE): instance.method3,
        (LeadState.STATE_POSTPONED, LeadState.STATE_IN_PROGRESS): instance.method4,
        (LeadState.STATE_POSTPONED, LeadState.STATE_DONE): instance.method5
    }
    
    # Выполняем соответствующее действие для выполненного перехода состояния
    if instance.state_id != previous_state and (previous_state, instance.state_id) in state_actions:
        action = state_actions[(previous_state, instance.state_id)]
        action()

def method1(self):
    # Дополнительная бизнес логика для перехода из "Новый" в "В работе"
    pass

def method2(self):
    # Дополнительная бизнес логика для перехода из "В работе" в "Приостановлен"
    pass

def method3(self):
    # Дополнительная бизнес логика для перехода из "В работе" в "Завершен"
    pass

def method4(self):
    # Дополнительная бизнес логика для перехода из "Приостановлен" в "В работе"
    pass

def method5(self):
    # Дополнительная бизнес логика для перехода из "Приостановлен" в "Завершен"
    pass
  • Пункт 3

В данном коде убрал не нужные проверки, добавил тразакционность, проверку баланса пользователя перед списанием средтсв, обновление статуса товара (т.к.товар уникален). `

@classmethod
def buy(cls, user, item_id):
    with transaction.atomic():
        product = Product.objects.select_for_update().get(item_id=item_id)
            if product.available and user.balance >= product.price:
                try:
                    # списание средств со счета пользователя
                    user.withdraw(product.price)
                
                # информация о купленном товаре
                send_email_to_user_of_buy_product(user)
                
                # обновление состояния товара
                product.available = False
                product.buyer = user
                product.save()
                
                return True
            except Exception as e:
                # обработка возможных исключений при списании средств или отправке почты
                # логирование ошибки
                return False
        else:
            return False
    else:
        return False
  • Пункт 4

    def print_tariff_info(tariff_info, indent=0):

      for key, value in tariff_info.items():
          if isinstance(value, dict):
              print(' ' * indent + key)
              print_tariff_info(value, indent + 2)
          elif isinstance(value, list):
              print(' ' * indent + key)
              for item in value:
                  if isinstance(item, dict):
                      print_tariff_info(item, indent + 2)
                  else:
                      print(' ' * (indent + 2) + item)
          else:
              print(' ' * (indent + 2) + key)
    

    print_tariff_info(tariff_info['root'])`