Add Catering Management #4
@ -25,6 +25,6 @@ class CateringCartItem(Component):
|
|||||||
return Row(
|
return Row(
|
||||||
Text(self.ellipsize_string(self.article_name), align_x=0, overflow="wrap", min_width=19, style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
Text(self.ellipsize_string(self.article_name), align_x=0, overflow="wrap", min_width=19, style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
||||||
Text(AccountingService.make_euro_string_from_int(self.article_price), style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
Text(AccountingService.make_euro_string_from_int(self.article_price), style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
||||||
IconButton(icon="material/close", size=2, color=self.session.theme.danger_color, style="plain-text", on_press=lambda: self.remove_item_cb(self.list_id)),
|
IconButton(icon="material/close", min_size=2, color=self.session.theme.danger_color, style="plain-text", on_press=lambda: self.remove_item_cb(self.list_id)),
|
||||||
proportions=(19, 5, 2)
|
proportions=(19, 5, 2)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from rio import Component, Row, Card, Column, Text, TextStyle, Spacer
|
||||||
|
|
||||||
|
from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus
|
||||||
|
from src.ez_lan_manager.types.Seat import Seat
|
||||||
|
|
||||||
|
|
||||||
|
class CateringManagementOrderDisplay(Component):
|
||||||
|
order: CateringOrder
|
||||||
|
seat: Optional[Seat]
|
||||||
|
|
||||||
|
def format_order_status(self, status: CateringOrderStatus) -> Text:
|
||||||
|
status_text = CateringOrder.translate_order_status(status)
|
||||||
|
|
||||||
|
color = self.session.theme.warning_color
|
||||||
|
if status == CateringOrderStatus.DELAYED or status == CateringOrderStatus.CANCELED:
|
||||||
|
color = self.session.theme.danger_color
|
||||||
|
elif status == CateringOrderStatus.COMPLETED:
|
||||||
|
color = self.session.theme.success_color
|
||||||
|
|
||||||
|
return Text(text=status_text, style=TextStyle(fill=color))
|
||||||
|
|
||||||
|
def build(self) -> Component:
|
||||||
|
return Card(
|
||||||
|
content=Column(
|
||||||
|
Row(
|
||||||
|
Text(f"Status: ", margin_left=0.3, margin_top=0.2),
|
||||||
|
self.format_order_status(self.order.status),
|
||||||
|
Spacer(),
|
||||||
|
Text(self.order.order_date.strftime("%d.%m. - %H:%M Uhr"), margin_right=0.3),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
Text(f"Gast: {self.order.customer.user_name}", margin_left=0.3),
|
||||||
|
Spacer(),
|
||||||
|
Text(f"Sitzplatz: {'-' if not self.seat else self.seat.seat_id}", margin_right=0.3),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
Text("Diese Bestellung wird:", margin_left=0.3),
|
||||||
|
Spacer(),
|
||||||
|
Text("Geliefert" if self.order.is_delivery else "Abgeholt", margin_right=0.3, margin_bottom=0.2),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
color=self.session.theme.hud_color,
|
||||||
|
colorize_on_hover=True,
|
||||||
|
margin=1
|
||||||
|
)
|
||||||
@ -65,8 +65,9 @@ class ShoppingCartAndOrders(Component):
|
|||||||
|
|
||||||
user_id = self.session[SessionStorage].user_id
|
user_id = self.session[SessionStorage].user_id
|
||||||
cart = self.session[CateringService].get_cart(user_id)
|
cart = self.session[CateringService].get_cart(user_id)
|
||||||
|
show_popup_task = None
|
||||||
if len(cart) < 1:
|
if len(cart) < 1:
|
||||||
_ = create_task(self.show_popup("Warenkorb leer", True))
|
show_popup_task = create_task(self.show_popup("Warenkorb leer", True))
|
||||||
else:
|
else:
|
||||||
items_with_amounts: CateringMenuItemsWithAmount = {}
|
items_with_amounts: CateringMenuItemsWithAmount = {}
|
||||||
for item in cart:
|
for item in cart:
|
||||||
@ -78,14 +79,15 @@ class ShoppingCartAndOrders(Component):
|
|||||||
await self.session[CateringService].place_order(items_with_amounts, user_id)
|
await self.session[CateringService].place_order(items_with_amounts, user_id)
|
||||||
except CateringError as catering_error:
|
except CateringError as catering_error:
|
||||||
if catering_error.error_type == CateringErrorType.INCLUDES_DISABLED_ITEM:
|
if catering_error.error_type == CateringErrorType.INCLUDES_DISABLED_ITEM:
|
||||||
_ = create_task(self.show_popup("Warenkorb enthält gesperrte Artikel", True))
|
show_popup_task = create_task(self.show_popup("Warenkorb enthält gesperrte Artikel", True))
|
||||||
elif catering_error.error_type == CateringErrorType.INSUFFICIENT_FUNDS:
|
elif catering_error.error_type == CateringErrorType.INSUFFICIENT_FUNDS:
|
||||||
_ = create_task(self.show_popup("Guthaben nicht ausreichend", True))
|
show_popup_task = create_task(self.show_popup("Guthaben nicht ausreichend", True))
|
||||||
else:
|
else:
|
||||||
_ = create_task(self.show_popup("Unbekannter Fehler", True))
|
show_popup_task = create_task(self.show_popup("Unbekannter Fehler", True))
|
||||||
self.session[CateringService].save_cart(self.session[SessionStorage].user_id, [])
|
self.session[CateringService].save_cart(self.session[SessionStorage].user_id, [])
|
||||||
self.order_button_loading = False
|
self.order_button_loading = False
|
||||||
_ = create_task(self.show_popup("Bestellung erfolgreich aufgegeben!", False))
|
if not show_popup_task:
|
||||||
|
show_popup_task = create_task(self.show_popup("Bestellung erfolgreich aufgegeben!", False))
|
||||||
|
|
||||||
async def _create_order_info_modal(self, order: CateringOrder) -> None:
|
async def _create_order_info_modal(self, order: CateringOrder) -> None:
|
||||||
def build_dialog_content() -> rio.Component:
|
def build_dialog_content() -> rio.Component:
|
||||||
|
|||||||
@ -65,6 +65,8 @@ class UserInfoBox(Component):
|
|||||||
self.session[AccountingService].add_update_hook(self.update)
|
self.session[AccountingService].add_update_hook(self.update)
|
||||||
|
|
||||||
async def update(self) -> None:
|
async def update(self) -> None:
|
||||||
|
if not self.user:
|
||||||
|
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
|
||||||
self.user_balance = await self.session[AccountingService].get_balance(self.user.user_id)
|
self.user_balance = await self.session[AccountingService].get_balance(self.user.user_id)
|
||||||
self.user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id)
|
self.user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id)
|
||||||
self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id)
|
self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id)
|
||||||
|
|||||||
@ -1,16 +1,52 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from dataclasses import field, dataclass
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from rio import Column, Component, event, TextStyle, Text, Spacer
|
from rio import Column, Component, event, TextStyle, Text, Spacer
|
||||||
|
|
||||||
from src.ez_lan_manager import ConfigurationService
|
from src.ez_lan_manager import ConfigurationService, CateringService, SeatingService
|
||||||
|
from src.ez_lan_manager.components.CateringManagementOrderDisplay import CateringManagementOrderDisplay
|
||||||
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
|
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
|
||||||
|
from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus
|
||||||
|
from src.ez_lan_manager.types.Seat import Seat
|
||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CateringOrderWithSeat:
|
||||||
|
catering_order: CateringOrder
|
||||||
|
seat: Optional[Seat]
|
||||||
|
|
||||||
class ManageCateringPage(Component):
|
class ManageCateringPage(Component):
|
||||||
|
all_orders: list[CateringOrderWithSeat] = field(default_factory=list)
|
||||||
|
last_updated: Optional[datetime] = None
|
||||||
|
|
||||||
@event.on_populate
|
@event.on_populate
|
||||||
async def on_populate(self) -> None:
|
async def on_populate(self) -> None:
|
||||||
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Catering Verwaltung")
|
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Catering Verwaltung")
|
||||||
|
self.all_orders = await self.populate_seating(await self.session[CateringService].get_orders())
|
||||||
|
self.last_updated = datetime.now()
|
||||||
|
|
||||||
|
|
||||||
|
@event.periodic(30)
|
||||||
|
async def update_orders(self) -> None:
|
||||||
|
polled_orders = await self.session[CateringService].get_orders()
|
||||||
|
self.all_orders = await self.populate_seating(polled_orders)
|
||||||
|
self.last_updated = datetime.now()
|
||||||
|
|
||||||
|
async def populate_seating(self, orders: list[CateringOrder]) -> list[CateringOrderWithSeat]:
|
||||||
|
result = []
|
||||||
|
for order in orders:
|
||||||
|
seat = await self.session[SeatingService].get_user_seat(order.customer.user_id)
|
||||||
|
result.append(CateringOrderWithSeat(catering_order=order, seat=seat))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_all_pending_orders(self) -> list[CateringOrderWithSeat]:
|
||||||
|
filtered_list = list(filter(lambda o: o.catering_order.status != CateringOrderStatus.COMPLETED and o.catering_order.status != CateringOrderStatus.CANCELED, self.all_orders))
|
||||||
|
sorted_list = sorted(filtered_list, key=lambda o: o.catering_order.order_date)
|
||||||
|
return sorted_list
|
||||||
|
|
||||||
|
|
||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
return Column(
|
return Column(
|
||||||
@ -28,5 +64,30 @@ class ManageCateringPage(Component):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
MainViewContentBox(
|
||||||
|
Column(
|
||||||
|
Text(
|
||||||
|
text="Offene Bestellungen",
|
||||||
|
style=TextStyle(
|
||||||
|
fill=self.session.theme.background_color,
|
||||||
|
font_size=1.2
|
||||||
|
),
|
||||||
|
margin_top=2,
|
||||||
|
margin_bottom=0.2,
|
||||||
|
align_x=0.5
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
text=f"Letzte Aktualisierung: {'-' if not self.last_updated else self.last_updated.strftime('%H:%M:%S')}",
|
||||||
|
style=TextStyle(
|
||||||
|
fill=self.session.theme.background_color,
|
||||||
|
font_size=0.7
|
||||||
|
),
|
||||||
|
margin_top=0.2,
|
||||||
|
margin_bottom=2,
|
||||||
|
align_x=0.5
|
||||||
|
),
|
||||||
|
*[CateringManagementOrderDisplay(v.catering_order, v.seat) for v in self.get_all_pending_orders()],
|
||||||
|
)
|
||||||
|
),
|
||||||
Spacer()
|
Spacer()
|
||||||
)
|
)
|
||||||
|
|||||||
@ -31,3 +31,20 @@ class CateringOrder:
|
|||||||
for item, amount in self.items.items():
|
for item, amount in self.items.items():
|
||||||
total += (item.price * amount)
|
total += (item.price * amount)
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def translate_order_status(status: CateringOrderStatus) -> str:
|
||||||
|
if status == CateringOrderStatus.RECEIVED:
|
||||||
|
return "Eingegangen"
|
||||||
|
elif status == CateringOrderStatus.DELAYED:
|
||||||
|
return "Verzögert"
|
||||||
|
elif status == CateringOrderStatus.READY_FOR_PICKUP:
|
||||||
|
return "Abholbereit"
|
||||||
|
elif status == CateringOrderStatus.EN_ROUTE:
|
||||||
|
return "In Zustellung"
|
||||||
|
elif status == CateringOrderStatus.COMPLETED:
|
||||||
|
return "Abgeschlossen"
|
||||||
|
elif status == CateringOrderStatus.CANCELED:
|
||||||
|
return "Storniert"
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Unknown CateringOrderStatus:", status)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user