From cb0dad191626ad47e1764737aa605a26c5b1b85f Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Wed, 21 Aug 2024 23:44:39 +0200 Subject: [PATCH] WIP: Catering Orders --- src/EzLanManager.py | 12 ++++++- .../services/CateringService.py | 30 ++++++++++++++++-- .../services/DatabaseService.py | 31 ++++++++++++++++++- src/ez_lan_manager/services/UserService.py | 2 +- src/ez_lan_manager/types/CateringMenuItem.py | 3 ++ src/ez_lan_manager/types/CateringOrder.py | 10 ++++-- 6 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/EzLanManager.py b/src/EzLanManager.py index e1a00c3..ad5f8bb 100644 --- a/src/EzLanManager.py +++ b/src/EzLanManager.py @@ -11,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 +from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItemCategory, CateringMenuItem logger = logging.getLogger(__name__.split(".")[-1]) @@ -27,4 +28,13 @@ 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) + catering_service = CateringService(db_service, accounting_service, user_service) + #print(catering_service.get_menu()) + + # catering_service.place_order( + # { + # CateringMenuItem(item_id=5, name='Bier', price=250, category=CateringMenuItemCategory.BEVERAGE_ALCOHOLIC, additional_info="Pils", is_disabled=False): 12, + # CateringMenuItem(item_id=6, name='Pizza Hawaii', price=900, category=CateringMenuItemCategory.MAIN_COURSE, additional_info = '', is_disabled = False): 2 + # }, + # 19 + # ) diff --git a/src/ez_lan_manager/services/CateringService.py b/src/ez_lan_manager/services/CateringService.py index d9a1bdc..837fd24 100644 --- a/src/ez_lan_manager/services/CateringService.py +++ b/src/ez_lan_manager/services/CateringService.py @@ -1,23 +1,47 @@ +import logging 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.services.UserService import UserService +from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus, CateringMenuItemsWithAmount from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory +logger = logging.getLogger(__name__.split(".")[-1]) + class CateringError(Exception): def __init__(self, message: str) -> None: self.message = message class CateringService: - def __init__(self, db_service: DatabaseService, accounting_service: AccountingService): + def __init__(self, db_service: DatabaseService, accounting_service: AccountingService, user_service: UserService): self._db_service = db_service self._accounting_service = accounting_service + self._user_service = user_service # ORDERS - def place_order(self, menu_items: list[CateringMenuItem], user_id: int, is_delivery: bool = True) -> CateringOrder: + def place_order(self, menu_items: CateringMenuItemsWithAmount, user_id: int, is_delivery: bool = True) -> CateringOrder: + for menu_item in menu_items: + if menu_item.is_disabled: + raise CateringError("Order includes disabled items") + + user = self._user_service.get_user(user_id) + if not user: + raise CateringError("User does not exist") + + total_price = sum([item.price * quantity for item, quantity in menu_items.items()]) + if self._accounting_service.get_balance(user_id) < total_price: + raise CateringError("Insufficient funds") + + order = self._db_service.add_new_order(menu_items, user_id, is_delivery) + if order: + self._accounting_service.remove_balance(user_id, total_price, f"CATERING - {order.order_id}") + logger.info(f"User '{order.customer.user_name}' (ID:{order.customer.user_id}) ordered from catering for {self._accounting_service.make_euro_string_from_int(total_price)}") + return order + + def update_order_status(self, order_id: int, new_status: CateringOrderStatus) -> None: pass def get_orders(self) -> list[CateringOrder]: diff --git a/src/ez_lan_manager/services/DatabaseService.py b/src/ez_lan_manager/services/DatabaseService.py index 3428174..151e04d 100644 --- a/src/ez_lan_manager/services/DatabaseService.py +++ b/src/ez_lan_manager/services/DatabaseService.py @@ -1,12 +1,14 @@ import logging import sys -from datetime import date +from datetime import date, datetime from typing import Optional import mariadb from mariadb import Cursor +from src.ez_lan_manager.types.CateringOrder import CateringOrder from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory +from src.ez_lan_manager.types.CateringOrder import CateringMenuItemsWithAmount, CateringOrderStatus 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 @@ -381,3 +383,30 @@ class DatabaseService: logger.warning(f"Error updating menu item: {e}") return False return bool(affected_rows) + + def add_new_order(self, menu_items: CateringMenuItemsWithAmount, user_id: int, is_delivery: bool) -> Optional[CateringOrder]: + now = datetime.now() + cursor = self._get_cursor() + try: + cursor.execute( + "INSERT INTO orders (status, user, is_delivery, order_date) VALUES (?, ?, ?, ?);", + (CateringOrderStatus.RECEIVED.value, user_id, is_delivery, now) + ) + order_id = cursor.lastrowid + for menu_item, quantity in menu_items.items(): + cursor.execute( + "INSERT INTO order_catering_menu_item (order_id, catering_menu_item_id, quantity) VALUES (?, ?, ?);", + (order_id, menu_item.item_id, quantity) + ) + self._connection.commit() + return CateringOrder( + order_id=order_id, + order_date=now, + status=CateringOrderStatus.RECEIVED, + items=menu_items, + customer=self.get_user_by_id(user_id), + is_delivery=is_delivery + ) + except Exception as e: + logger.warning(f"Error placing order: {e}") + return diff --git a/src/ez_lan_manager/services/UserService.py b/src/ez_lan_manager/services/UserService.py index a671aa1..d971ca5 100644 --- a/src/ez_lan_manager/services/UserService.py +++ b/src/ez_lan_manager/services/UserService.py @@ -16,7 +16,7 @@ class UserService: def __init__(self, db_service: DatabaseService) -> None: self._db_service = db_service - def get_user(self, accessor: Union[str, int]) -> User: + def get_user(self, accessor: Union[str, int]) -> Optional[User]: if isinstance(accessor, int): return self._db_service.get_user_by_id(accessor) if "@" in accessor: diff --git a/src/ez_lan_manager/types/CateringMenuItem.py b/src/ez_lan_manager/types/CateringMenuItem.py index e5353ff..5de46b6 100644 --- a/src/ez_lan_manager/types/CateringMenuItem.py +++ b/src/ez_lan_manager/types/CateringMenuItem.py @@ -21,3 +21,6 @@ class CateringMenuItem: category: CateringMenuItemCategory additional_info: str = str() is_disabled: bool = False + + def __hash__(self) -> int: + return hash(str(self.item_id) + self.name) diff --git a/src/ez_lan_manager/types/CateringOrder.py b/src/ez_lan_manager/types/CateringOrder.py index 51ef04b..54aad54 100644 --- a/src/ez_lan_manager/types/CateringOrder.py +++ b/src/ez_lan_manager/types/CateringOrder.py @@ -1,9 +1,12 @@ from dataclasses import dataclass +from datetime import datetime from enum import StrEnum -from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem +from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory from src.ez_lan_manager.types.User import User +CateringMenuItemsWithAmount = dict[CateringMenuItem, int] + class CateringOrderStatus(StrEnum): RECEIVED = "RECEIVED" @@ -16,11 +19,12 @@ class CateringOrderStatus(StrEnum): @dataclass(frozen=True) class CateringOrder: order_id: int + order_date: datetime status: CateringOrderStatus - items: list[CateringMenuItem] + items: CateringMenuItemsWithAmount customer: User is_delivery: bool = True @property def price(self) -> int: - return sum([item.price for item in self.items]) + return sum([item.price for item in self.items.keys()])