Add Catering Management #4

Merged
Typhus merged 2 commits from feature/add-catering-management into main 2025-02-01 14:23:12 +00:00
5 changed files with 111 additions and 28 deletions
Showing only changes of commit e0f7105fea - Show all commits

View File

@ -171,7 +171,7 @@ if __name__ == "__main__":
"robots": "INDEX,FOLLOW", "robots": "INDEX,FOLLOW",
"description": f"Info und Verwaltungs-Seite der LAN Party '{lan_info.name} - {lan_info.iteration}'.", "description": f"Info und Verwaltungs-Seite der LAN Party '{lan_info.name} - {lan_info.iteration}'.",
"og:description": f"Info und Verwaltungs-Seite der LAN Party '{lan_info.name} - {lan_info.iteration}'.", "og:description": f"Info und Verwaltungs-Seite der LAN Party '{lan_info.name} - {lan_info.iteration}'.",
"keywords": "Gaming, Clan, Guild, Verein, Club, Einfach, Zocken, Genuss, Gesellschaft, Videospiele, " "keywords": "Gaming, Clan, Guild, Verein, Club, Einfach, Zocken, Gesellschaft, Videospiele, "
"Videogames, LAN, Party, EZ, LAN, Manager", "Videogames, LAN, Party, EZ, LAN, Manager",
"author": "David Rodenkirchen", "author": "David Rodenkirchen",
"publisher": "EZ GG e.V.", "publisher": "EZ GG e.V.",

View File

@ -1,14 +1,29 @@
from typing import Optional from functools import partial
from typing import Optional, Callable
from rio import Component, Row, Card, Column, Text, TextStyle, Spacer from rio import Component, Row, Card, Column, Text, TextStyle, Spacer, PointerEventListener, Button
from src.ez_lan_manager.services.CateringService import CateringService
from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus from src.ez_lan_manager.types.CateringOrder import CateringOrder, CateringOrderStatus
from src.ez_lan_manager.types.Seat import Seat from src.ez_lan_manager.types.Seat import Seat
class CateringManagementOrderDisplayStatusButton(Component):
status: CateringOrderStatus
clicked_cb: Callable
def build(self) -> Component:
return Button(
content=Text(
CateringOrder.translate_order_status(self.status)
),
shape="rectangle",
on_press=partial(self.clicked_cb, self.status)
)
class CateringManagementOrderDisplay(Component): class CateringManagementOrderDisplay(Component):
order: CateringOrder order: CateringOrder
seat: Optional[Seat] seat: Optional[Seat]
clicked_cb: Callable
def format_order_status(self, status: CateringOrderStatus) -> Text: def format_order_status(self, status: CateringOrderStatus) -> Text:
status_text = CateringOrder.translate_order_status(status) status_text = CateringOrder.translate_order_status(status)
@ -21,27 +36,65 @@ class CateringManagementOrderDisplay(Component):
return Text(text=status_text, style=TextStyle(fill=color)) return Text(text=status_text, style=TextStyle(fill=color))
def build(self) -> Component: async def status_button_clicked(self, new_status: CateringOrderStatus) -> None:
return Card( if self.order.status == CateringOrderStatus.CANCELED:
content=Column( return
Row(
Text(f"Status: ", margin_left=0.3, margin_top=0.2), if new_status == CateringOrderStatus.CANCELED:
self.format_order_status(self.order.status), # ToDo: Hier sollten wir nochmal nachfragen ob der Bediener sich wirklich sicher ist,
Spacer(), # und anwarnen das eine stornierte Bestellung nicht ent-storniert werden kann.
Text(self.order.order_date.strftime("%d.%m. - %H:%M Uhr"), margin_right=0.3), pass
),
Row( if self.order.status != new_status:
Text(f"Gast: {self.order.customer.user_name}", margin_left=0.3), if new_status == CateringOrderStatus.CANCELED:
Spacer(), success = await self.session[CateringService].cancel_order(self.order)
Text(f"Sitzplatz: {'-' if not self.seat else self.seat.seat_id}", margin_right=0.3), else:
), success = await self.session[CateringService].update_order_status(self.order.order_id, new_status)
Row(
Text("Diese Bestellung wird:", margin_left=0.3), if success:
Spacer(), self.order = CateringOrder(
Text("Geliefert" if self.order.is_delivery else "Abgeholt", margin_right=0.3, margin_bottom=0.2), order_id=self.order.order_id,
order_date=self.order.order_date,
status=new_status,
items=self.order.items,
customer=self.order.customer,
is_delivery=self.order.is_delivery
) )
def build(self) -> Component:
return PointerEventListener(
content=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, margin_bottom=0.5),
Spacer(),
Text("Geliefert" if self.order.is_delivery else "Abgeholt", margin_right=0.3, margin_bottom=0.5),
),
Row(
CateringManagementOrderDisplayStatusButton(CateringOrderStatus.RECEIVED, self.status_button_clicked),
CateringManagementOrderDisplayStatusButton(CateringOrderStatus.CANCELED, self.status_button_clicked),
CateringManagementOrderDisplayStatusButton(CateringOrderStatus.EN_ROUTE, self.status_button_clicked)
),
Row(
CateringManagementOrderDisplayStatusButton(CateringOrderStatus.READY_FOR_PICKUP, self.status_button_clicked),
CateringManagementOrderDisplayStatusButton(CateringOrderStatus.COMPLETED, self.status_button_clicked),
CateringManagementOrderDisplayStatusButton(CateringOrderStatus.DELAYED, self.status_button_clicked),
)
),
color=self.session.theme.hud_color,
colorize_on_hover=True,
margin=1
), ),
color=self.session.theme.hud_color, on_press=partial(self.clicked_cb, self.order)
colorize_on_hover=True,
margin=1
) )

