Co-authored-by: David Rodenkirchen <davidr.develop@gmail.com> Reviewed-on: Vereins-IT/ez-lan-manager#4
211 lines
9.1 KiB
Python
211 lines
9.1 KiB
Python
from asyncio import sleep, create_task
|
|
|
|
import rio
|
|
from rio import Component, Column, Text, TextStyle, Button, Row, ScrollContainer, Spacer, Popup, Table
|
|
|
|
from src.ez_lan_manager.components.CateringCartItem import CateringCartItem
|
|
from src.ez_lan_manager.components.CateringOrderItem import CateringOrderItem
|
|
from src.ez_lan_manager.services.AccountingService import AccountingService
|
|
from src.ez_lan_manager.services.CateringService import CateringService, CateringError, CateringErrorType
|
|
from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringMenuItemsWithAmount
|
|
from src.ez_lan_manager.types.SessionStorage import SessionStorage
|
|
|
|
POPUP_CLOSE_TIMEOUT_SECONDS = 3
|
|
|
|
class ShoppingCartAndOrders(Component):
|
|
show_cart: bool = True
|
|
orders: list[CateringOrder] = []
|
|
order_button_loading: bool = False
|
|
popup_message: str = ""
|
|
popup_is_shown: bool = False
|
|
popup_is_error: bool = True
|
|
|
|
async def switch(self) -> None:
|
|
self.show_cart = not self.show_cart
|
|
self.orders = await self.session[CateringService].get_orders_for_user(self.session[SessionStorage].user_id)
|
|
|
|
async def on_remove_item(self, list_id: int) -> None:
|
|
catering_service = self.session[CateringService]
|
|
user_id = self.session[SessionStorage].user_id
|
|
cart = catering_service.get_cart(user_id)
|
|
try:
|
|
cart.pop(list_id)
|
|
except IndexError:
|
|
return
|
|
catering_service.save_cart(user_id, cart)
|
|
await self.force_refresh()
|
|
|
|
async def on_empty_cart_pressed(self) -> None:
|
|
self.session[CateringService].save_cart(self.session[SessionStorage].user_id, [])
|
|
await self.force_refresh()
|
|
|
|
async def on_add_item(self, article_id: int) -> None:
|
|
catering_service = self.session[CateringService]
|
|
user_id = self.session[SessionStorage].user_id
|
|
if not user_id:
|
|
return
|
|
cart = catering_service.get_cart(user_id)
|
|
item_to_add = await catering_service.get_menu_item_by_id(article_id)
|
|
cart.append(item_to_add)
|
|
catering_service.save_cart(user_id, cart)
|
|
await self.force_refresh()
|
|
|
|
async def show_popup(self, text: str, is_error: bool) -> None:
|
|
self.popup_is_error = is_error
|
|
self.popup_message = text
|
|
self.popup_is_shown = True
|
|
await self.force_refresh()
|
|
await sleep(POPUP_CLOSE_TIMEOUT_SECONDS)
|
|
self.popup_is_shown = False
|
|
await self.force_refresh()
|
|
|
|
async def on_order_pressed(self) -> None:
|
|
self.order_button_loading = True
|
|
await self.force_refresh()
|
|
|
|
user_id = self.session[SessionStorage].user_id
|
|
cart = self.session[CateringService].get_cart(user_id)
|
|
show_popup_task = None
|
|
if len(cart) < 1:
|
|
show_popup_task = create_task(self.show_popup("Warenkorb leer", True))
|
|
else:
|
|
items_with_amounts: CateringMenuItemsWithAmount = {}
|
|
for item in cart:
|
|
try:
|
|
items_with_amounts[item] += 1
|
|
except KeyError:
|
|
items_with_amounts[item] = 1
|
|
try:
|
|
await self.session[CateringService].place_order(items_with_amounts, user_id)
|
|
except CateringError as catering_error:
|
|
if catering_error.error_type == CateringErrorType.INCLUDES_DISABLED_ITEM:
|
|
show_popup_task = create_task(self.show_popup("Warenkorb enthält gesperrte Artikel", True))
|
|
elif catering_error.error_type == CateringErrorType.INSUFFICIENT_FUNDS:
|
|
show_popup_task = create_task(self.show_popup("Guthaben nicht ausreichend", True))
|
|
else:
|
|
show_popup_task = create_task(self.show_popup("Unbekannter Fehler", True))
|
|
self.session[CateringService].save_cart(self.session[SessionStorage].user_id, [])
|
|
self.order_button_loading = 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:
|
|
def build_dialog_content() -> rio.Component:
|
|
# @todo: rio 0.10.8 did not have the ability to align the columns, check back in a future version
|
|
table = Table(
|
|
{
|
|
"Artikel": [item.name for item in order.items.keys()] + ["Gesamtpreis:"],
|
|
"Anzahl": [item for item in order.items.values()] + [""],
|
|
"Preis": [AccountingService.make_euro_string_from_int(item.price) for item in order.items.keys()] + [AccountingService.make_euro_string_from_int(order.price)],
|
|
},
|
|
show_row_numbers=False
|
|
)
|
|
return rio.Card(
|
|
rio.Column(
|
|
rio.Text(
|
|
f"Deine Bestellung ({order.order_id})",
|
|
align_x=0.5,
|
|
margin_bottom=0.5
|
|
),
|
|
table,
|
|
margin=2,
|
|
),
|
|
align_x=0.5,
|
|
align_y=0.2,
|
|
min_width=50,
|
|
min_height=10,
|
|
color=self.session.theme.primary_color,
|
|
margin_left=1,
|
|
margin_right=1,
|
|
margin_top=2,
|
|
margin_bottom=1,
|
|
)
|
|
dialog = await self.session.show_custom_dialog(
|
|
build=build_dialog_content,
|
|
modal=True,
|
|
user_closeable=True,
|
|
)
|
|
await dialog.wait_for_close()
|
|
|
|
def build(self) -> rio.Component:
|
|
user_id = self.session[SessionStorage].user_id
|
|
catering_service = self.session[CateringService]
|
|
cart = catering_service.get_cart(user_id)
|
|
if self.show_cart:
|
|
cart_container = ScrollContainer(
|
|
content=Column(
|
|
*[CateringCartItem(
|
|
article_name=cart_item.name,
|
|
article_price=cart_item.price,
|
|
article_id=cart_item.item_id,
|
|
remove_item_cb=self.on_remove_item,
|
|
list_id=idx
|
|
) for idx, cart_item in enumerate(cart)],
|
|
Spacer(grow_y=True)
|
|
),
|
|
min_height=8,
|
|
min_width=33,
|
|
margin=1
|
|
)
|
|
return Column(
|
|
cart_container,
|
|
Popup(
|
|
anchor=cart_container,
|
|
content=Text(self.popup_message, style=TextStyle(fill=self.session.theme.danger_color if self.popup_is_error else self.session.theme.success_color), overflow="wrap", margin=2, justify="center", min_width=20),
|
|
is_open=self.popup_is_shown,
|
|
position="center",
|
|
color=self.session.theme.primary_color
|
|
),
|
|
Row(
|
|
Text(
|
|
text=f"Preis: {AccountingService.make_euro_string_from_int(sum(cart_item.price for cart_item in cart))}",
|
|
style=TextStyle(
|
|
fill=self.session.theme.background_color,
|
|
font_size=0.8
|
|
),
|
|
margin=1
|
|
),
|
|
Button(
|
|
content=Text(
|
|
"Warenkorb leeren",
|
|
style=TextStyle(fill=self.session.theme.danger_color, font_size=0.9),
|
|
align_x=0.2
|
|
),
|
|
margin=1,
|
|
margin_left=0,
|
|
shape="rectangle",
|
|
style="major",
|
|
color="primary",
|
|
on_press=self.on_empty_cart_pressed
|
|
),
|
|
Button(
|
|
content=Text(
|
|
"Bestellen",
|
|
style=TextStyle(fill=self.session.theme.success_color, font_size=0.9),
|
|
align_x=0.2
|
|
),
|
|
margin=1,
|
|
margin_left=0,
|
|
shape="rectangle",
|
|
style="major",
|
|
color="primary",
|
|
on_press=self.on_order_pressed,
|
|
is_loading=self.order_button_loading
|
|
)
|
|
)
|
|
)
|
|
else:
|
|
orders_container = ScrollContainer(
|
|
content=Column(
|
|
*[CateringOrderItem(
|
|
order=order_item,
|
|
info_modal_cb=self._create_order_info_modal
|
|
) for order_item in self.orders],
|
|
Spacer(grow_y=True)
|
|
),
|
|
min_height=8,
|
|
min_width=33,
|
|
margin=1
|
|
)
|
|
return Column(orders_container)
|