diff --git a/src/EzLanManager.py b/src/EzLanManager.py index 5d0d235..e1a00c3 100644 --- a/src/EzLanManager.py +++ b/src/EzLanManager.py @@ -3,6 +3,7 @@ import logging from from_root import from_root from src.ez_lan_manager.services.AccountingService import AccountingService +from src.ez_lan_manager.services.CateringService import CateringService from src.ez_lan_manager.services.ConfigurationService import ConfigurationService from src.ez_lan_manager.services.DatabaseService import DatabaseService from src.ez_lan_manager.services.MailingService import MailingService @@ -10,6 +11,7 @@ from src.ez_lan_manager.services.NewsService import NewsService from src.ez_lan_manager.services.SeatingService import SeatingService from src.ez_lan_manager.services.TicketingService import TicketingService from src.ez_lan_manager.services.UserService import UserService + logger = logging.getLogger(__name__.split(".")[-1]) if __name__ == "__main__": @@ -25,3 +27,4 @@ if __name__ == "__main__": mailing_service = MailingService(configuration_service.get_mailing_service_configuration()) ticketing_service = TicketingService(lan_info, db_service, accounting_service) seating_service = SeatingService(seating_config, lan_info, db_service, ticketing_service) + catering_service = CateringService(db_service, accounting_service) diff --git a/src/ez_lan_manager/services/CateringService.py b/src/ez_lan_manager/services/CateringService.py new file mode 100644 index 0000000..d9a1bdc --- /dev/null +++ b/src/ez_lan_manager/services/CateringService.py @@ -0,0 +1,82 @@ +from typing import Optional + +from src.ez_lan_manager.services.AccountingService import AccountingService +from src.ez_lan_manager.services.DatabaseService import DatabaseService +from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus +from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory + +class CateringError(Exception): + def __init__(self, message: str) -> None: + self.message = message + + +class CateringService: + def __init__(self, db_service: DatabaseService, accounting_service: AccountingService): + self._db_service = db_service + self._accounting_service = accounting_service + + # ORDERS + + def place_order(self, menu_items: list[CateringMenuItem], user_id: int, is_delivery: bool = True) -> CateringOrder: + pass + + def get_orders(self) -> list[CateringOrder]: + pass + + def get_orders_for_user(self, user_id: int) -> list[CateringOrder]: + pass + + def get_orders_by_status(self, status: CateringOrderStatus) -> list[CateringOrder]: + pass + + def cancel_order(self, order: CateringOrder) -> None: + pass + + # MENU ITEMS + + def get_menu(self, category: Optional[CateringMenuItemCategory] = None) -> list[CateringMenuItem]: + items = self._db_service.get_menu_items() + if not category: + return items + return list(filter(lambda item: item.category == category, items)) + + def get_menu_item_by_id(self, menu_item_id: int) -> CateringMenuItem: + item = self._db_service.get_menu_item(menu_item_id) + if not item: + raise CateringError("Menu item not found") + return item + + def add_menu_item(self, name: str, info: str, price: int, category: CateringMenuItemCategory, is_disabled: bool = False) -> CateringMenuItem: + if new_item := self._db_service.add_menu_item(name, info, price, category, is_disabled): + return new_item + raise CateringError(f"Could not add item '{name}' to the menu.") + + def remove_menu_item(self, menu_item_id: int) -> bool: + return self._db_service.delete_menu_item(menu_item_id) + + def change_menu_item(self, updated_item: CateringMenuItem) -> bool: + return self._db_service.update_menu_item(updated_item) + + def disable_menu_item(self, menu_item_id: int) -> bool: + try: + item = self.get_menu_item_by_id(menu_item_id) + except CateringError: + return False + item.is_disabled = True + return self._db_service.update_menu_item(item) + + def enable_menu_item(self, menu_item_id: int) -> bool: + try: + item = self.get_menu_item_by_id(menu_item_id) + except CateringError: + return False + item.is_disabled = False + return self._db_service.update_menu_item(item) + + def disable_menu_items_by_category(self, category: CateringMenuItemCategory) -> bool: + items = self.get_menu(category=category) + return all([self.disable_menu_item(item.item_id) for item in items]) + + def enable_menu_items_by_category(self, category: CateringMenuItemCategory) -> bool: + items = self.get_menu(category=category) + return all([self.enable_menu_item(item.item_id) for item in items]) diff --git a/src/ez_lan_manager/services/DatabaseService.py b/src/ez_lan_manager/services/DatabaseService.py index 67431d8..3428174 100644 --- a/src/ez_lan_manager/services/DatabaseService.py +++ b/src/ez_lan_manager/services/DatabaseService.py @@ -6,6 +6,7 @@ from typing import Optional import mariadb from mariadb import Cursor +from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration from src.ez_lan_manager.types.News import News from src.ez_lan_manager.types.Seat import Seat @@ -294,3 +295,89 @@ class DatabaseService: logger.warning(f"Error seating user: {e}") return False return bool(affected_rows) + + def get_menu_items(self) -> list[CateringMenuItem]: + results = [] + cursor = self._get_cursor() + try: + cursor.execute("SELECT * FROM catering_menu_items;") + except Exception as e: + logger.warning(f"Error fetching menu items: {e}") + return results + + for menu_item_raw in cursor.fetchall(): + results.append(CateringMenuItem( + item_id=menu_item_raw[0], + name=menu_item_raw[1], + additional_info=menu_item_raw[2], + price=menu_item_raw[3], + category=CateringMenuItemCategory(menu_item_raw[4]), + is_disabled=bool(menu_item_raw[5]) + )) + + return results + + def get_menu_item(self, menu_item_id) -> Optional[CateringMenuItem]: + cursor = self._get_cursor() + try: + cursor.execute("SELECT * FROM catering_menu_items WHERE catering_menu_item_id = ?;", (menu_item_id, )) + except Exception as e: + logger.warning(f"Error fetching menu items: {e}") + return + + raw_data = cursor.fetchone() + if raw_data is None: + return + return CateringMenuItem( + item_id=raw_data[0], + name=raw_data[1], + additional_info=raw_data[2], + price=raw_data[3], + category=CateringMenuItemCategory(raw_data[4]), + is_disabled=bool(raw_data[5]) + ) + + def add_menu_item(self, name: str, info: str, price: int, category: CateringMenuItemCategory, is_disabled: bool = False) -> Optional[CateringMenuItem]: + cursor = self._get_cursor() + try: + cursor.execute( + "INSERT INTO catering_menu_items (name, additional_info, price, category, is_disabled) VALUES (?, ?, ?, ?, ?);", + (name, info, price, category.value, is_disabled) + ) + self._connection.commit() + except Exception as e: + logger.warning(f"Error adding menu item: {e}") + return + + return CateringMenuItem( + item_id=cursor.lastrowid, + name=name, + additional_info=info, + price=price, + category=category, + is_disabled=is_disabled + ) + + def delete_menu_item(self, menu_item_id: int) -> bool: + cursor = self._get_cursor() + try: + cursor.execute("DELETE FROM catering_menu_items WHERE catering_menu_item_id = ?;", (menu_item_id,)) + self._connection.commit() + except Exception as e: + logger.warning(f"Error deleting menu item: {e}") + return False + return bool(cursor.affected_rows) + + def update_menu_item(self, updated_item: CateringMenuItem) -> bool: + cursor = self._get_cursor() + try: + cursor.execute( + "UPDATE catering_menu_items SET name = ?, additional_info = ?, price = ?, category = ?, is_disabled = ? WHERE catering_menu_item_id = ?;", + (updated_item.name, updated_item.additional_info, updated_item.price, updated_item.category.value, updated_item.is_disabled, updated_item.item_id) + ) + affected_rows = cursor.rowcount + self._connection.commit() + except Exception as e: + logger.warning(f"Error updating menu item: {e}") + return False + return bool(affected_rows) diff --git a/src/ez_lan_manager/types/CateringMenuItem.py b/src/ez_lan_manager/types/CateringMenuItem.py new file mode 100644 index 0000000..e5353ff --- /dev/null +++ b/src/ez_lan_manager/types/CateringMenuItem.py @@ -0,0 +1,23 @@ +from dataclasses import dataclass +from enum import StrEnum + +class CateringMenuItemCategory(StrEnum): + MAIN_COURSE = "MAIN_COURSE" + DESSERT = "DESSERT" + BEVERAGE_NON_ALCOHOLIC = "BEVERAGE_NON_ALCOHOLIC" + BEVERAGE_ALCOHOLIC = "BEVERAGE_ALCOHOLIC" + BEVERAGE_COCKTAIL = "BEVERAGE_COCKTAIL" + BEVERAGE_SHOT = "BEVERAGE_SHOT" + BREAKFAST = "BREAKFAST" + SNACK = "SNACK" + NON_FOOD = "NON_FOOD" + + +@dataclass(frozen=False) +class CateringMenuItem: + item_id: int + name: str + price: int + category: CateringMenuItemCategory + additional_info: str = str() + is_disabled: bool = False diff --git a/src/ez_lan_manager/types/CateringOrder.py b/src/ez_lan_manager/types/CateringOrder.py new file mode 100644 index 0000000..51ef04b --- /dev/null +++ b/src/ez_lan_manager/types/CateringOrder.py @@ -0,0 +1,26 @@ +from dataclasses import dataclass +from enum import StrEnum + +from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem +from src.ez_lan_manager.types.User import User + + +class CateringOrderStatus(StrEnum): + RECEIVED = "RECEIVED" + DELAYED = "DELAYED" + READY_FOR_PICKUP = "READY_FOR_PICKUP" + EN_ROUTE = "EN_ROUTE" + COMPLETED = "COMPLETED" + CANCELED = "CANCELED" + +@dataclass(frozen=True) +class CateringOrder: + order_id: int + status: CateringOrderStatus + items: list[CateringMenuItem] + customer: User + is_delivery: bool = True + + @property + def price(self) -> int: + return sum([item.price for item in self.items])