Advertisement
GeorgiLukanov87

Python OOP Retake Exam - 22 August 2022 - Food Orders App

Nov 12th, 2022 (edited)
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.41 KB | None | 0 0
  1. # Python OOP Retake Exam - 22 August 2022 - Food Orders App
  2.  
  3. # https://judge.softuni.org/Contests/Practice/Index/3591#1
  4. =============================================================================================
  5. # file name: validator.py
  6.  
  7. class Validator:
  8.  
  9.     @staticmethod
  10.     def raise_if_string_is_empty(string: str, error_msg: str):
  11.         if string.strip() == '':
  12.             raise ValueError(error_msg)
  13.  
  14.     @staticmethod
  15.     def raise_if_phone_number_is_invalid(phone_number: str, error_msg):
  16.         if len([n for n in phone_number if n.isdigit()]) != 10 or \
  17.                 phone_number[0] != '0':
  18.             raise ValueError(error_msg)
  19.  
  20.     @staticmethod
  21.     def raise_if_price_less_or_eq_zero(price: float, error_msg):
  22.         if price <= 0:
  23.             raise ValueError(error_msg)
  24.  
  25.     @staticmethod
  26.     def raise_if_menu_is_less_than_5_dishes(menu, error_msg):
  27.         if len(menu) < 5:
  28.             raise Exception(error_msg)
  29.  
  30.     @staticmethod
  31.     def find_client_by_phone_number(phone_number, client_list):
  32.         client = [c for c in client_list if c.phone_number == phone_number]
  33.         if client:
  34.             return client[0]
  35.         return None
  36.  
  37.     @staticmethod
  38.     def raise_if_meal_name_not_in_menu(client_orders, menu):
  39.         for meal, count in client_orders.items():
  40.             if meal not in [m.name for m in menu]:
  41.                 raise Exception(f'{meal} is not on the menu!')
  42.  
  43.     @staticmethod
  44.     def raise_if_qnt_is_wrong(client_orders, menu):
  45.         all_qnt = [order.quantity for order in menu]
  46.         all_products = [product.name for product in menu]
  47.         all_types = [type(product).__name__ for product in menu]
  48.  
  49.         result1 = dict(zip(all_products, all_qnt))
  50.         result2 = dict(zip(all_products, all_types))
  51.  
  52.         for meal, count in client_orders.items():
  53.             if count > result1[meal]:
  54.                 raise Exception(f'Not enough quantity of {result2[meal]}: {meal}!')
  55.  
  56.     @staticmethod
  57.     def remove_qnt_from_general_menu(general_menu, meal, qnt):
  58.         for obj_meal in general_menu:
  59.             if obj_meal.name == meal:
  60.                 obj_meal.quantity -= qnt
  61.  
  62.     @staticmethod
  63.     def add_qnt_to_general_menu(general_menu, meal, qnt):
  64.         for obj in general_menu:
  65.             if obj.name == meal:
  66.                 obj.quantity += qnt
  67.  
  68. =============================================================================================
  69. # file name: dessert.py
  70.  
  71. from project.meals.meal import Meal
  72.  
  73.  
  74. class Dessert(Meal):
  75.  
  76.     def __init__(self, name: str, price: float, quantity=30):
  77.         super().__init__(name, price, quantity)
  78.  
  79.     def details(self):
  80.         return f'Dessert {self.name}: {self.price:.2f}lv/piece'
  81.  
  82. =============================================================================================
  83. # file name: main_dish.py
  84.  
  85. from project.meals.meal import Meal
  86.  
  87.  
  88. class MainDish(Meal):
  89.  
  90.     def __init__(self, name: str, price: float, quantity=50):
  91.         super().__init__(name, price, quantity)
  92.  
  93.     def details(self):
  94.         return f'Main Dish {self.name}: {self.price:.2f}lv/piece'
  95.  
  96. =============================================================================================
  97. # file name: meal.py
  98.  
  99. from abc import ABC, abstractmethod
  100.  
  101. from project.helper.validator import Validator
  102.  
  103.  
  104. class Meal(ABC):
  105.  
  106.     def __init__(self, name: str, price: float, quantity: int):
  107.         self.name = name
  108.         self.price = price
  109.         self.quantity = quantity
  110.  
  111.     @property
  112.     def name(self):
  113.         return self.__name
  114.  
  115.     @name.setter
  116.     def name(self, value):
  117.         Validator.raise_if_string_is_empty(value, 'Name cannot be an empty string!')
  118.         self.__name = value
  119.  
  120.     @property
  121.     def price(self):
  122.         return self.__price
  123.  
  124.     @price.setter
  125.     def price(self, value):
  126.         Validator.raise_if_price_less_or_eq_zero(value, 'Invalid price!')
  127.         self.__price = value
  128.  
  129.     @abstractmethod
  130.     def details(self):
  131.         ...
  132.  
  133. =============================================================================================
  134. # file name: starter.py
  135.  
  136. from project.meals.meal import Meal
  137.  
  138.  
  139. class Starter(Meal):
  140.  
  141.     def __init__(self, name: str, price: float, quantity=60):
  142.         super().__init__(name, price, quantity)
  143.  
  144.     def details(self):
  145.         return f'Starter {self.name}: {self.price:.2f}lv/piece'
  146.  
  147. =============================================================================================
  148. # file name: client.py
  149.  
  150. from project.helper.validator import Validator
  151.  
  152.  
  153. class Client:
  154.     def __init__(self, phone_number: str):
  155.         self.phone_number = phone_number
  156.         self.shopping_cart = []  # List to add OBJs by the client !
  157.         self.bill = float(0.0)
  158.  
  159.     @property
  160.     def phone_number(self):
  161.         return self.__phone_number
  162.  
  163.     @phone_number.setter
  164.     def phone_number(self, value):
  165.         Validator.raise_if_phone_number_is_invalid(value, 'Invalid phone number!')
  166.         self.__phone_number = value
  167.  
  168. =============================================================================================
  169. # file name: food_orders_app.py
  170.  
  171. from project.client import Client
  172. from project.helper.validator import Validator
  173. from project.meals.dessert import Dessert
  174. from project.meals.main_dish import MainDish
  175. from project.meals.meal import Meal
  176. from project.meals.starter import Starter
  177.  
  178.  
  179. class FoodOrdersApp:
  180.     def __init__(self):
  181.         self.menu = []  # all the meals (objects)!
  182.         self.clients_list = []  # all the clients (objects)!
  183.         self.order = 0
  184.  
  185.     def register_client(self, client_phone_number: str):
  186.         client = Client(client_phone_number)
  187.         if [c for c in self.clients_list if c.phone_number == client_phone_number]:
  188.             raise Exception('The client has already been registered!')
  189.         self.clients_list.append(client)
  190.         return f'Client {client_phone_number} registered successfully.'
  191.  
  192.     def add_meals_to_menu(self, *meals: Meal):
  193.         for meal in meals:
  194.             if type(meal).__name__ in ['Starter', 'MainDish', 'Dessert']:
  195.                 self.menu.append(meal)
  196.  
  197.     def show_menu(self):
  198.         Validator.raise_if_menu_is_less_than_5_dishes(self.menu, 'The menu is not ready!')
  199.         result = ''
  200.         for meal in self.menu:
  201.             result += meal.details() + '\n'
  202.         return result.strip()
  203.  
  204.     def add_meals_to_shopping_cart(self, client_phone_number: str, **meal_names_and_quantities):
  205.         client = None
  206.         # Validate menu before adding items to the client!
  207.         Validator.raise_if_menu_is_less_than_5_dishes(self.menu, 'The menu is not ready!')
  208.         # searching for client , if not in the list -> auto-add it !
  209.         client = Validator.find_client_by_phone_number(client_phone_number, self.clients_list)
  210.         if client is None:
  211.             client = Client(client_phone_number)
  212.         self.clients_list.append(client)
  213.         Validator.raise_if_meal_name_not_in_menu(meal_names_and_quantities, self.menu)
  214.         Validator.raise_if_qnt_is_wrong(meal_names_and_quantities, self.menu)
  215.         self.add_client_order_to_client_shopping_card(client, meal_names_and_quantities)
  216.         print_names = [x.name for x in client.shopping_cart]
  217.         return f"Client {client.phone_number} successfully ordered {', '.join(print_names)} for {client.bill:.2f}lv."
  218.  
  219.     def add_client_order_to_client_shopping_card(self, client: Client, client_order):
  220.         class_mapper = {
  221.             'Starter': Starter,
  222.             'MainDish': MainDish,
  223.             'Dessert': Dessert,
  224.         }
  225.         meal_names = []
  226.         for meal, qnt in client_order.items():
  227.             Validator.remove_qnt_from_general_menu(self.menu, meal, qnt)
  228.  
  229.             meal_names.append(meal)
  230.             current_type = [type(obj).__name__ for obj in self.menu if obj.name == meal][0]
  231.             current_price = [obj.price for obj in self.menu if obj.name == meal][0]
  232.             current_meal_obj = class_mapper[current_type](meal, current_price, qnt)
  233.  
  234.             client.bill += current_price * qnt
  235.             client.shopping_cart.append(current_meal_obj)
  236.  
  237.     def cancel_order(self, client_phone_number: str):
  238.         client = Validator.find_client_by_phone_number(client_phone_number, self.clients_list)
  239.         if len(client.shopping_cart) <= 0:
  240.             raise Exception('There are no ordered meals!')
  241.         else:
  242.             for obj in client.shopping_cart:
  243.                 meal_name = obj.name
  244.                 meal_qnt = obj.quantity
  245.                 Validator.add_qnt_to_general_menu(self.menu, meal_name, meal_qnt)
  246.         client.shopping_cart = []
  247.         client.bill = 0
  248.         return f"Client {client_phone_number} successfully canceled his order."
  249.  
  250.     def finish_order(self, client_phone_number: str):
  251.         client = Validator.find_client_by_phone_number(client_phone_number, self.clients_list)
  252.         if len(client.shopping_cart) <= 0:
  253.             raise Exception('There are no ordered meals!')
  254.         self.order += 1
  255.         total_paid_money = client.bill
  256.         client.shopping_cart = []
  257.         client.bill = 0
  258.  
  259.         return f"Receipt #{self.order} with total amount of {total_paid_money:.2f}" \
  260.                f" was successfully paid for {client_phone_number}."
  261.  
  262.     def __str__(self):
  263.         result = f'Food Orders App has {len(self.menu)} meals on the menu ' \
  264.                f'and {len(self.clients_list)} clients.'
  265.         return result.strip()
  266.  
  267.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement