Example #1
0
class PizzaBotMain(object):
    """Это основной класс блока.
    Этот класс содержит информацию о том, какие блюда готовятся в текущий момент, содержит информацию о печах и
    показываает время работы коиска. После завешения заказа, он удаляется из self.current_orders_proceed
    """
    def __init__(self, equipment_data, recipes):
        self.equipment = Equipment(equipment_data)
        self.recipes = recipes
        self.is_cooking_paused = False
        # все заказы за текущий сеанс работы, {id: BaseOrder}
        self.current_orders_proceed = {}
        # все неприготовленые блюда
        self.current_dishes_proceed = {}
        self.time_to_cook_all_dishes_left = 0
        self.orders_requested_for_delivery = {}
        self.is_free = True
        self.main_queue = asyncio.Queue()
        self.delivety_queue = asyncio.Queue()
        self.maintain_queue = asyncio.Queue()

    def checking_order_for_double(self, new_order_id):
        """Этот метод проверяет есть ли уже заказ с таким ref id в обработке
        :return bool"""
        is_new_order = True if new_order_id not in self.current_orders_proceed.keys(
        ) else False
        return is_new_order

    async def get_order_content_from_db(self, new_order_id):
        """Этот метод вызывает процедуру 'Получи состав блюд в заказе' и возвращает словарь вида
        {"refid": new_order_id,
                     "dishes": {"40576654-9f31-11ea-bb37-0242ac130002":
                         {
                             "dough": {"id": 2},
                             "sauce": {"id": 2, "content": ((1, 5), (2, 25))},
                             "filling": {"id": 1, "content": (6, 2, 3, 3, 6, 8)},
                             "additive": {"id": 7}
                         }
                         ,
                         "6327ade2-9f31-11ea-bb37-0242ac130002":
                             {
                                 "dough": {"id": 1},
                                 "sauce": {"id": 2, "content": ((1, 5), (2, 25))},
                                 "filling": {"id": 1, "content": (6, 2, 3, 3, 6, 8)},
                                 "additive": {"id": 1}
                             }
                     }
                     }
        """
        new_order = {
            "refid": new_order_id,
            "dishes": {
                "40576654-9f31-11ea-bb37-0242ac130002": {
                    "dough": {
                        "id": 2
                    },
                    "sauce": {
                        "id": 2,
                        "content": ((1, 5), (2, 25))
                    },
                    "filling": {
                        "id": 1,
                        "content": (6, 2, 3, 3, 6, 8)
                    },
                    "additive": {
                        "id": 7
                    }
                },
                "6327ade2-9f31-11ea-bb37-0242ac130002": {
                    "dough": {
                        "id": 1
                    },
                    "sauce": {
                        "id": 2,
                        "content": ((1, 5), (2, 25))
                    },
                    "filling": {
                        "id": 1,
                        "content": (6, 2, 3, 3, 6, 8)
                    },
                    "additive": {
                        "id": 1
                    }
                }
            }
        }
        return new_order

    def get_recipe_data(self, new_order):
        """Этот метод добавляет в данные о блюде параметры чейнов рецепта для конкретного ингредиента
        :param словарь блюд из заказа
        {'40576654-9f31-11ea-bb37-0242ac130002':
            {'dough': {'id': 2},
            'sauce': {'id': 2, 'content': ((1, 5), (2, 25))},
            'filling': {'id': 1, 'content': (6, 2, 3, 3, 6, 8)},
            'additive': {'id': 7}},
        '6327ade2-9f31-11ea-bb37-0242ac130002':
            {'dough': {'id': 1},
            'sauce': {'id': 2, 'content': ((1, 5), (2, 25))},
            'filling': {'id': 1, 'content': (6, 2, 3, 3, 6, 8)},
            'additive': {'id': 1}}}

        Возвращаемый результат, где filling -->content tuple 0 - halfstaff_id, 1 - {cutting_program}
        {'refid': 65, 'dishes': [
        {'dough': {'id': 2, 'recipe': {1: 10, 2: 5, 3: 10, 4: 10, 5: 12, 6: 7, 7: 2}},

        'sauce': {'id': 2,
                 'content': ((1, 5), (2, 25)),
                'recipe':
                        {'duration': 20,
                        'content': {1:
                                     {'program': 1, 'sauce_station': None, 'qt': 5},
                                    2:
                                      {'program': 3, 'sauce_station': None, 'qt': 25}}}},

        'filling': {'id': 1,
        'content': ((6, {'program_id': 2, 'duration': 10}), (2, {'program_id': 1, 'duration': 12}),
        (3, {'program_id': 5, 'duration': 15}), (3, {'program_id': 8, 'duration': 8}),
        (6, {'program_id': 4, 'duration': 17}), (8, {'program_id': 9, 'duration': 9})),
        'cooking_program': (2, 180), 'heating_program': (2, 20), 'chain': {}},

        'additive': {'id': 7, 'recipe': {1: 5}}},

        {'dough': {'id': 1, 'recipe': {1: 10, 2: 5, 3: 10, 4: 10, 5: 12, 6: 7, 7: 2}},

        'sauce': {'id': 2,
                 'content': ((1, 5), (2, 25)),
                'recipe':
                        {'duration': 20,
                        'content': {1:
                                     {'program': 1, 'sauce_station': None, 'qt': 5},
                                    2:
                                      {'program': 3, 'sauce_station': None, 'qt': 25}}}},
        'filling': {'id': 1, 'content': ((6, {'program_id': 2, 'duration': 10}),
        (2, {'program_id': 1, 'duration': 12}), (3, {'program_id': 5, 'duration': 15}),
        (3, {'program_id': 8, 'duration': 8}), (6, {'program_id': 4, 'duration': 17}),
        (8, {'program_id': 9, 'duration': 9})),
        'cooking_program': (1, 180), 'heating_program': (1, 20), 'chain': {}},

        'additive': {'id': 1, 'recipe': {1: 5}}}]}
"""

        # print("Входные данные", new_order)

        def create_sauce_recipe(self, dish):
            """Этот метод выбирает рецепт для конкретного компонента соуса из общей базы рецептов"""
            sauce_id = dish["sauce"]["id"]
            dish["sauce"]["recipe"] = self.recipes["sauce"][sauce_id]
            for component, my_tuple in zip(dish["sauce"]["recipe"]["content"],
                                           dish["sauce"]["content"]):
                dish["sauce"]["recipe"]["content"][component]["qt"] = my_tuple[
                    1]
            print("составили рецепт соуса", dish["sauce"])

        def create_filling_recipe(self, dish):
            """Этот метод выбирает рецепт начинки для начинки в общем и для каждого компонента начинки в целом"""
            filling_id = dish["filling"]["id"]
            dough_id = dish["dough"]["id"]
            dish["filling"]["cooking_program"] = self.recipes["filling"][
                filling_id]["cooking_program"][dough_id]
            dish["filling"]["heating_program"] = self.recipes["filling"][
                filling_id]["heating_program"][dough_id]
            dish["filling"]["chain"] = self.recipes["filling"][filling_id][
                "chain"]
            halfstaff_content = dish["filling"]["content"]
            cutting_program = self.recipes["filling"][filling_id][
                "cutting_program"]
            dish["filling"]["content"] = tuple(
                zip(halfstaff_content, cutting_program))
            print("Составили рецепт начинки", dish["filling"])

        for dish in new_order.values():
            dish["dough"]["recipe"] = self.recipes["dough"]
            create_sauce_recipe(self, dish)
            create_filling_recipe(self, dish)
            dish["additive"]["recipe"] = self.recipes["additive"]
            print("В блюдо добавили рецепт")

    def fill_current_dishes_proceed(self, dish):
        """ Добавляет блюда заказа в self.current_dishes_proceed
        @:param order: экземпляр класса блюдо, созданный в self.create_new_order"""
        self.current_dishes_proceed[dish.id] = dish

    async def create_new_order(self, new_order):
        """Этот метод создает экземпляр класса Order и заносит его в словарь self.current_orders_proceed
        @:params:
        new_order - это словарь с блюдами, получаемый из БД в рамках метода get_order_content_from_db """

        try:
            # резервируем печи для заказа (сразу 2 шт)
            ovens_reserved = [
                self.equipment.oven_reserve(dish)
                for dish in new_order["dishes"]
            ]
            # создаем экземпляр класса заказа
            order = BaseOrder(new_order, ovens_reserved)
            if order:
                # если заказ создан успешно, помещаем его в словарь всех готовящихся заказов
                self.current_orders_proceed[order.ref_id] = order
                # for dish in order.dishes:
                #     self.main_queue.append((1, dish))
                for dish in order.dishes:
                    self.fill_current_dishes_proceed(dish)
                    await self.put_chains_in_queue(dish)

                # перемещаем заказы в словарь всех готовящихся блюд
                # self.fill_current_dishes_proceed(order)
        # придумать ошибки какие могут быть
        except ValueError:
            pass

    # def fill_current_dishes_proceed(self, order):
    #     """ Добавляет блюда заказа в self.current_dishes_proceed
    #     @:param order: экземпляр класса заказ, созданный в self.create_new_order"""
    #
    #     for dish in order.dishes:
    #         self.current_dishes_proceed[dish.id] = dish

    async def put_chains_in_queue(self, dish):
        """Добавляет чейны рецепта в очередь готовки в виде кортежа (dish, chain)"""
        chains = dish.chain_list
        for chain in chains:
            await self.main_queue.put((dish, chain))
        self.is_free = False

    def check_if_free(self):
        one = True if self.main_queue.empty() else False
        two = True if self.maintain_queue.empty() else False
        three = True if self.delivety_queue.empty() else False
        self.is_free = True if one and two and three else False
        print("Можно ли танцевать? ", self.is_free)

    async def hello_from_qr_code(self, qr_code_data):
        self.delivety_queue.put(qr_code_data)
        print("QR код обработан", time.time())

    async def hello_from_broken_oven(self):
        print("Изменение статуса оборудования обработано", time.time())

    async def controllers_alert_handler(self, cntrls_events):
        """Эта курутина обрабатывает уведомления от контроллеров: отказ оборудования и qr код """

        print("Переключились в контролеры", time.time())

        async def wait_for_qr_code(cntrls_events):
            """new_data - ckjdfhm {'ref_id': 65, 'pickup': 1}"""
            event_name = "qr_scanned"
            event = cntrls_events.get_dispatcher_event(event_name)
            while True:
                event_data = await event
                _, qr_code_data = event_data
                qr_code_data = qr_code_data["params"]
                self.check_order_status(qr_code_data)

        async def wait_for_hardware_status_changed(cntrls_events):
            """new_data - словарь {'unit_name': 'owen_cell_2', 'status': 'broken'} """
            event_name = "hardware_status_changed"
            event = cntrls_events.get_dispatcher_event(event_name)
            while True:
                event_data = await event
                _, new_data = event_data
                await self.equipment.oven_broke_handler(new_data)

        qr_event_waiter = asyncio.create_task(wait_for_qr_code(cntrls_events))
        status_change_waiter = asyncio.create_task(
            wait_for_hardware_status_changed(cntrls_events))
        await asyncio.gather(qr_event_waiter, status_change_waiter)

    async def cooking(self):
        """Эта курутина обеспеивает вызов методов по приготовлению блюд и другой важной работе"""

        while True:
            print("Работает cooking", time.time())

            # if self.current_dishes_proceed.keys():
            #     print("Начнаем готовить")
            #     _, current_dish = self.current_dishes_proceed.popitem()
            #     for chain in current_dish.chain_list:
            #         is_chain_succeed = await chain(current_dish)
            #         print("Результат из вызова", is_chain_succeed)
            #         if not is_chain_succeed:
            #             print("Блюло не приготовилось")
            #             break

            time_limit = None

            self.check_if_free()
            if self.is_free:
                print("Dancing 3 secs")
                await asyncio.sleep(3)
            else:
                if not self.delivety_queue.empty():
                    print("Выдаем заказ")
                    self.delivety_queue.get()
                    await asyncio.sleep(5)
                elif not self.main_queue.empty():
                    print("Готовим блюдо")
                    dish, chain_to_do = await self.main_queue.get()
                    if dish.status != "failed_to_be_cooked":
                        await chain_to_do(dish)
                    else:
                        continue

                elif not self.maintain_queue.empty():
                    print("Моем или выкидываем пиццу")

            # else:
            #     print("Dancing 3 secs")
            #     await asyncio.sleep(3)

    """Валиация qr кода
       входные данные: чек код заказа и номер пункта выдачи
       выходные данные: сообщение контроллеру, запускается выдача заказа, если он готов, выдача подарка, если произошла ошибка
       ORDER_STATUS = ["received", "cooking", "ready", "informed", "packed", "wait to delivery", "delivered", "closed",
                       "failed_to_be_cooked", "not_delivered"]
       добавить статус "time_is_up"
       """

    STATUS_FOR_CNTRL = {
        "ready": "заказ готов, скоро будет доставлен",
        "failed_to_be_cooked": "не смогли приготовить",
        "cooking": "находится в процессе готовки",
        "time_is_up": "время получения заказа истекло",
        "delivered": "заказ уже получен",
        "not_found": "заказ не найден"
    }

    def check_order_status(self, params):
        """Этот метод проверяет, есть ли заказ с таким чек кодом в current_orders_proceed.
        Входные данные params: полученный от контроллера словарь с чек кодом заказа и окном выдачи
        "ref_id": int, "pickup": int"""
        order_check_code = params["ref_id"]
        if order_check_code in self.current_orders_proceed:
            print("Валидный qr code")
            order_status = self.current_orders_proceed[order_check_code].status
            self.order_status_handler(order_status, params)
        else:
            self.status_to_cntrl("not_found")

    def order_status_handler(self, order_status, qr_code_data):
        """Этот метод анализирует статус и запускает обработчик отправляет значение контролеру"""
        if order_status == "ready":
            print("Валидный qr code, надо выдать заказ")
            order_check_code = qr_code_data["ref_id"]
            self.orders_requested_for_delivery[order_check_code] = qr_code_data
            self.status_to_cntrl("ready")
        elif order_status == "packed" or order_status == "wait to delivery":
            self.status_to_cntrl("ready")
        elif order_status == "cooking" or order_status == "received":
            self.status_to_cntrl("cooking")
        elif order_status == "failed_to_be_cooked":
            self.present_delivery_handler()
            self.status_to_cntrl("failed_to_be_cooked")
        else:
            self.status_to_cntrl(order_status)

    def status_to_cntrl(self, status_of_order):
        """Передает контроллу значение, на основании которого пользователю выводится информация о заказе"""
        print("контроллеру передано сообщение: ",
              self.STATUS_FOR_CNTRL[status_of_order])
        # обращеноие к контролу

    async def present_delivery_handler(self):
        """Обрабатывает процедуру получения подарка"""
        print("получение подарка")
        pass