From d8dca5c6d3cacd1370968f5bda65e3bf1152340c Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Thu, 28 May 2026 00:38:43 +0200 Subject: [PATCH] add catering admin order overview --- src/elm/pages/CateringAdminPage.py | 94 +++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 9 deletions(-) diff --git a/src/elm/pages/CateringAdminPage.py b/src/elm/pages/CateringAdminPage.py index f903906..7b11370 100644 --- a/src/elm/pages/CateringAdminPage.py +++ b/src/elm/pages/CateringAdminPage.py @@ -1,18 +1,19 @@ from __future__ import annotations import logging +from asyncio import sleep from functools import partial from typing import Optional from decimal import Decimal from beanie import PydanticObjectId, Document from rio import Component, Column, Row, Text, Spacer, page, Rectangle, TextInput, GuardEvent, Button, TextInputChangeEvent, NumberInput, IconButton, FlowContainer, List, \ - PointerEventListener + PointerEventListener, Overlay, Link from rio.event import on_populate from elm.types import UserSession, User, Transaction, Seat -from elm.services import AccountingService, MailingService -from elm.components import AccountInfoBox +from elm.services import AccountingService, MailingService, ReceiptPrintingService +from elm.components import AccountInfoBox, ElmButton from elm.types.CateringTypes import CateringOrder, CateringOrderStatus logger = logging.getLogger(__name__.split(".")[-1]) @@ -30,6 +31,7 @@ class CateringAdminPage(Component): open_orders: List[CateringOrder] = List() all_users: list[User] = [] all_seats: list[Seat] = [] + edited_order: Optional[CateringOrder] = None @on_populate async def on_populate(self) -> None: @@ -45,6 +47,8 @@ class CateringAdminPage(Component): } } ).to_list()) + await sleep(5) + self.session.create_task(self.on_populate()) def get_name_for_user_id(self, id_: PydanticObjectId) -> str: return next(filter(lambda user: user.id == id_ ,self.all_users)).user_name @@ -59,15 +63,86 @@ class CateringAdminPage(Component): return "-" async def on_order_pressed(self, order: CateringOrder) -> None: - print("Pressed on order: ", str(order.id)[-5:]) + self.edited_order = order + + async def change_order_status(self, new_status: CateringOrderStatus) -> None: + if not self.edited_order: + return + + if new_status == CateringOrderStatus.CANCELED: + pass + + if self.edited_order.status == new_status: + self.edited_order = None + return + + if new_status == CateringOrderStatus.CANCELED: + user = await User.find_one(User.id == self.edited_order.customer_id) + if not user: + self.edited_order = None + return + + price = Decimal(0) + for item in self.edited_order.items: + price += item.final_unit_price + await self.session[AccountingService].add_balance(user.user_name, price, f"CATERING REFUND - {str(self.edited_order.id)[-5:]}") + + self.edited_order.status = new_status + await self.edited_order.save() + self.open_orders = List(await CateringOrder.find_many( + { + "status": { + "$nin": [ + CateringOrderStatus.COMPLETED, + CateringOrderStatus.CANCELED, + ] + } + } + ).to_list()) + self.edited_order = None + + async def print_receipt(self) -> None: + if not self.edited_order: + return + user = await User.find_one(User.id == self.edited_order.customer_id) + if not user: + self.edited_order = None + return + self.session.create_task(self.session[ReceiptPrintingService].print_order(user, self.edited_order)) + self.edited_order = None def build(self) -> Component: + if self.edited_order: + overlay = [ + Overlay( + content=Rectangle( + content=Column( + Text(f"Status ändern - Bestellung {str(self.edited_order.id)[-5:]}", margin_bottom=1), + *[ElmButton(text=CateringOrder.translate_order_status(status), on_press=partial(self.change_order_status, status)) for status in CateringOrderStatus], + Row(ElmButton(text="Bon drucken", on_press=self.print_receipt), ElmButton(text="Abbrechen", on_press=lambda: self.__setattr__("edited_order", None)), spacing=1, margin_top=2), + spacing=0.5, + margin=1 + ), + fill=self.session.theme.box_color, + stroke_width=0.2, + stroke_color=self.session.theme.box_border_color, + align_x=0.5, + align_y=0.5 + ) + ) + ] + else: + overlay = [] return Row( + *overlay, Rectangle( content=Column( Rectangle( content=Rectangle( - content=Text("Bestellungen", margin=0.5, selectable=False, overflow="wrap"), + content=Row( + Text("Offene Bestellungen", margin=0.5, selectable=False, overflow="wrap"), + Link(content="Neue Bestellung", target_url="./new-pos-order") + ), fill=self.session.theme.header_box_background_color, margin=0.4 ), @@ -80,7 +155,8 @@ class CateringAdminPage(Component): content=Column( Row(Text(f"ID:", font_size=1.2), Text(str(order.id)[-5:], justify="right", font_size=1.2)), Row(Text("Nutzer:", font_size=1.2), Text(self.get_name_for_user_id(order.customer_id), font_size=1.2, justify="right")), - Row(Text(f"Sitzplatz:", font_size=1.2), Text(self.get_seat_for_user_id(order.customer_id), font_size=1.2, justify="right"), margin_bottom=2), + Row(Text(f"Sitzplatz:", font_size=1.2), Text(self.get_seat_for_user_id(order.customer_id), font_size=1.2, justify="right")), + Row(Text(f"Status:", font_size=1.2), Text(CateringOrder.translate_order_status(order.status), font_size=1.2, justify="right"), margin_bottom=2), *[Text(item.name, overflow="ellipsize") for item in order.items], margin=0.5, spacing=0.2 @@ -104,7 +180,8 @@ class CateringAdminPage(Component): stroke_width=0.1, stroke_color=self.session.theme.box_border_color, min_width=25, - grow_x=True + grow_x=True, + margin_right=1 ), Rectangle( content=Column( @@ -124,6 +201,5 @@ class CateringAdminPage(Component): stroke_color=self.session.theme.box_border_color, min_width=25 ), - margin=1, - spacing=1 + margin=1 )