View File

@ -3,7 +3,7 @@ from dataclasses import field, dataclass
from datetime import datetime from datetime import datetime
from typing import Optional from typing import Optional
from rio import Column, Component, event, TextStyle, Text, Spacer from rio import Column, Component, event, TextStyle, Text, Spacer, PointerEvent, Button
from src.ez_lan_manager import ConfigurationService, CateringService, SeatingService from src.ez_lan_manager import ConfigurationService, CateringService, SeatingService
from src.ez_lan_manager.components.CateringManagementOrderDisplay import CateringManagementOrderDisplay from src.ez_lan_manager.components.CateringManagementOrderDisplay import CateringManagementOrderDisplay
@ -47,6 +47,14 @@ class ManageCateringPage(Component):
sorted_list = sorted(filtered_list, key=lambda o: o.catering_order.order_date) sorted_list = sorted(filtered_list, key=lambda o: o.catering_order.order_date)
return sorted_list return sorted_list
def get_all_completed_orders(self) -> list[CateringOrderWithSeat]:
filtered_list = list(filter(lambda o: o.catering_order.status == CateringOrderStatus.COMPLETED or 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
async def order_clicked(self, order: CateringOrder, _: PointerEvent) -> None:
pass
def build(self) -> Component: def build(self) -> Component:
return Column( return Column(
@ -83,10 +91,31 @@ class ManageCateringPage(Component):
font_size=0.7 font_size=0.7
), ),
margin_top=0.2, margin_top=0.2,
margin_bottom=2, margin_bottom=0.2,
align_x=0.5 align_x=0.5
), ),
*[CateringManagementOrderDisplay(v.catering_order, v.seat) for v in self.get_all_pending_orders()], Button(
content=Text("Jetzt aktualisieren", style=TextStyle(font_size=0.7), justify="center"),
shape="rectangle",
margin_bottom=1,
on_press=self.update_orders
),
*[CateringManagementOrderDisplay(v.catering_order, v.seat, self.order_clicked) for v in self.get_all_pending_orders()],
)
),
MainViewContentBox(
Column(
Text(
text="Abgeschlossene Bestellungen",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1.2
),
margin_top=2,
margin_bottom=0.2,
align_x=0.5
),
*[CateringManagementOrderDisplay(v.catering_order, v.seat, self.order_clicked) for v in self.get_all_completed_orders()],
) )
), ),
Spacer() Spacer()

View File

@ -16,7 +16,7 @@ RULES: list[str] = [
AGB: dict[str, list[str]] = { AGB: dict[str, list[str]] = {
"§1": [ "§1": [
"Die Veranstaltung wird von der Einfach Zocken Genuss Gesellschaft e.V. organisiert.", "Die Veranstaltung wird von der Einfach Zocken Gaming Gesellschaft e.V. organisiert.",
"Unser Event verfolgt gemeinnützige Ziele und ist nicht auf Profit ausgerichtet. Die erhobenen Teilnahmebeiträge dienen lediglich der Kostendeckung. Überschüsse werden für die Organisation und Durchführung zukünftiger ähnlicher Veranstaltungen verwendet.", "Unser Event verfolgt gemeinnützige Ziele und ist nicht auf Profit ausgerichtet. Die erhobenen Teilnahmebeiträge dienen lediglich der Kostendeckung. Überschüsse werden für die Organisation und Durchführung zukünftiger ähnlicher Veranstaltungen verwendet.",
"Die Organisatoren haben das Recht, unerwünschte oder störende Personen jederzeit von der Veranstaltung auszuschließen (siehe §3). Im Falle eines Ausschlusses aufgrund eines Regelverstoßes erfolgt keine Rückerstattung des Eintrittspreises." "Die Organisatoren haben das Recht, unerwünschte oder störende Personen jederzeit von der Veranstaltung auszuschließen (siehe §3). Im Falle eines Ausschlusses aufgrund eines Regelverstoßes erfolgt keine Rückerstattung des Eintrittspreises."
], ],

View File

@ -1,6 +1,7 @@
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from enum import StrEnum from enum import StrEnum
from typing import Optional, Iterable, Self
from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, CateringMenuItemCategory
from src.ez_lan_manager.types.User import User from src.ez_lan_manager.types.User import User