Compare commits
2 Commits
98c2d1570c
...
40f8bc1049
| Author | SHA1 | Date | |
|---|---|---|---|
| 40f8bc1049 | |||
|
|
a419ee8885 |
@ -28,14 +28,14 @@
|
|||||||
[tickets]
|
[tickets]
|
||||||
[tickets."NORMAL"]
|
[tickets."NORMAL"]
|
||||||
total_tickets=30
|
total_tickets=30
|
||||||
price=2500
|
price="25.00"
|
||||||
description="Normales Ticket"
|
description="Normales Ticket"
|
||||||
additional_info="Berechtigt zur Nutzung eines regulären Platzes für die gesamte Dauer der LAN"
|
additional_info="Berechtigt zur Nutzung eines regulären Platzes für die gesamte Dauer der LAN"
|
||||||
is_default=true
|
is_default=true
|
||||||
|
|
||||||
[tickets."LUXUS"]
|
[tickets."LUXUS"]
|
||||||
total_tickets=10
|
total_tickets=10
|
||||||
price=3500
|
price="35.00"
|
||||||
description="Luxus Ticket"
|
description="Luxus Ticket"
|
||||||
additional_info="Berechtigt zur Nutzung eines verbesserten Platzes. Dieser ist mit einer höheren Internet-Bandbreite und einem Sitzkissen ausgestattet."
|
additional_info="Berechtigt zur Nutzung eines verbesserten Platzes. Dieser ist mit einer höheren Internet-Bandbreite und einem Sitzkissen ausgestattet."
|
||||||
is_default=false
|
is_default=false
|
||||||
|
|||||||
@ -28,7 +28,7 @@ CREATE TABLE `catering_menu_items` (
|
|||||||
`catering_menu_item_id` int(11) NOT NULL AUTO_INCREMENT,
|
`catering_menu_item_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(45) NOT NULL,
|
`name` varchar(45) NOT NULL,
|
||||||
`additional_info` varchar(300) DEFAULT '',
|
`additional_info` varchar(300) DEFAULT '',
|
||||||
`price` int(11) NOT NULL DEFAULT 0,
|
`price` varchar(45) NOT NULL DEFAULT '0',
|
||||||
`category` varchar(80) NOT NULL,
|
`category` varchar(80) NOT NULL,
|
||||||
`is_disabled` tinyint(4) DEFAULT 0,
|
`is_disabled` tinyint(4) DEFAULT 0,
|
||||||
PRIMARY KEY (`catering_menu_item_id`)
|
PRIMARY KEY (`catering_menu_item_id`)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import rio
|
import rio
|
||||||
from rio import Component, Row, Text, IconButton, TextStyle
|
from rio import Component, Row, Text, IconButton, TextStyle
|
||||||
@ -9,7 +10,7 @@ MAX_LEN = 24
|
|||||||
|
|
||||||
class CateringCartItem(Component):
|
class CateringCartItem(Component):
|
||||||
article_name: str
|
article_name: str
|
||||||
article_price: int
|
article_price: Decimal
|
||||||
article_id: int
|
article_id: int
|
||||||
list_id: int
|
list_id: int
|
||||||
remove_item_cb: Callable
|
remove_item_cb: Callable
|
||||||
@ -24,7 +25,7 @@ class CateringCartItem(Component):
|
|||||||
def build(self) -> rio.Component:
|
def build(self) -> rio.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_decimal(self.article_price), style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
||||||
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)),
|
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)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from decimal import Decimal
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
import rio
|
import rio
|
||||||
@ -7,9 +8,10 @@ from src.ez_lan_manager import AccountingService
|
|||||||
|
|
||||||
MAX_LEN = 24
|
MAX_LEN = 24
|
||||||
|
|
||||||
|
|
||||||
class CateringSelectionItem(Component):
|
class CateringSelectionItem(Component):
|
||||||
article_name: str
|
article_name: str
|
||||||
article_price: int
|
article_price: Decimal
|
||||||
article_id: int
|
article_id: int
|
||||||
on_add_callback: Callable
|
on_add_callback: Callable
|
||||||
is_sensitive: bool
|
is_sensitive: bool
|
||||||
@ -33,15 +35,16 @@ class CateringSelectionItem(Component):
|
|||||||
|
|
||||||
return top.strip(), bottom.strip()
|
return top.strip(), bottom.strip()
|
||||||
|
|
||||||
|
|
||||||
def build(self) -> rio.Component:
|
def build(self) -> rio.Component:
|
||||||
article_name_top, article_name_bottom = self.split_article_name(self.article_name)
|
article_name_top, article_name_bottom = self.split_article_name(self.article_name)
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
content=Column(
|
content=Column(
|
||||||
Row(
|
Row(
|
||||||
Text(article_name_top, align_x=0, overflow="wrap", min_width=19, style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
Text(article_name_top, align_x=0, overflow="wrap", min_width=19,
|
||||||
Text(AccountingService.make_euro_string_from_int(self.article_price), style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
||||||
|
Text(AccountingService.make_euro_string_from_decimal(self.article_price),
|
||||||
|
style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon="material/add",
|
icon="material/add",
|
||||||
min_size=2,
|
min_size=2,
|
||||||
@ -53,7 +56,10 @@ class CateringSelectionItem(Component):
|
|||||||
proportions=(19, 5, 2),
|
proportions=(19, 5, 2),
|
||||||
margin_bottom=0
|
margin_bottom=0
|
||||||
),
|
),
|
||||||
Spacer() if not article_name_bottom else Text(article_name_bottom, align_x=0, overflow="wrap", min_width=19, style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
|
Spacer() if not article_name_bottom else Text(article_name_bottom, align_x=0, overflow="wrap",
|
||||||
|
min_width=19,
|
||||||
|
style=TextStyle(fill=self.session.theme.background_color,
|
||||||
|
font_size=0.9)),
|
||||||
Row(
|
Row(
|
||||||
Text(
|
Text(
|
||||||
self.additional_info,
|
self.additional_info,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from rio import Component, Column, NumberInput, ThemeContextSwitcher, TextInput, Row, Button, EventHandler
|
from rio import Component, Column, NumberInput, ThemeContextSwitcher, TextInput, Row, Button, EventHandler
|
||||||
@ -18,7 +19,7 @@ class NewTransactionForm(Component):
|
|||||||
self.new_transaction_cb,
|
self.new_transaction_cb,
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=self.user.user_id,
|
user_id=self.user.user_id,
|
||||||
value=round(self.input_value * 100),
|
value=Decimal(str(self.input_value)),
|
||||||
is_debit=True,
|
is_debit=True,
|
||||||
reference=self.input_reason,
|
reference=self.input_reason,
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
@ -30,7 +31,7 @@ class NewTransactionForm(Component):
|
|||||||
self.new_transaction_cb,
|
self.new_transaction_cb,
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=self.user.user_id,
|
user_id=self.user.user_id,
|
||||||
value=round(self.input_value * 100),
|
value=Decimal(str(self.input_value)),
|
||||||
is_debit=False,
|
is_debit=False,
|
||||||
reference=self.input_reason,
|
reference=self.input_reason,
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from decimal import Decimal
|
||||||
from typing import Optional, Callable
|
from typing import Optional, Callable
|
||||||
|
|
||||||
from rio import Component, Column, Text, TextStyle, Button, Spacer
|
from rio import Component, Column, Text, TextStyle, Button, Spacer
|
||||||
@ -9,23 +10,30 @@ class SeatingPlanInfoBox(Component):
|
|||||||
is_booking_blocked: bool
|
is_booking_blocked: bool
|
||||||
seat_id: Optional[str] = None
|
seat_id: Optional[str] = None
|
||||||
seat_occupant: Optional[str] = None
|
seat_occupant: Optional[str] = None
|
||||||
seat_price: int = 0
|
seat_price: Decimal = Decimal("0")
|
||||||
is_blocked: bool = False
|
is_blocked: bool = False
|
||||||
|
|
||||||
|
|
||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
if not self.show:
|
if not self.show:
|
||||||
return Spacer()
|
return Spacer()
|
||||||
if self.is_blocked:
|
if self.is_blocked:
|
||||||
return Column(Text(f"Sitzplatz gesperrt", margin=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), overflow="wrap", justify="center"), min_height=10)
|
return Column(Text(f"Sitzplatz gesperrt", margin=1,
|
||||||
|
style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), overflow="wrap",
|
||||||
|
justify="center"), min_height=10)
|
||||||
if self.seat_id is None and self.seat_occupant is None:
|
if self.seat_id is None and self.seat_occupant is None:
|
||||||
return Column(Text(f"Sitzplatz auswählen...", margin=1, style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"), min_height=10)
|
return Column(
|
||||||
|
Text(f"Sitzplatz auswählen...", margin=1, style=TextStyle(fill=self.session.theme.neutral_color),
|
||||||
|
overflow="wrap", justify="center"), min_height=10)
|
||||||
return Column(
|
return Column(
|
||||||
Text(f"Dieser Sitzplatz ({self.seat_id}) ist gebucht von:", margin=1, style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"),
|
Text(f"Dieser Sitzplatz ({self.seat_id}) ist gebucht von:", margin=1,
|
||||||
Text(f"{self.seat_occupant}", margin_bottom=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), overflow="wrap", justify="center"),
|
style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"),
|
||||||
|
Text(f"{self.seat_occupant}", margin_bottom=1,
|
||||||
|
style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), overflow="wrap",
|
||||||
|
justify="center"),
|
||||||
min_height=10
|
min_height=10
|
||||||
) if self.seat_id and self.seat_occupant else Column(
|
) if self.seat_id and self.seat_occupant else Column(
|
||||||
Text(f"Dieser Sitzplatz ({self.seat_id}) ist frei", margin=1, style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"),
|
Text(f"Dieser Sitzplatz ({self.seat_id}) ist frei", margin=1,
|
||||||
|
style=TextStyle(fill=self.session.theme.neutral_color), overflow="wrap", justify="center"),
|
||||||
Button(
|
Button(
|
||||||
Text(
|
Text(
|
||||||
f"Buchen",
|
f"Buchen",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from asyncio import sleep, create_task
|
from asyncio import sleep, create_task
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import rio
|
import rio
|
||||||
from rio import Component, Column, Text, TextStyle, Button, Row, ScrollContainer, Spacer, Popup, Table
|
from rio import Component, Column, Text, TextStyle, Button, Row, ScrollContainer, Spacer, Popup, Table
|
||||||
@ -96,7 +97,7 @@ class ShoppingCartAndOrders(Component):
|
|||||||
{
|
{
|
||||||
"Artikel": [item.name for item in order.items.keys()] + ["Gesamtpreis:"],
|
"Artikel": [item.name for item in order.items.keys()] + ["Gesamtpreis:"],
|
||||||
"Anzahl": [item for item in order.items.values()] + [""],
|
"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)],
|
"Preis": [AccountingService.make_euro_string_from_decimal(item.price) for item in order.items.keys()] + [AccountingService.make_euro_string_from_decimal(order.price)],
|
||||||
},
|
},
|
||||||
show_row_numbers=False
|
show_row_numbers=False
|
||||||
)
|
)
|
||||||
@ -158,7 +159,7 @@ class ShoppingCartAndOrders(Component):
|
|||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
Text(
|
Text(
|
||||||
text=f"Preis: {AccountingService.make_euro_string_from_int(sum(cart_item.price for cart_item in cart))}",
|
text=f"Preis: {AccountingService.make_euro_string_from_decimal(sum((cart_item.price for cart_item in cart), Decimal(0)))}",
|
||||||
style=TextStyle(
|
style=TextStyle(
|
||||||
fill=self.session.theme.background_color,
|
fill=self.session.theme.background_color,
|
||||||
font_size=0.8
|
font_size=0.8
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import rio
|
import rio
|
||||||
from rio import Component, Card, Column, Text, Row, Button, TextStyle, ProgressBar, event, Spacer
|
from rio import Component, Card, Column, Text, Row, Button, TextStyle, ProgressBar, event, Spacer
|
||||||
@ -12,7 +13,7 @@ from src.ez_lan_manager.types.Ticket import Ticket
|
|||||||
class TicketBuyCard(Component):
|
class TicketBuyCard(Component):
|
||||||
description: str
|
description: str
|
||||||
additional_info: str
|
additional_info: str
|
||||||
price: int
|
price: Decimal
|
||||||
category: str
|
category: str
|
||||||
pressed_cb: Callable
|
pressed_cb: Callable
|
||||||
is_enabled: bool
|
is_enabled: bool
|
||||||
@ -67,7 +68,7 @@ class TicketBuyCard(Component):
|
|||||||
margin_right=1
|
margin_right=1
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
Text(f"{AccountingService.make_euro_string_from_int(self.price)}", margin_left=1, margin_top=1, grow_x=True),
|
Text(f"{AccountingService.make_euro_string_from_decimal(self.price)}", margin_left=1, margin_top=1, grow_x=True),
|
||||||
Button(
|
Button(
|
||||||
Text("Kaufen", align_x=0.5, margin=0.4),
|
Text("Kaufen", align_x=0.5, margin=0.4),
|
||||||
margin_right=1,
|
margin_right=1,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from random import choice
|
from random import choice
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from rio import Component, TextStyle, Color, Button, Text, Rectangle, Column, Row, Spacer, Link, event, EventHandler
|
from rio import Component, TextStyle, Color, Button, Text, Rectangle, Column, Row, Spacer, Link, event, EventHandler
|
||||||
|
|
||||||
@ -23,26 +24,27 @@ class StatusButton(Component):
|
|||||||
|
|
||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
return Link(
|
return Link(
|
||||||
content=Button(
|
content=Button(
|
||||||
content=Text(self.label, style=self.STYLE, justify="center"),
|
content=Text(self.label, style=self.STYLE, justify="center"),
|
||||||
shape="rectangle",
|
shape="rectangle",
|
||||||
style="major",
|
style="major",
|
||||||
color="success" if self.enabled else "danger",
|
color="success" if self.enabled else "danger",
|
||||||
grow_x=True,
|
grow_x=True,
|
||||||
margin_left=0.6,
|
margin_left=0.6,
|
||||||
margin_right=0.6,
|
margin_right=0.6,
|
||||||
margin_top=0.6
|
margin_top=0.6
|
||||||
),
|
),
|
||||||
target_url=self.target_url,
|
target_url=self.target_url,
|
||||||
align_y=0.5,
|
align_y=0.5,
|
||||||
grow_y=False
|
grow_y=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserInfoBox(Component):
|
class UserInfoBox(Component):
|
||||||
status_change_cb: EventHandler = None
|
status_change_cb: EventHandler = None
|
||||||
TEXT_STYLE = TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9)
|
TEXT_STYLE = TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9)
|
||||||
user: Optional[User] = None
|
user: Optional[User] = None
|
||||||
user_balance: Optional[int] = 0
|
user_balance: Optional[Decimal] = Decimal("0")
|
||||||
user_ticket: Optional[Ticket] = None
|
user_ticket: Optional[Ticket] = None
|
||||||
user_seat: Optional[Seat] = None
|
user_seat: Optional[Seat] = None
|
||||||
|
|
||||||
@ -80,8 +82,10 @@ class UserInfoBox(Component):
|
|||||||
return Spacer()
|
return Spacer()
|
||||||
return Rectangle(
|
return Rectangle(
|
||||||
content=Column(
|
content=Column(
|
||||||
Text(f"{self.get_greeting()},", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9), justify="center"),
|
Text(f"{self.get_greeting()},", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9),
|
||||||
Text(f"{self.user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2), justify="center"),
|
justify="center"),
|
||||||
|
Text(f"{self.user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2),
|
||||||
|
justify="center"),
|
||||||
Row(
|
Row(
|
||||||
StatusButton(label="TICKET", target_url="./buy_ticket",
|
StatusButton(label="TICKET", target_url="./buy_ticket",
|
||||||
enabled=self.user_ticket is not None),
|
enabled=self.user_ticket is not None),
|
||||||
@ -91,7 +95,9 @@ class UserInfoBox(Component):
|
|||||||
grow_y=False
|
grow_y=False
|
||||||
),
|
),
|
||||||
UserInfoBoxButton("Profil bearbeiten", "./edit-profile"),
|
UserInfoBoxButton("Profil bearbeiten", "./edit-profile"),
|
||||||
UserInfoBoxButton(f"Guthaben: {self.session[AccountingService].make_euro_string_from_int(self.user_balance)}", "./account"),
|
UserInfoBoxButton(
|
||||||
|
f"Guthaben: {self.session[AccountingService].make_euro_string_from_decimal(self.user_balance)}",
|
||||||
|
"./account"),
|
||||||
Button(
|
Button(
|
||||||
content=Text("Ausloggen", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.6)),
|
content=Text("Ausloggen", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.6)),
|
||||||
shape="rectangle",
|
shape="rectangle",
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
# USE THIS ON AN EMPTY DATABASE TO GENERATE DEMO DATA
|
# USE THIS ON AN EMPTY DATABASE TO GENERATE DEMO DATA
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -9,13 +10,14 @@ from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItemCategory
|
|||||||
from src.ez_lan_manager.types.News import News
|
from src.ez_lan_manager.types.News import News
|
||||||
|
|
||||||
DEMO_USERS = [
|
DEMO_USERS = [
|
||||||
{ "user_name": "manfred", "user_mail": "manfred@demomail.com", "password_clear_text": "manfred" }, # Gast
|
{"user_name": "manfred", "user_mail": "manfred@demomail.com", "password_clear_text": "manfred"}, # Gast
|
||||||
{ "user_name": "gustav", "user_mail": "gustav@demomail.com", "password_clear_text": "gustav" }, # Gast + Ticket(NORMAL)
|
{"user_name": "gustav", "user_mail": "gustav@demomail.com", "password_clear_text": "gustav"}, # Gast + Ticket(NORMAL)
|
||||||
{ "user_name": "jason", "user_mail": "juergen@demomail.com", "password_clear_text": "jason" }, # Gast + Ticket(NORMAL) + Sitzplatz
|
{"user_name": "jason", "user_mail": "juergen@demomail.com", "password_clear_text": "jason"}, # Gast + Ticket(NORMAL) + Sitzplatz
|
||||||
{ "user_name": "lisa", "user_mail": "lisa@demomail.com", "password_clear_text": "lisa" }, # Teamler
|
{"user_name": "lisa", "user_mail": "lisa@demomail.com", "password_clear_text": "lisa"}, # Teamler
|
||||||
{ "user_name": "thomas", "user_mail": "thomas@demomail.com", "password_clear_text": "thomas" } # Teamler + Admin
|
{"user_name": "thomas", "user_mail": "thomas@demomail.com", "password_clear_text": "thomas"} # Teamler + Admin
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
async def run() -> None:
|
async def run() -> None:
|
||||||
services = init_services()
|
services = init_services()
|
||||||
await services[3].init_db_pool()
|
await services[3].init_db_pool()
|
||||||
@ -31,112 +33,143 @@ async def run() -> None:
|
|||||||
|
|
||||||
if not input("Generate users? (Y/n): ").lower() == "n":
|
if not input("Generate users? (Y/n): ").lower() == "n":
|
||||||
# MANFRED
|
# MANFRED
|
||||||
manfred = await user_service.create_user(DEMO_USERS[0]["user_name"], DEMO_USERS[0]["user_mail"], DEMO_USERS[0]["password_clear_text"])
|
manfred = await user_service.create_user(DEMO_USERS[0]["user_name"], DEMO_USERS[0]["user_mail"],
|
||||||
|
DEMO_USERS[0]["password_clear_text"])
|
||||||
|
|
||||||
# GUSTAV
|
# GUSTAV
|
||||||
gustav = await user_service.create_user(DEMO_USERS[1]["user_name"], DEMO_USERS[1]["user_mail"], DEMO_USERS[1]["password_clear_text"])
|
gustav = await user_service.create_user(DEMO_USERS[1]["user_name"], DEMO_USERS[1]["user_mail"],
|
||||||
await accounting_service.add_balance(gustav.user_id, 100000, "DEMO EINZAHLUNG")
|
DEMO_USERS[1]["password_clear_text"])
|
||||||
|
await accounting_service.add_balance(gustav.user_id, Decimal("1000.00"), "DEMO EINZAHLUNG")
|
||||||
await ticket_service.purchase_ticket(gustav.user_id, "NORMAL")
|
await ticket_service.purchase_ticket(gustav.user_id, "NORMAL")
|
||||||
|
|
||||||
# JASON
|
# JASON
|
||||||
jason = await user_service.create_user(DEMO_USERS[2]["user_name"], DEMO_USERS[2]["user_mail"], DEMO_USERS[2]["password_clear_text"])
|
jason = await user_service.create_user(DEMO_USERS[2]["user_name"], DEMO_USERS[2]["user_mail"],
|
||||||
await accounting_service.add_balance(jason.user_id, 100000, "DEMO EINZAHLUNG")
|
DEMO_USERS[2]["password_clear_text"])
|
||||||
|
await accounting_service.add_balance(jason.user_id, Decimal("1000.00"), "DEMO EINZAHLUNG")
|
||||||
await ticket_service.purchase_ticket(jason.user_id, "NORMAL")
|
await ticket_service.purchase_ticket(jason.user_id, "NORMAL")
|
||||||
await seating_service.seat_user(jason.user_id, "D10")
|
|
||||||
|
|
||||||
# LISA
|
# LISA
|
||||||
lisa = await user_service.create_user(DEMO_USERS[3]["user_name"], DEMO_USERS[3]["user_mail"], DEMO_USERS[3]["password_clear_text"])
|
lisa = await user_service.create_user(DEMO_USERS[3]["user_name"], DEMO_USERS[3]["user_mail"],
|
||||||
await accounting_service.add_balance(lisa.user_id, 100000, "DEMO EINZAHLUNG")
|
DEMO_USERS[3]["password_clear_text"])
|
||||||
|
await accounting_service.add_balance(lisa.user_id, Decimal("1000.00"), "DEMO EINZAHLUNG")
|
||||||
lisa.is_team_member = True
|
lisa.is_team_member = True
|
||||||
await user_service.update_user(lisa)
|
await user_service.update_user(lisa)
|
||||||
|
|
||||||
# THOMAS
|
# THOMAS
|
||||||
thomas = await user_service.create_user(DEMO_USERS[4]["user_name"], DEMO_USERS[4]["user_mail"], DEMO_USERS[4]["password_clear_text"])
|
thomas = await user_service.create_user(DEMO_USERS[4]["user_name"], DEMO_USERS[4]["user_mail"],
|
||||||
await accounting_service.add_balance(thomas.user_id, 100000, "DEMO EINZAHLUNG")
|
DEMO_USERS[4]["password_clear_text"])
|
||||||
|
await accounting_service.add_balance(thomas.user_id, Decimal("1000.00"), "DEMO EINZAHLUNG")
|
||||||
thomas.is_team_member = True
|
thomas.is_team_member = True
|
||||||
thomas.is_admin = True
|
thomas.is_admin = True
|
||||||
await user_service.update_user(thomas)
|
await user_service.update_user(thomas)
|
||||||
|
|
||||||
if not input("Generate catering menu? (Y/n): ").lower() == "n":
|
if not input("Generate catering menu? (Y/n): ").lower() == "n":
|
||||||
# MAIN_COURSE
|
# MAIN_COURSE
|
||||||
await catering_service.add_menu_item("Schnitzel Wiener Art", "mit Pommes", 1050, CateringMenuItemCategory.MAIN_COURSE)
|
await catering_service.add_menu_item("Schnitzel Wiener Art", "mit Pommes", Decimal("10.00"),
|
||||||
await catering_service.add_menu_item("Jäger Schnitzel mit Champignonrahm Sauce", "mit Pommes", 1150, CateringMenuItemCategory.MAIN_COURSE)
|
CateringMenuItemCategory.MAIN_COURSE)
|
||||||
await catering_service.add_menu_item("Tortellini in Käsesauce mit Fleischfüllung", "", 1050, CateringMenuItemCategory.MAIN_COURSE)
|
await catering_service.add_menu_item("Jäger Schnitzel mit Champignonrahm Sauce", "mit Pommes", Decimal("11.50"),
|
||||||
await catering_service.add_menu_item("Tortellini in Käsesauce ohne Fleischfüllung", "Vegetarisch", 1050, CateringMenuItemCategory.MAIN_COURSE)
|
CateringMenuItemCategory.MAIN_COURSE)
|
||||||
|
await catering_service.add_menu_item("Tortellini in Käsesauce mit Fleischfüllung", "", Decimal("10.50"),
|
||||||
|
CateringMenuItemCategory.MAIN_COURSE)
|
||||||
|
await catering_service.add_menu_item("Tortellini in Käsesauce ohne Fleischfüllung", "Vegetarisch", Decimal("10.50"),
|
||||||
|
CateringMenuItemCategory.MAIN_COURSE)
|
||||||
|
|
||||||
# SNACK
|
# SNACK
|
||||||
await catering_service.add_menu_item("Käse Schinken Wrap", "", 500, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Käse Schinken Wrap", "", Decimal("5.00"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Puten Paprika Wrap", "", 700, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Puten Paprika Wrap", "", Decimal("7.00"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Tomate Mozzarella Wrap", "", 600, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Tomate Mozzarella Wrap", "", Decimal("6.00"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Portion Pommes", "", 400, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Portion Pommes", "", Decimal("4.00"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Rinds-Currywurst", "", 450, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Rinds-Currywurst", "", Decimal("4.50"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Rinds-Currywurst mit Pommes", "", 650, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Rinds-Currywurst mit Pommes", "", Decimal("6.50"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Nudelsalat", "", 450, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Nudelsalat", "", Decimal("4.50"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Nudelsalat mit Bockwurst", "", 600, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Nudelsalat mit Bockwurst", "", Decimal("6.00"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Kartoffelsalat", "", 450, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Kartoffelsalat", "", Decimal("4.50"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Kartoffelsalat mit Bockwurst", "", 600, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Kartoffelsalat mit Bockwurst", "", Decimal("6.00"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Sandwichtoast - Schinken", "", 180, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Sandwichtoast - Schinken", "", Decimal("1.80"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Sandwichtoast - Käse", "", 180, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Sandwichtoast - Käse", "", Decimal("1.80"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Sandwichtoast - Schinken/Käse", "", 210, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Sandwichtoast - Schinken/Käse", "", Decimal("2.10"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Sandwichtoast - Salami", "", 180, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Sandwichtoast - Salami", "", Decimal("1.80"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Sandwichtoast - Salami/Käse", "", 210, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Sandwichtoast - Salami/Käse", "", Decimal("2.10"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Chips - Western Style", "", 130, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Chips - Western Style", "", Decimal("1.30"), CateringMenuItemCategory.SNACK)
|
||||||
await catering_service.add_menu_item("Nachos - Salted", "", 130, CateringMenuItemCategory.SNACK)
|
await catering_service.add_menu_item("Nachos - Salted", "", Decimal("1.30"), CateringMenuItemCategory.SNACK)
|
||||||
|
|
||||||
# DESSERT
|
# DESSERT
|
||||||
await catering_service.add_menu_item("Panna Cotta mit Erdbeersauce", "", 700, CateringMenuItemCategory.DESSERT)
|
await catering_service.add_menu_item("Panna Cotta mit Erdbeersauce", "", Decimal("7.00"), CateringMenuItemCategory.DESSERT)
|
||||||
await catering_service.add_menu_item("Panna Cotta mit Blaubeersauce", "", 700, CateringMenuItemCategory.DESSERT)
|
await catering_service.add_menu_item("Panna Cotta mit Blaubeersauce", "", Decimal("7.00"), CateringMenuItemCategory.DESSERT)
|
||||||
await catering_service.add_menu_item("Mousse au Chocolat", "", 700, CateringMenuItemCategory.DESSERT)
|
await catering_service.add_menu_item("Mousse au Chocolat", "", Decimal("7.00"), CateringMenuItemCategory.DESSERT)
|
||||||
|
|
||||||
# BREAKFAST
|
# BREAKFAST
|
||||||
await catering_service.add_menu_item("Fruit Loops", "", 150, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Fruit Loops", "", Decimal("1.50"), CateringMenuItemCategory.BREAKFAST)
|
||||||
await catering_service.add_menu_item("Smacks", "", 150, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Smacks", "", Decimal("1.50"), CateringMenuItemCategory.BREAKFAST)
|
||||||
await catering_service.add_menu_item("Knuspermüsli", "Schoko", 200, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Knuspermüsli", "Schoko", Decimal("2.00"), CateringMenuItemCategory.BREAKFAST)
|
||||||
await catering_service.add_menu_item("Cini Minis", "", 150, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Cini Minis", "", Decimal("2.50"), CateringMenuItemCategory.BREAKFAST)
|
||||||
await catering_service.add_menu_item("Brötchen - Schinken", "mit Margarine", 120, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Brötchen - Schinken", "mit Margarine", Decimal("1.20"),
|
||||||
await catering_service.add_menu_item("Brötchen - Käse", "mit Margarine", 120, CateringMenuItemCategory.BREAKFAST)
|
CateringMenuItemCategory.BREAKFAST)
|
||||||
await catering_service.add_menu_item("Brötchen - Schinken/Käse", "mit Margarine", 140, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Brötchen - Käse", "mit Margarine", Decimal("1.20"),
|
||||||
await catering_service.add_menu_item("Brötchen - Salami", "mit Margarine", 120, CateringMenuItemCategory.BREAKFAST)
|
CateringMenuItemCategory.BREAKFAST)
|
||||||
await catering_service.add_menu_item("Brötchen - Salami/Käse", "mit Margarine", 140, CateringMenuItemCategory.BREAKFAST)
|
await catering_service.add_menu_item("Brötchen - Schinken/Käse", "mit Margarine", Decimal("1.40"),
|
||||||
await catering_service.add_menu_item("Brötchen - Nutella", "mit Margarine", 120, CateringMenuItemCategory.BREAKFAST)
|
CateringMenuItemCategory.BREAKFAST)
|
||||||
|
await catering_service.add_menu_item("Brötchen - Salami", "mit Margarine", Decimal("1.20"),
|
||||||
|
CateringMenuItemCategory.BREAKFAST)
|
||||||
|
await catering_service.add_menu_item("Brötchen - Salami/Käse", "mit Margarine", Decimal("1.40"),
|
||||||
|
CateringMenuItemCategory.BREAKFAST)
|
||||||
|
await catering_service.add_menu_item("Brötchen - Nutella", "mit Margarine", Decimal("1.20"),
|
||||||
|
CateringMenuItemCategory.BREAKFAST)
|
||||||
|
|
||||||
# BEVERAGE_NON_ALCOHOLIC
|
# BEVERAGE_NON_ALCOHOLIC
|
||||||
await catering_service.add_menu_item("Wasser - Still", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
await catering_service.add_menu_item("Wasser - Still", "1L Flasche", Decimal("2.00"),
|
||||||
await catering_service.add_menu_item("Wasser - Medium", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Wasser - Spritzig", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
await catering_service.add_menu_item("Wasser - Medium", "1L Flasche", Decimal("2.00"),
|
||||||
await catering_service.add_menu_item("Coca-Cola", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Coca-Cola Zero", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
await catering_service.add_menu_item("Wasser - Spritzig", "1L Flasche", Decimal("2.00"),
|
||||||
await catering_service.add_menu_item("Fanta", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Sprite", "1L Flasche", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
await catering_service.add_menu_item("Coca-Cola", "1L Flasche", Decimal("2.00"),
|
||||||
await catering_service.add_menu_item("Spezi", "von Paulaner, 0,5L Flasche", 150, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Red Bull", "", 200, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
await catering_service.add_menu_item("Coca-Cola Zero", "1L Flasche", Decimal("2.00"),
|
||||||
await catering_service.add_menu_item("Energy", "Hausmarke", 150, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Fanta", "1L Flasche", Decimal("2.00"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Sprite", "1L Flasche", Decimal("2.00"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Spezi", "von Paulaner, 0,5L Flasche", Decimal("1.50"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Red Bull", "", Decimal("2.00"), CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Energy", "Hausmarke", Decimal("1.50"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC)
|
||||||
|
|
||||||
# BEVERAGE_ALCOHOLIC
|
# BEVERAGE_ALCOHOLIC
|
||||||
await catering_service.add_menu_item("Pils", "0,33L Flasche", 190, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
await catering_service.add_menu_item("Pils", "0,33L Flasche", Decimal("1.90"), CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Radler", "0,33L Flasche", 190, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
await catering_service.add_menu_item("Radler", "0,33L Flasche", Decimal("1.90"),
|
||||||
await catering_service.add_menu_item("Diesel", "0,33L Flasche", 190, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Apfelwein Pur", "0,33L Flasche", 190, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
await catering_service.add_menu_item("Diesel", "0,33L Flasche", Decimal("1.90"),
|
||||||
await catering_service.add_menu_item("Apfelwein Sauer", "0,33L Flasche", 190, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
||||||
await catering_service.add_menu_item("Apfelwein Cola", "0,33L Flasche", 190, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
await catering_service.add_menu_item("Apfelwein Pur", "0,33L Flasche", Decimal("1.90"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Apfelwein Sauer", "0,33L Flasche", Decimal("1.90"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
||||||
|
await catering_service.add_menu_item("Apfelwein Cola", "0,33L Flasche", Decimal("1.90"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_ALCOHOLIC)
|
||||||
|
|
||||||
# BEVERAGE_COCKTAIL
|
# BEVERAGE_COCKTAIL
|
||||||
await catering_service.add_menu_item("Vodka Energy", "", 400, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
await catering_service.add_menu_item("Vodka Energy", "", Decimal("4.00"), CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
await catering_service.add_menu_item("Vodka O-Saft", "", 400, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
await catering_service.add_menu_item("Vodka O-Saft", "", Decimal("4.00"), CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
await catering_service.add_menu_item("Whiskey Cola", "mit Bourbon", 400, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
await catering_service.add_menu_item("Whiskey Cola", "mit Bourbon", Decimal("4.00"),
|
||||||
await catering_service.add_menu_item("Jägermeister Energy", "", 400, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
await catering_service.add_menu_item("Sex on the Beach", "", 550, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
await catering_service.add_menu_item("Jägermeister Energy", "", Decimal("4.00"), CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
await catering_service.add_menu_item("Long Island Ice Tea", "", 550, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
await catering_service.add_menu_item("Sex on the Beach", "", Decimal("5.50"), CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
await catering_service.add_menu_item("Caipirinha", "", 550, CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
await catering_service.add_menu_item("Long Island Ice Tea", "", Decimal("5.50"), CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
|
await catering_service.add_menu_item("Caipirinha", "", Decimal("5.50"), CateringMenuItemCategory.BEVERAGE_COCKTAIL)
|
||||||
|
|
||||||
# BEVERAGE_SHOT
|
# BEVERAGE_SHOT
|
||||||
await catering_service.add_menu_item("Jägermeister", "", 200, CateringMenuItemCategory.BEVERAGE_SHOT)
|
await catering_service.add_menu_item("Jägermeister", "", Decimal("2.00"), CateringMenuItemCategory.BEVERAGE_SHOT)
|
||||||
await catering_service.add_menu_item("Tequila", "", 200, CateringMenuItemCategory.BEVERAGE_SHOT)
|
await catering_service.add_menu_item("Tequila", "", Decimal("2.00"), CateringMenuItemCategory.BEVERAGE_SHOT)
|
||||||
await catering_service.add_menu_item("PfEZzi", "Getunter Pfefferminz-Schnaps", 199, CateringMenuItemCategory.BEVERAGE_SHOT)
|
await catering_service.add_menu_item("PfEZzi", "Getunter Pfefferminz-Schnaps", Decimal("1.99"),
|
||||||
|
CateringMenuItemCategory.BEVERAGE_SHOT)
|
||||||
|
|
||||||
# NON_FOOD
|
# NON_FOOD
|
||||||
await catering_service.add_menu_item("Zigaretten", "Elixyr", 800, CateringMenuItemCategory.NON_FOOD)
|
await catering_service.add_menu_item("Zigaretten", "Elixyr", Decimal("8.00"), CateringMenuItemCategory.NON_FOOD)
|
||||||
await catering_service.add_menu_item("Mentholfilter", "passend für Elixyr", 120, CateringMenuItemCategory.NON_FOOD)
|
await catering_service.add_menu_item("Mentholfilter", "passend für Elixyr", Decimal("1.20"),
|
||||||
|
CateringMenuItemCategory.NON_FOOD)
|
||||||
|
|
||||||
if not input("Generate default new post? (Y/n): ").lower() == "n":
|
if not input("Generate default new post? (Y/n): ").lower() == "n":
|
||||||
loops = 0
|
loops = 0
|
||||||
@ -154,11 +187,14 @@ async def run() -> None:
|
|||||||
news_id=None,
|
news_id=None,
|
||||||
title="Der EZ LAN Manager",
|
title="Der EZ LAN Manager",
|
||||||
subtitle="Eine Software des EZ GG e.V.",
|
subtitle="Eine Software des EZ GG e.V.",
|
||||||
content="Dies ist eine WIP-Version des EZ LAN Managers. Diese Software soll uns helfen in Zukunft die LAN Parties des EZ GG e.V.'s zu organisieren. Wer Fehler findet darf sie behalten. (Oder er meldet sie)",
|
content="Dies ist eine WIP-Version des EZ LAN Managers. Diese Software soll uns helfen in Zukunft die LAN "
|
||||||
|
"Parties des EZ GG e.V.'s zu organisieren. Wer Fehler findet darf sie behalten. (Oder er meldet "
|
||||||
|
"sie)",
|
||||||
author=user,
|
author=user,
|
||||||
news_date=date.today()
|
news_date=date.today()
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with asyncio.Runner() as loop:
|
with asyncio.Runner() as loop:
|
||||||
loop.run(run())
|
loop.run(run())
|
||||||
|
|||||||
@ -159,7 +159,7 @@ class AccountPage(Component):
|
|||||||
align_x=0
|
align_x=0
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
f"{'-' if transaction.is_debit else '+'}{AccountingService.make_euro_string_from_int(transaction.value)}",
|
f"{'-' if transaction.is_debit else '+'}{AccountingService.make_euro_string_from_decimal(transaction.value)}",
|
||||||
style=TextStyle(
|
style=TextStyle(
|
||||||
fill=self.session.theme.danger_color if transaction.is_debit else self.session.theme.success_color,
|
fill=self.session.theme.danger_color if transaction.is_debit else self.session.theme.success_color,
|
||||||
font_size=0.8
|
font_size=0.8
|
||||||
@ -175,7 +175,7 @@ class AccountPage(Component):
|
|||||||
return Column(
|
return Column(
|
||||||
MainViewContentBox(
|
MainViewContentBox(
|
||||||
content=Text(
|
content=Text(
|
||||||
f"Kontostand: {AccountingService.make_euro_string_from_int(self.balance)}",
|
f"Kontostand: {AccountingService.make_euro_string_from_decimal(self.balance)}",
|
||||||
style=TextStyle(
|
style=TextStyle(
|
||||||
fill=self.session.theme.background_color,
|
fill=self.session.theme.background_color,
|
||||||
font_size=1.2
|
font_size=1.2
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from src.ez_lan_manager.types.Seat import Seat
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class CateringOrderInfoPopup(Component):
|
class CateringOrderInfoPopup(Component):
|
||||||
order: Optional[CateringOrder] = None
|
order: Optional[CateringOrder] = None
|
||||||
close_cb: Optional[Callable] = None
|
close_cb: Optional[Callable] = None
|
||||||
@ -20,17 +21,18 @@ class CateringOrderInfoPopup(Component):
|
|||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
if not self.order:
|
if not self.order:
|
||||||
return Card(
|
return Card(
|
||||||
content=Text(""),
|
content=Text(""),
|
||||||
margin=1,
|
margin=1,
|
||||||
color=self.session.theme.hud_color,
|
color=self.session.theme.hud_color,
|
||||||
min_width=40,
|
min_width=40,
|
||||||
min_height=40,
|
min_height=40,
|
||||||
on_press=self.close_cb
|
on_press=self.close_cb
|
||||||
)
|
)
|
||||||
rows = []
|
rows = []
|
||||||
is_contrast_line = True
|
is_contrast_line = True
|
||||||
for item, amount in self.order.items.items():
|
for item, amount in self.order.items.items():
|
||||||
style = TextStyle(fill=self.session.theme.secondary_color if is_contrast_line else self.session.theme.neutral_color)
|
style = TextStyle(
|
||||||
|
fill=self.session.theme.secondary_color if is_contrast_line else self.session.theme.neutral_color)
|
||||||
is_contrast_line = not is_contrast_line
|
is_contrast_line = not is_contrast_line
|
||||||
rows.append(
|
rows.append(
|
||||||
Row(
|
Row(
|
||||||
@ -44,7 +46,8 @@ class CateringOrderInfoPopup(Component):
|
|||||||
Text(f"Bestellung {self.order.order_id}", style=TextStyle(font_size=1.2), margin_bottom=1),
|
Text(f"Bestellung {self.order.order_id}", style=TextStyle(font_size=1.2), margin_bottom=1),
|
||||||
*rows,
|
*rows,
|
||||||
Spacer(),
|
Spacer(),
|
||||||
Row(Text("Gesamtpreis:"), Spacer(), Text(self.session[AccountingService].make_euro_string_from_int(self.order.price)))
|
Row(Text("Gesamtpreis:"), Spacer(),
|
||||||
|
Text(self.session[AccountingService].make_euro_string_from_decimal(self.order.price)))
|
||||||
),
|
),
|
||||||
margin=1,
|
margin=1,
|
||||||
color=self.session.theme.hud_color,
|
color=self.session.theme.hud_color,
|
||||||
@ -56,11 +59,13 @@ class CateringOrderInfoPopup(Component):
|
|||||||
colorize_on_hover=False
|
colorize_on_hover=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CateringOrderWithSeat:
|
class CateringOrderWithSeat:
|
||||||
catering_order: CateringOrder
|
catering_order: CateringOrder
|
||||||
seat: Optional[Seat]
|
seat: Optional[Seat]
|
||||||
|
|
||||||
|
|
||||||
class ManageCateringPage(Component):
|
class ManageCateringPage(Component):
|
||||||
all_orders: list[CateringOrderWithSeat] = field(default_factory=list)
|
all_orders: list[CateringOrderWithSeat] = field(default_factory=list)
|
||||||
last_updated: Optional[datetime] = None
|
last_updated: Optional[datetime] = None
|
||||||
@ -73,7 +78,6 @@ class ManageCateringPage(Component):
|
|||||||
self.all_orders = await self.populate_seating(await self.session[CateringService].get_orders())
|
self.all_orders = await self.populate_seating(await self.session[CateringService].get_orders())
|
||||||
self.last_updated = datetime.now()
|
self.last_updated = datetime.now()
|
||||||
|
|
||||||
|
|
||||||
@event.periodic(30)
|
@event.periodic(30)
|
||||||
async def update_orders(self) -> None:
|
async def update_orders(self) -> None:
|
||||||
polled_orders = await self.session[CateringService].get_orders()
|
polled_orders = await self.session[CateringService].get_orders()
|
||||||
@ -88,12 +92,16 @@ class ManageCateringPage(Component):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def get_all_pending_orders(self) -> list[CateringOrderWithSeat]:
|
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))
|
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)
|
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]:
|
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))
|
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)
|
sorted_list = sorted(filtered_list, key=lambda o: o.catering_order.order_date)
|
||||||
return sorted_list
|
return sorted_list
|
||||||
|
|
||||||
@ -154,7 +162,8 @@ class ManageCateringPage(Component):
|
|||||||
margin_bottom=1,
|
margin_bottom=1,
|
||||||
on_press=self.update_orders
|
on_press=self.update_orders
|
||||||
),
|
),
|
||||||
*[CateringManagementOrderDisplay(v.catering_order, v.seat, self.order_clicked) for v in self.get_all_pending_orders()],
|
*[CateringManagementOrderDisplay(v.catering_order, v.seat, self.order_clicked) for v in
|
||||||
|
self.get_all_pending_orders()],
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
MainViewContentBox(
|
MainViewContentBox(
|
||||||
@ -169,7 +178,8 @@ class ManageCateringPage(Component):
|
|||||||
margin_bottom=0.2,
|
margin_bottom=0.2,
|
||||||
align_x=0.5
|
align_x=0.5
|
||||||
),
|
),
|
||||||
*[CateringManagementOrderDisplay(v.catering_order, v.seat, self.order_clicked) for v in self.get_all_completed_orders()],
|
*[CateringManagementOrderDisplay(v.catering_order, v.seat, self.order_clicked) for v in
|
||||||
|
self.get_all_completed_orders()],
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|||||||
@ -17,6 +17,7 @@ from src.ez_lan_manager.types.User import User
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class ClickableGridContent(Component):
|
class ClickableGridContent(Component):
|
||||||
text: str = ""
|
text: str = ""
|
||||||
is_hovered: bool = False
|
is_hovered: bool = False
|
||||||
@ -36,7 +37,8 @@ class ClickableGridContent(Component):
|
|||||||
content=Rectangle(
|
content=Rectangle(
|
||||||
content=Text(
|
content=Text(
|
||||||
self.text,
|
self.text,
|
||||||
style=TextStyle(fill=self.session.theme.success_color) if self.is_hovered else TextStyle(fill=self.session.theme.background_color),
|
style=TextStyle(fill=self.session.theme.success_color) if self.is_hovered else TextStyle(
|
||||||
|
fill=self.session.theme.background_color),
|
||||||
grow_x=True
|
grow_x=True
|
||||||
),
|
),
|
||||||
fill=Color.TRANSPARENT,
|
fill=Color.TRANSPARENT,
|
||||||
@ -47,6 +49,7 @@ class ClickableGridContent(Component):
|
|||||||
on_press=self.on_mouse_click
|
on_press=self.on_mouse_click
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ManageUsersPage(Component):
|
class ManageUsersPage(Component):
|
||||||
selected_user: Optional[User] = None
|
selected_user: Optional[User] = None
|
||||||
all_users: Optional[list] = None
|
all_users: Optional[list] = None
|
||||||
@ -66,13 +69,15 @@ class ManageUsersPage(Component):
|
|||||||
async def on_user_clicked(self, user_name: str) -> None:
|
async def on_user_clicked(self, user_name: str) -> None:
|
||||||
self.selected_user = next(filter(lambda user: user.user_name == user_name, self.all_users))
|
self.selected_user = next(filter(lambda user: user.user_name == user_name, self.all_users))
|
||||||
user_account_balance_raw = await self.session[AccountingService].get_balance(self.selected_user.user_id)
|
user_account_balance_raw = await self.session[AccountingService].get_balance(self.selected_user.user_id)
|
||||||
self.user_account_balance = AccountingService.make_euro_string_from_int(user_account_balance_raw)
|
self.user_account_balance = AccountingService.make_euro_string_from_decimal(user_account_balance_raw)
|
||||||
seat = await self.session[SeatingService].get_user_seat(self.selected_user.user_id)
|
seat = await self.session[SeatingService].get_user_seat(self.selected_user.user_id)
|
||||||
self.user_seat = seat.seat_id if seat else "-"
|
self.user_seat = seat.seat_id if seat else "-"
|
||||||
self.is_user_account_locked = not self.selected_user.is_active
|
self.is_user_account_locked = not self.selected_user.is_active
|
||||||
|
|
||||||
async def on_search_parameters_changed(self, e: TextInputChangeEvent) -> None:
|
async def on_search_parameters_changed(self, e: TextInputChangeEvent) -> None:
|
||||||
self.search_results = list(filter(lambda user: (e.text.lower() in user.user_name.lower()) or e.text.lower() in str(user.user_id), self.all_users))
|
self.search_results = list(
|
||||||
|
filter(lambda user: (e.text.lower() in user.user_name.lower()) or e.text.lower() in str(user.user_id),
|
||||||
|
self.all_users))
|
||||||
|
|
||||||
async def change_account_active(self, _: SwitchChangeEvent) -> None:
|
async def change_account_active(self, _: SwitchChangeEvent) -> None:
|
||||||
self.selected_user.is_active = not self.is_user_account_locked
|
self.selected_user.is_active = not self.is_user_account_locked
|
||||||
@ -84,7 +89,7 @@ class ManageUsersPage(Component):
|
|||||||
|
|
||||||
logger.info(f"Got new transaction for user with ID '{transaction.user_id}' over "
|
logger.info(f"Got new transaction for user with ID '{transaction.user_id}' over "
|
||||||
f"{'-' if transaction.is_debit else '+'}"
|
f"{'-' if transaction.is_debit else '+'}"
|
||||||
f"{AccountingService.make_euro_string_from_int(transaction.value)} "
|
f"{AccountingService.make_euro_string_from_decimal(transaction.value)} "
|
||||||
f"with reference '{transaction.reference}'")
|
f"with reference '{transaction.reference}'")
|
||||||
|
|
||||||
if transaction.is_debit:
|
if transaction.is_debit:
|
||||||
@ -108,7 +113,6 @@ class ManageUsersPage(Component):
|
|||||||
self.accounting_section_result_text = f"Guthaben {'entfernt' if transaction.is_debit else 'hinzugefügt'}!"
|
self.accounting_section_result_text = f"Guthaben {'entfernt' if transaction.is_debit else 'hinzugefügt'}!"
|
||||||
self.accounting_section_result_success = True
|
self.accounting_section_result_success = True
|
||||||
|
|
||||||
|
|
||||||
def build(self) -> Component:
|
def build(self) -> Component:
|
||||||
return Column(
|
return Column(
|
||||||
MainViewContentBox(
|
MainViewContentBox(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
from asyncio import sleep
|
from asyncio import sleep
|
||||||
|
from decimal import Decimal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from rio import Text, Column, TextStyle, Component, event, PressEvent, ProgressCircle
|
from rio import Text, Column, TextStyle, Component, event, PressEvent, ProgressCircle
|
||||||
@ -21,7 +22,7 @@ class SeatingPlanPage(Component):
|
|||||||
seating_info: Optional[list[Seat]] = None
|
seating_info: Optional[list[Seat]] = None
|
||||||
current_seat_id: Optional[str] = None
|
current_seat_id: Optional[str] = None
|
||||||
current_seat_occupant: Optional[str] = None
|
current_seat_occupant: Optional[str] = None
|
||||||
current_seat_price: int = 0
|
current_seat_price: Decimal = Decimal("0")
|
||||||
current_seat_is_blocked: bool = False
|
current_seat_is_blocked: bool = False
|
||||||
user: Optional[User] = None
|
user: Optional[User] = None
|
||||||
show_info_box: bool = True
|
show_info_box: bool = True
|
||||||
@ -54,7 +55,7 @@ class SeatingPlanPage(Component):
|
|||||||
self.current_seat_is_blocked = seat.is_blocked
|
self.current_seat_is_blocked = seat.is_blocked
|
||||||
self.current_seat_id = seat.seat_id
|
self.current_seat_id = seat.seat_id
|
||||||
ticket_info = self.session[TicketingService].get_ticket_info_by_category(seat.category)
|
ticket_info = self.session[TicketingService].get_ticket_info_by_category(seat.category)
|
||||||
price = 0 if not ticket_info else ticket_info.price
|
price = Decimal("0") if not ticket_info else ticket_info.price
|
||||||
self.current_seat_price = price
|
self.current_seat_price = price
|
||||||
if seat.user:
|
if seat.user:
|
||||||
self.current_seat_occupant = seat.user.user_name
|
self.current_seat_occupant = seat.user.user_name
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
import logging
|
import logging
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from decimal import Decimal, ROUND_DOWN
|
||||||
|
|
||||||
from src.ez_lan_manager.services.DatabaseService import DatabaseService
|
from src.ez_lan_manager.services.DatabaseService import DatabaseService
|
||||||
from src.ez_lan_manager.types.Transaction import Transaction
|
from src.ez_lan_manager.types.Transaction import Transaction
|
||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class InsufficientFundsError(Exception):
|
class InsufficientFundsError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountingService:
|
class AccountingService:
|
||||||
def __init__(self, db_service: DatabaseService) -> None:
|
def __init__(self, db_service: DatabaseService) -> None:
|
||||||
self._db_service = db_service
|
self._db_service = db_service
|
||||||
@ -19,7 +22,7 @@ class AccountingService:
|
|||||||
""" Adds a function to this service, which is called whenever the account balance changes """
|
""" Adds a function to this service, which is called whenever the account balance changes """
|
||||||
self._update_hooks.add(update_hook)
|
self._update_hooks.add(update_hook)
|
||||||
|
|
||||||
async def add_balance(self, user_id: int, balance_to_add: int, reference: str) -> int:
|
async def add_balance(self, user_id: int, balance_to_add: Decimal, reference: str) -> Decimal:
|
||||||
await self._db_service.add_transaction(Transaction(
|
await self._db_service.add_transaction(Transaction(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
value=balance_to_add,
|
value=balance_to_add,
|
||||||
@ -27,12 +30,12 @@ class AccountingService:
|
|||||||
reference=reference,
|
reference=reference,
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
))
|
))
|
||||||
logger.debug(f"Added balance of {self.make_euro_string_from_int(balance_to_add)} to user with ID {user_id}")
|
logger.debug(f"Added balance of {self.make_euro_string_from_decimal(balance_to_add)} to user with ID {user_id}")
|
||||||
for update_hook in self._update_hooks:
|
for update_hook in self._update_hooks:
|
||||||
await update_hook()
|
await update_hook()
|
||||||
return await self.get_balance(user_id)
|
return await self.get_balance(user_id)
|
||||||
|
|
||||||
async def remove_balance(self, user_id: int, balance_to_remove: int, reference: str) -> int:
|
async def remove_balance(self, user_id: int, balance_to_remove: Decimal, reference: str) -> Decimal:
|
||||||
current_balance = await self.get_balance(user_id)
|
current_balance = await self.get_balance(user_id)
|
||||||
if (current_balance - balance_to_remove) < 0:
|
if (current_balance - balance_to_remove) < 0:
|
||||||
raise InsufficientFundsError
|
raise InsufficientFundsError
|
||||||
@ -43,13 +46,14 @@ class AccountingService:
|
|||||||
reference=reference,
|
reference=reference,
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
))
|
))
|
||||||
logger.debug(f"Removed balance of {self.make_euro_string_from_int(balance_to_remove)} to user with ID {user_id}")
|
logger.debug(
|
||||||
|
f"Removed balance of {self.make_euro_string_from_decimal(balance_to_remove)} to user with ID {user_id}")
|
||||||
for update_hook in self._update_hooks:
|
for update_hook in self._update_hooks:
|
||||||
await update_hook()
|
await update_hook()
|
||||||
return await self.get_balance(user_id)
|
return await self.get_balance(user_id)
|
||||||
|
|
||||||
async def get_balance(self, user_id: int) -> int:
|
async def get_balance(self, user_id: int) -> Decimal:
|
||||||
balance_buffer = 0
|
balance_buffer = Decimal("0")
|
||||||
for transaction in await self._db_service.get_all_transactions_for_user(user_id):
|
for transaction in await self._db_service.get_all_transactions_for_user(user_id):
|
||||||
if transaction.is_debit:
|
if transaction.is_debit:
|
||||||
balance_buffer -= transaction.value
|
balance_buffer -= transaction.value
|
||||||
@ -61,23 +65,9 @@ class AccountingService:
|
|||||||
return await self._db_service.get_all_transactions_for_user(user_id)
|
return await self._db_service.get_all_transactions_for_user(user_id)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_euro_string_from_int(cent_int: int) -> str:
|
def make_euro_string_from_decimal(euros: Decimal) -> str:
|
||||||
""" Internally, all money values are cents as ints. Only when showing them to the user we generate a string. Prevents float inaccuracy. """
|
"""
|
||||||
as_str = str(cent_int)
|
Internally, all money values are euros as decimal. Only when showing them to the user we generate a string.
|
||||||
if as_str[0] == "-":
|
"""
|
||||||
is_negative = True
|
rounded_decimal = str(euros.quantize(Decimal(".01"), rounding=ROUND_DOWN))
|
||||||
as_str = as_str[1:]
|
return f"{rounded_decimal} €"
|
||||||
else:
|
|
||||||
is_negative = False
|
|
||||||
|
|
||||||
if len(as_str) == 1:
|
|
||||||
result = f"0.0{as_str} €"
|
|
||||||
elif len(as_str) == 2:
|
|
||||||
result = f"0.{as_str} €"
|
|
||||||
else:
|
|
||||||
result = f"{as_str[:-2]}.{as_str[-2:]} €"
|
|
||||||
|
|
||||||
if is_negative:
|
|
||||||
result = f"-{result}"
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from decimal import Decimal
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -10,11 +11,13 @@ from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItem, Catering
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class CateringErrorType(Enum):
|
class CateringErrorType(Enum):
|
||||||
INCLUDES_DISABLED_ITEM = 0
|
INCLUDES_DISABLED_ITEM = 0
|
||||||
INSUFFICIENT_FUNDS = 1
|
INSUFFICIENT_FUNDS = 1
|
||||||
GENERIC = 99
|
GENERIC = 99
|
||||||
|
|
||||||
|
|
||||||
class CateringError(Exception):
|
class CateringError(Exception):
|
||||||
def __init__(self, message: str, error_type: CateringErrorType = CateringErrorType.GENERIC) -> None:
|
def __init__(self, message: str, error_type: CateringErrorType = CateringErrorType.GENERIC) -> None:
|
||||||
self.message = message
|
self.message = message
|
||||||
@ -30,7 +33,8 @@ class CateringService:
|
|||||||
|
|
||||||
# ORDERS
|
# ORDERS
|
||||||
|
|
||||||
async def place_order(self, menu_items: CateringMenuItemsWithAmount, user_id: int, is_delivery: bool = True) -> CateringOrder:
|
async def place_order(self, menu_items: CateringMenuItemsWithAmount, user_id: int,
|
||||||
|
is_delivery: bool = True) -> CateringOrder:
|
||||||
for menu_item in menu_items:
|
for menu_item in menu_items:
|
||||||
if menu_item.is_disabled:
|
if menu_item.is_disabled:
|
||||||
raise CateringError("Order includes disabled items", CateringErrorType.INCLUDES_DISABLED_ITEM)
|
raise CateringError("Order includes disabled items", CateringErrorType.INCLUDES_DISABLED_ITEM)
|
||||||
@ -39,14 +43,15 @@ class CateringService:
|
|||||||
if not user:
|
if not user:
|
||||||
raise CateringError("User does not exist")
|
raise CateringError("User does not exist")
|
||||||
|
|
||||||
total_price = sum([item.price * quantity for item, quantity in menu_items.items()])
|
total_price = sum([item.price * quantity for item, quantity in menu_items.items()], Decimal(0))
|
||||||
if await self._accounting_service.get_balance(user_id) < total_price:
|
if await self._accounting_service.get_balance(user_id) < total_price:
|
||||||
raise CateringError("Insufficient funds", CateringErrorType.INSUFFICIENT_FUNDS)
|
raise CateringError("Insufficient funds", CateringErrorType.INSUFFICIENT_FUNDS)
|
||||||
|
|
||||||
order = await self._db_service.add_new_order(menu_items, user_id, is_delivery)
|
order = await self._db_service.add_new_order(menu_items, user_id, is_delivery)
|
||||||
if order:
|
if order:
|
||||||
await self._accounting_service.remove_balance(user_id, total_price, f"CATERING - {order.order_id}")
|
await 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)}")
|
logger.info(
|
||||||
|
f"User '{order.customer.user_name}' (ID:{order.customer.user_id}) ordered from catering for {self._accounting_service.make_euro_string_from_decimal(total_price)}")
|
||||||
# await self.cancel_order(order) # ToDo: Check if commented out before commit. Un-comment to auto-cancel every placed order
|
# await self.cancel_order(order) # ToDo: Check if commented out before commit. Un-comment to auto-cancel every placed order
|
||||||
return order
|
return order
|
||||||
|
|
||||||
@ -68,7 +73,8 @@ class CateringService:
|
|||||||
async def cancel_order(self, order: CateringOrder) -> bool:
|
async def cancel_order(self, order: CateringOrder) -> bool:
|
||||||
change_result = await self._db_service.change_order_status(order.order_id, CateringOrderStatus.CANCELED)
|
change_result = await self._db_service.change_order_status(order.order_id, CateringOrderStatus.CANCELED)
|
||||||
if change_result:
|
if change_result:
|
||||||
await self._accounting_service.add_balance(order.customer.user_id, order.price, f"CATERING REFUND - {order.order_id}")
|
await self._accounting_service.add_balance(order.customer.user_id, order.price,
|
||||||
|
f"CATERING REFUND - {order.order_id}")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -86,7 +92,8 @@ class CateringService:
|
|||||||
raise CateringError("Menu item not found")
|
raise CateringError("Menu item not found")
|
||||||
return item
|
return item
|
||||||
|
|
||||||
async def add_menu_item(self, name: str, info: str, price: int, category: CateringMenuItemCategory, is_disabled: bool = False) -> CateringMenuItem:
|
async def add_menu_item(self, name: str, info: str, price: Decimal, category: CateringMenuItemCategory,
|
||||||
|
is_disabled: bool = False) -> CateringMenuItem:
|
||||||
if new_item := await self._db_service.add_menu_item(name, info, price, category, is_disabled):
|
if new_item := await self._db_service.add_menu_item(name, info, price, category, is_disabled):
|
||||||
return new_item
|
return new_item
|
||||||
raise CateringError(f"Could not add item '{name}' to the menu.")
|
raise CateringError(f"Could not add item '{name}' to the menu.")
|
||||||
@ -134,3 +141,4 @@ class CateringService:
|
|||||||
return self.cached_cart[user_id]
|
return self.cached_cart[user_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import logging
|
import logging
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|
||||||
from from_root import from_root
|
from from_root import from_root
|
||||||
|
|
||||||
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration, MailingServiceConfiguration, LanInfo, SeatingConfiguration, TicketInfo
|
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration, MailingServiceConfiguration, LanInfo, \
|
||||||
|
SeatingConfiguration, TicketInfo
|
||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationService:
|
class ConfigurationService:
|
||||||
def __init__(self, config_file_path: Path) -> None:
|
def __init__(self, config_file_path: Path) -> None:
|
||||||
try:
|
try:
|
||||||
@ -40,7 +43,6 @@ class ConfigurationService:
|
|||||||
logger.fatal("Error loading DatabaseConfiguration, exiting...")
|
logger.fatal("Error loading DatabaseConfiguration, exiting...")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def get_mailing_service_configuration(self) -> MailingServiceConfiguration:
|
def get_mailing_service_configuration(self) -> MailingServiceConfiguration:
|
||||||
try:
|
try:
|
||||||
mailing_configuration = self._config["mailing"]
|
mailing_configuration = self._config["mailing"]
|
||||||
@ -83,7 +85,7 @@ class ConfigurationService:
|
|||||||
return tuple([TicketInfo(
|
return tuple([TicketInfo(
|
||||||
category=value,
|
category=value,
|
||||||
total_tickets=self._config["tickets"][value]["total_tickets"],
|
total_tickets=self._config["tickets"][value]["total_tickets"],
|
||||||
price=self._config["tickets"][value]["price"],
|
price=Decimal(self._config["tickets"][value]["price"]),
|
||||||
description=self._config["tickets"][value]["description"],
|
description=self._config["tickets"][value]["description"],
|
||||||
additional_info=self._config["tickets"][value]["additional_info"],
|
additional_info=self._config["tickets"][value]["additional_info"],
|
||||||
is_default=self._config["tickets"][value]["is_default"]
|
is_default=self._config["tickets"][value]["is_default"]
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import logging
|
|||||||
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
import aiomysql
|
import aiomysql
|
||||||
|
|
||||||
@ -17,14 +18,18 @@ from src.ez_lan_manager.types.User import User
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class DuplicationError(Exception):
|
class DuplicationError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NoDatabaseConnectionError(Exception):
|
class NoDatabaseConnectionError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DatabaseService:
|
class DatabaseService:
|
||||||
MAX_CONNECTION_RETRIES = 5
|
MAX_CONNECTION_RETRIES = 5
|
||||||
|
|
||||||
def __init__(self, database_config: DatabaseConfiguration) -> None:
|
def __init__(self, database_config: DatabaseConfiguration) -> None:
|
||||||
self._database_config = database_config
|
self._database_config = database_config
|
||||||
self._connection_pool: Optional[aiomysql.Pool] = None
|
self._connection_pool: Optional[aiomysql.Pool] = None
|
||||||
@ -85,7 +90,6 @@ class DatabaseService:
|
|||||||
return
|
return
|
||||||
return self._map_db_result_to_user(result)
|
return self._map_db_result_to_user(result)
|
||||||
|
|
||||||
|
|
||||||
async def get_user_by_id(self, user_id: int) -> Optional[User]:
|
async def get_user_by_id(self, user_id: int) -> Optional[User]:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
@ -110,7 +114,7 @@ class DatabaseService:
|
|||||||
try:
|
try:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO users (user_name, user_mail, user_password) "
|
"INSERT INTO users (user_name, user_mail, user_password) "
|
||||||
"VALUES (%s, %s, %s)", (user_name, user_mail.lower(), password_hash)
|
"VALUES (%s, %s, %s)", (user_name, user_mail.lower(), password_hash)
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
@ -123,19 +127,19 @@ class DatabaseService:
|
|||||||
raise DuplicationError
|
raise DuplicationError
|
||||||
|
|
||||||
return await self.get_user_by_name(user_name)
|
return await self.get_user_by_name(user_name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def update_user(self, user: User) -> User:
|
async def update_user(self, user: User) -> User:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"UPDATE users SET user_name=%s, user_mail=%s, user_password=%s, user_first_name=%s, user_last_name=%s, user_birth_date=%s, "
|
"UPDATE users SET user_name=%s, user_mail=%s, user_password=%s, user_first_name=%s, "
|
||||||
"is_active=%s, is_team_member=%s, is_admin=%s WHERE (user_id=%s)", (user.user_name, user.user_mail.lower(), user.user_password,
|
"user_last_name=%s, user_birth_date=%s, is_active=%s, is_team_member=%s, is_admin=%s "
|
||||||
user.user_first_name, user.user_last_name, user.user_birth_day,
|
"WHERE (user_id=%s)",
|
||||||
user.is_active, user.is_team_member, user.is_admin,
|
(user.user_name, user.user_mail.lower(), user.user_password,
|
||||||
user.user_id)
|
user.user_first_name, user.user_last_name, user.user_birth_day,
|
||||||
|
user.is_active, user.is_team_member, user.is_admin,
|
||||||
|
user.user_id)
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
@ -155,7 +159,8 @@ class DatabaseService:
|
|||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO transactions (user_id, value, is_debit, transaction_date, transaction_reference) "
|
"INSERT INTO transactions (user_id, value, is_debit, transaction_date, transaction_reference) "
|
||||||
"VALUES (%s, %s, %s, %s, %s)",
|
"VALUES (%s, %s, %s, %s, %s)",
|
||||||
(transaction.user_id, transaction.value, transaction.is_debit, transaction.transaction_date, transaction.reference)
|
(transaction.user_id, transaction.value, transaction.is_debit, transaction.transaction_date,
|
||||||
|
transaction.reference)
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
@ -189,14 +194,13 @@ class DatabaseService:
|
|||||||
for transaction_raw in result:
|
for transaction_raw in result:
|
||||||
transactions.append(Transaction(
|
transactions.append(Transaction(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
value=int(transaction_raw[2]),
|
value=Decimal(transaction_raw[2]),
|
||||||
is_debit=bool(transaction_raw[3]),
|
is_debit=bool(transaction_raw[3]),
|
||||||
transaction_date=transaction_raw[4],
|
transaction_date=transaction_raw[4],
|
||||||
reference=transaction_raw[5]
|
reference=transaction_raw[5]
|
||||||
))
|
))
|
||||||
return transactions
|
return transactions
|
||||||
|
|
||||||
|
|
||||||
async def add_news(self, news: News) -> None:
|
async def add_news(self, news: News) -> None:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
@ -215,13 +219,15 @@ class DatabaseService:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error adding Transaction: {e}")
|
logger.warning(f"Error adding Transaction: {e}")
|
||||||
|
|
||||||
|
|
||||||
async def get_news(self, dt_start: date, dt_end: date) -> list[News]:
|
async def get_news(self, dt_start: date, dt_end: date) -> list[News]:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
results = []
|
results = []
|
||||||
try:
|
try:
|
||||||
await cursor.execute("SELECT * FROM news INNER JOIN users ON news.news_author = users.user_id WHERE news_date BETWEEN %s AND %s;", (dt_start, dt_end))
|
await cursor.execute(
|
||||||
|
"SELECT * FROM news INNER JOIN users ON news.news_author = users.user_id WHERE news_date"
|
||||||
|
" BETWEEN %s AND %s;",
|
||||||
|
(dt_start, dt_end))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -315,12 +321,13 @@ class DatabaseService:
|
|||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
async def get_ticket_for_user(self, user_id: int) -> Optional[Ticket]:
|
async def get_ticket_for_user(self, user_id: int) -> Optional[Ticket]:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("SELECT * FROM tickets INNER JOIN users ON tickets.user = users.user_id WHERE user_id=%s;", (user_id, ))
|
await cursor.execute(
|
||||||
|
"SELECT * FROM tickets INNER JOIN users ON tickets.user = users.user_id WHERE user_id=%s;",
|
||||||
|
(user_id,))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -347,7 +354,8 @@ class DatabaseService:
|
|||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("INSERT INTO tickets (ticket_category, user) VALUES (%s, %s)", (category, user_id))
|
await cursor.execute("INSERT INTO tickets (ticket_category, user) VALUES (%s, %s)",
|
||||||
|
(category, user_id))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -360,12 +368,12 @@ class DatabaseService:
|
|||||||
|
|
||||||
return await self.get_ticket_for_user(user_id)
|
return await self.get_ticket_for_user(user_id)
|
||||||
|
|
||||||
|
|
||||||
async def change_ticket_owner(self, ticket_id: int, new_owner_id: int) -> bool:
|
async def change_ticket_owner(self, ticket_id: int, new_owner_id: int) -> bool:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("UPDATE tickets SET user = %s WHERE ticket_id = %s;", (new_owner_id, ticket_id))
|
await cursor.execute("UPDATE tickets SET user = %s WHERE ticket_id = %s;",
|
||||||
|
(new_owner_id, ticket_id))
|
||||||
affected_rows = cursor.rowcount
|
affected_rows = cursor.rowcount
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
@ -382,7 +390,7 @@ class DatabaseService:
|
|||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("DELETE FROM tickets WHERE ticket_id = %s;", (ticket_id, ))
|
await cursor.execute("DELETE FROM tickets WHERE ticket_id = %s;", (ticket_id,))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -401,7 +409,8 @@ class DatabaseService:
|
|||||||
try:
|
try:
|
||||||
await cursor.execute("TRUNCATE seats;")
|
await cursor.execute("TRUNCATE seats;")
|
||||||
for seat in seats:
|
for seat in seats:
|
||||||
await cursor.execute("INSERT INTO seats (seat_id, seat_category) VALUES (%s, %s);", (seat[0], seat[1]))
|
await cursor.execute("INSERT INTO seats (seat_id, seat_category) VALUES (%s, %s);",
|
||||||
|
(seat[0], seat[1]))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -417,7 +426,8 @@ class DatabaseService:
|
|||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
results = []
|
results = []
|
||||||
try:
|
try:
|
||||||
await cursor.execute("SELECT seats.*, users.* FROM seats LEFT JOIN users ON seats.user = users.user_id;")
|
await cursor.execute(
|
||||||
|
"SELECT seats.*, users.* FROM seats LEFT JOIN users ON seats.user = users.user_id;")
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -475,7 +485,7 @@ class DatabaseService:
|
|||||||
item_id=menu_item_raw[0],
|
item_id=menu_item_raw[0],
|
||||||
name=menu_item_raw[1],
|
name=menu_item_raw[1],
|
||||||
additional_info=menu_item_raw[2],
|
additional_info=menu_item_raw[2],
|
||||||
price=menu_item_raw[3],
|
price=Decimal(menu_item_raw[3]),
|
||||||
category=CateringMenuItemCategory(menu_item_raw[4]),
|
category=CateringMenuItemCategory(menu_item_raw[4]),
|
||||||
is_disabled=bool(menu_item_raw[5])
|
is_disabled=bool(menu_item_raw[5])
|
||||||
))
|
))
|
||||||
@ -486,7 +496,8 @@ class DatabaseService:
|
|||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("SELECT * FROM catering_menu_items WHERE catering_menu_item_id = %s;", (menu_item_id, ))
|
await cursor.execute("SELECT * FROM catering_menu_items WHERE catering_menu_item_id = %s;",
|
||||||
|
(menu_item_id,))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -501,20 +512,22 @@ class DatabaseService:
|
|||||||
if raw_data is None:
|
if raw_data is None:
|
||||||
return
|
return
|
||||||
return CateringMenuItem(
|
return CateringMenuItem(
|
||||||
item_id=raw_data[0],
|
item_id=raw_data[0],
|
||||||
name=raw_data[1],
|
name=raw_data[1],
|
||||||
additional_info=raw_data[2],
|
additional_info=raw_data[2],
|
||||||
price=raw_data[3],
|
price=Decimal(raw_data[3]),
|
||||||
category=CateringMenuItemCategory(raw_data[4]),
|
category=CateringMenuItemCategory(raw_data[4]),
|
||||||
is_disabled=bool(raw_data[5])
|
is_disabled=bool(raw_data[5])
|
||||||
)
|
)
|
||||||
|
|
||||||
async def add_menu_item(self, name: str, info: str, price: int, category: CateringMenuItemCategory, is_disabled: bool = False) -> Optional[CateringMenuItem]:
|
async def add_menu_item(self, name: str, info: str, price: Decimal, category: CateringMenuItemCategory,
|
||||||
|
is_disabled: bool = False) -> Optional[CateringMenuItem]:
|
||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO catering_menu_items (name, additional_info, price, category, is_disabled) VALUES (%s, %s, %s, %s, %s);",
|
"INSERT INTO catering_menu_items (name, additional_info, price, category, is_disabled) VALUES "
|
||||||
|
"(%s, %s, %s, %s, %s);",
|
||||||
(name, info, price, category.value, is_disabled)
|
(name, info, price, category.value, is_disabled)
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
@ -540,7 +553,8 @@ class DatabaseService:
|
|||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("DELETE FROM catering_menu_items WHERE catering_menu_item_id = %s;", (menu_item_id,))
|
await cursor.execute("DELETE FROM catering_menu_items WHERE catering_menu_item_id = %s;",
|
||||||
|
(menu_item_id,))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
pool_init_result = await self.init_db_pool()
|
pool_init_result = await self.init_db_pool()
|
||||||
@ -557,8 +571,10 @@ class DatabaseService:
|
|||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"UPDATE catering_menu_items SET name = %s, additional_info = %s, price = %s, category = %s, is_disabled = %s WHERE catering_menu_item_id = %s;",
|
"UPDATE catering_menu_items SET name = %s, additional_info = %s, price = %s, category = %s, "
|
||||||
(updated_item.name, updated_item.additional_info, updated_item.price, updated_item.category.value, updated_item.is_disabled, updated_item.item_id)
|
"is_disabled = %s WHERE catering_menu_item_id = %s;",
|
||||||
|
(updated_item.name, updated_item.additional_info, updated_item.price,
|
||||||
|
updated_item.category.value, updated_item.is_disabled, updated_item.item_id)
|
||||||
)
|
)
|
||||||
affected_rows = cursor.rowcount
|
affected_rows = cursor.rowcount
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
@ -584,7 +600,8 @@ class DatabaseService:
|
|||||||
order_id = cursor.lastrowid
|
order_id = cursor.lastrowid
|
||||||
for menu_item, quantity in menu_items.items():
|
for menu_item, quantity in menu_items.items():
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO order_catering_menu_item (order_id, catering_menu_item_id, quantity) VALUES (%s, %s, %s);",
|
"INSERT INTO order_catering_menu_item (order_id, catering_menu_item_id, quantity) VALUES "
|
||||||
|
"(%s, %s, %s);",
|
||||||
(order_id, menu_item.item_id, quantity)
|
(order_id, menu_item.item_id, quantity)
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
@ -673,7 +690,7 @@ class DatabaseService:
|
|||||||
"SELECT * FROM order_catering_menu_item "
|
"SELECT * FROM order_catering_menu_item "
|
||||||
"LEFT JOIN catering_menu_items ON order_catering_menu_item.catering_menu_item_id = catering_menu_items.catering_menu_item_id "
|
"LEFT JOIN catering_menu_items ON order_catering_menu_item.catering_menu_item_id = catering_menu_items.catering_menu_item_id "
|
||||||
"WHERE order_id = %s;",
|
"WHERE order_id = %s;",
|
||||||
(order_id, )
|
(order_id,)
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
except aiomysql.InterfaceError:
|
except aiomysql.InterfaceError:
|
||||||
@ -690,7 +707,7 @@ class DatabaseService:
|
|||||||
item_id=order_catering_menu_item_raw[1],
|
item_id=order_catering_menu_item_raw[1],
|
||||||
name=order_catering_menu_item_raw[4],
|
name=order_catering_menu_item_raw[4],
|
||||||
additional_info=order_catering_menu_item_raw[5],
|
additional_info=order_catering_menu_item_raw[5],
|
||||||
price=order_catering_menu_item_raw[6],
|
price=Decimal(order_catering_menu_item_raw[6]),
|
||||||
category=CateringMenuItemCategory(order_catering_menu_item_raw[7]),
|
category=CateringMenuItemCategory(order_catering_menu_item_raw[7]),
|
||||||
is_disabled=bool(order_catering_menu_item_raw[8])
|
is_disabled=bool(order_catering_menu_item_raw[8])
|
||||||
)] = order_catering_menu_item_raw[2]
|
)] = order_catering_menu_item_raw[2]
|
||||||
@ -718,7 +735,7 @@ class DatabaseService:
|
|||||||
async with self._connection_pool.acquire() as conn:
|
async with self._connection_pool.acquire() as conn:
|
||||||
async with conn.cursor(aiomysql.Cursor) as cursor:
|
async with conn.cursor(aiomysql.Cursor) as cursor:
|
||||||
try:
|
try:
|
||||||
await cursor.execute("SELECT (picture) FROM user_profile_picture WHERE user_id = %s", (user_id, ))
|
await cursor.execute("SELECT (picture) FROM user_profile_picture WHERE user_id = %s", (user_id,))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
r = await cursor.fetchone()
|
r = await cursor.fetchone()
|
||||||
if r is None:
|
if r is None:
|
||||||
|
|||||||
@ -8,15 +8,19 @@ from src.ez_lan_manager.types.Ticket import Ticket
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__.split(".")[-1])
|
logger = logging.getLogger(__name__.split(".")[-1])
|
||||||
|
|
||||||
|
|
||||||
class TicketNotAvailableError(Exception):
|
class TicketNotAvailableError(Exception):
|
||||||
def __init__(self, category: str):
|
def __init__(self, category: str):
|
||||||
self.category = category
|
self.category = category
|
||||||
|
|
||||||
|
|
||||||
class UserAlreadyHasTicketError(Exception):
|
class UserAlreadyHasTicketError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TicketingService:
|
class TicketingService:
|
||||||
def __init__(self, ticket_infos: tuple[TicketInfo, ...], db_service: DatabaseService, accounting_service: AccountingService) -> None:
|
def __init__(self, ticket_infos: tuple[TicketInfo, ...], db_service: DatabaseService,
|
||||||
|
accounting_service: AccountingService) -> None:
|
||||||
self._ticket_infos = ticket_infos
|
self._ticket_infos = ticket_infos
|
||||||
self._db_service = db_service
|
self._db_service = db_service
|
||||||
self._accounting_service = accounting_service
|
self._accounting_service = accounting_service
|
||||||
@ -75,7 +79,8 @@ class TicketingService:
|
|||||||
|
|
||||||
ticket_info = self.get_ticket_info_by_category(user_ticket.category)
|
ticket_info = self.get_ticket_info_by_category(user_ticket.category)
|
||||||
if await self._db_service.delete_ticket(user_ticket.ticket_id):
|
if await self._db_service.delete_ticket(user_ticket.ticket_id):
|
||||||
await self._accounting_service.add_balance(user_id, ticket_info.price, f"TICKET REFUND {user_ticket.ticket_id}")
|
await self._accounting_service.add_balance(user_id, ticket_info.price,
|
||||||
|
f"TICKET REFUND {user_ticket.ticket_id}")
|
||||||
logger.debug(f"User {user_id} refunded ticket {user_ticket.ticket_id}")
|
logger.debug(f"User {user_id} refunded ticket {user_ticket.ticket_id}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from decimal import Decimal
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Self
|
from typing import Self
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ class CateringMenuItemCategory(StrEnum):
|
|||||||
class CateringMenuItem:
|
class CateringMenuItem:
|
||||||
item_id: int
|
item_id: int
|
||||||
name: str
|
name: str
|
||||||
price: int
|
price: Decimal
|
||||||
category: CateringMenuItemCategory
|
category: CateringMenuItemCategory
|
||||||
additional_info: str = str()
|
additional_info: str = str()
|
||||||
is_disabled: bool = False
|
is_disabled: bool = False
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Optional, Iterable, Self
|
from typing import Optional, Iterable, Self
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ class CateringOrderStatus(StrEnum):
|
|||||||
COMPLETED = "COMPLETED"
|
COMPLETED = "COMPLETED"
|
||||||
CANCELED = "CANCELED"
|
CANCELED = "CANCELED"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class CateringOrder:
|
class CateringOrder:
|
||||||
order_id: int
|
order_id: int
|
||||||
@ -27,8 +29,8 @@ class CateringOrder:
|
|||||||
is_delivery: bool = True
|
is_delivery: bool = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def price(self) -> int:
|
def price(self) -> Decimal:
|
||||||
total = 0
|
total = Decimal("0")
|
||||||
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
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
class NoSuchCategoryError(Exception):
|
class NoSuchCategoryError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class DatabaseConfiguration:
|
class DatabaseConfiguration:
|
||||||
db_user: str
|
db_user: str
|
||||||
@ -14,15 +16,17 @@ class DatabaseConfiguration:
|
|||||||
db_port: int
|
db_port: int
|
||||||
db_name: str
|
db_name: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class TicketInfo:
|
class TicketInfo:
|
||||||
category: str
|
category: str
|
||||||
total_tickets: int
|
total_tickets: int
|
||||||
price: int
|
price: Decimal
|
||||||
description: str
|
description: str
|
||||||
additional_info: str
|
additional_info: str
|
||||||
is_default: bool
|
is_default: bool
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class MailingServiceConfiguration:
|
class MailingServiceConfiguration:
|
||||||
smtp_server: str
|
smtp_server: str
|
||||||
@ -31,6 +35,7 @@ class MailingServiceConfiguration:
|
|||||||
username: str
|
username: str
|
||||||
password: str
|
password: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class LanInfo:
|
class LanInfo:
|
||||||
name: str
|
name: str
|
||||||
@ -39,6 +44,7 @@ class LanInfo:
|
|||||||
date_till: datetime
|
date_till: datetime
|
||||||
organizer_mail: str
|
organizer_mail: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class SeatingConfiguration:
|
class SeatingConfiguration:
|
||||||
seats: dict[str, str]
|
seats: dict[str, str]
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Transaction:
|
class Transaction:
|
||||||
user_id: int
|
user_id: int
|
||||||
value: int
|
value: Decimal
|
||||||
is_debit: bool
|
is_debit: bool
|
||||||
reference: str
|
reference: str
|
||||||
transaction_date: datetime
|
transaction_date: datetime
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from unittest.mock import MagicMock, AsyncMock
|
from unittest.mock import MagicMock, AsyncMock
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from src.ez_lan_manager.services.AccountingService import AccountingService, InsufficientFundsError
|
from src.ez_lan_manager.services.AccountingService import AccountingService, InsufficientFundsError
|
||||||
from src.ez_lan_manager.types.Transaction import Transaction
|
from src.ez_lan_manager.types.Transaction import Transaction
|
||||||
@ -12,7 +13,6 @@ class AccountingServiceTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
self.mock_database_service.add_transaction = AsyncMock()
|
self.mock_database_service.add_transaction = AsyncMock()
|
||||||
self.accounting_service = AccountingService(self.mock_database_service)
|
self.accounting_service = AccountingService(self.mock_database_service)
|
||||||
|
|
||||||
|
|
||||||
def test_importing_unit_under_test_works(self) -> None:
|
def test_importing_unit_under_test_works(self) -> None:
|
||||||
"""
|
"""
|
||||||
This test asserts that the object produced in setUp is AccountingService object,
|
This test asserts that the object produced in setUp is AccountingService object,
|
||||||
@ -21,59 +21,59 @@ class AccountingServiceTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
self.assertIsInstance(self.accounting_service, AccountingService)
|
self.assertIsInstance(self.accounting_service, AccountingService)
|
||||||
|
|
||||||
def test_making_string_from_euro_value_works_correctly(self) -> None:
|
def test_making_string_from_euro_value_works_correctly(self) -> None:
|
||||||
test_value = 13466
|
test_value = Decimal("134.66")
|
||||||
expected_result = "134.66 €"
|
expected_result = "134.66 €"
|
||||||
self.assertEqual(expected_result, AccountingService.make_euro_string_from_int(test_value))
|
self.assertEqual(expected_result, AccountingService.make_euro_string_from_decimal(test_value))
|
||||||
|
|
||||||
def test_making_euro_string_from_negative_value_works_correctly(self) -> None:
|
def test_making_euro_string_from_negative_value_works_correctly(self) -> None:
|
||||||
test_value = -99741
|
test_value = Decimal("-997.41")
|
||||||
expected_result = "-997.41 €"
|
expected_result = "-997.41 €"
|
||||||
self.assertEqual(expected_result, AccountingService.make_euro_string_from_int(test_value))
|
self.assertEqual(expected_result, AccountingService.make_euro_string_from_decimal(test_value))
|
||||||
|
|
||||||
def test_making_euro_string_from_less_than_ten_cents_works_correctly(self) -> None:
|
def test_making_euro_string_from_less_than_ten_cents_works_correctly(self) -> None:
|
||||||
test_value = 4
|
test_value = Decimal("0.04")
|
||||||
expected_result = "0.04 €"
|
expected_result = "0.04 €"
|
||||||
self.assertEqual(expected_result, AccountingService.make_euro_string_from_int(test_value))
|
self.assertEqual(expected_result, AccountingService.make_euro_string_from_decimal(test_value))
|
||||||
|
|
||||||
async def test_get_balance_correctly_adds_up_transactions(self) -> None:
|
async def test_get_balance_correctly_adds_up_transactions(self) -> None:
|
||||||
self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[
|
self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=0,
|
user_id=0,
|
||||||
value=5,
|
value=Decimal("0.05"),
|
||||||
is_debit=True,
|
is_debit=True,
|
||||||
reference="",
|
reference="",
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
),
|
),
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=0,
|
user_id=0,
|
||||||
value=99,
|
value=Decimal("0.99"),
|
||||||
is_debit=False,
|
is_debit=False,
|
||||||
reference="",
|
reference="",
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
),
|
),
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=0,
|
user_id=0,
|
||||||
value=101,
|
value=Decimal("1.01"),
|
||||||
is_debit=False,
|
is_debit=False,
|
||||||
reference="",
|
reference="",
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
),
|
),
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=0,
|
user_id=0,
|
||||||
value=77,
|
value=Decimal("0.77"),
|
||||||
is_debit=True,
|
is_debit=True,
|
||||||
reference="",
|
reference="",
|
||||||
transaction_date=datetime.now()
|
transaction_date=datetime.now()
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
expected_result = 118
|
expected_result = Decimal("1.18")
|
||||||
actual_result = await self.accounting_service.get_balance(0)
|
actual_result = await self.accounting_service.get_balance(0)
|
||||||
|
|
||||||
self.assertEqual(expected_result, actual_result)
|
self.assertEqual(expected_result, actual_result)
|
||||||
|
|
||||||
async def test_trying_to_remove_more_than_is_on_account_balance_raises_exception(self) -> None:
|
async def test_trying_to_remove_more_than_is_on_account_balance_raises_exception(self) -> None:
|
||||||
user_balance = 100
|
user_balance = Decimal("1.00")
|
||||||
balance_to_remove = 101
|
balance_to_remove = Decimal("1.01")
|
||||||
self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[
|
self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[
|
||||||
Transaction(
|
Transaction(
|
||||||
user_id=0,
|
user_id=0,
|
||||||
@ -88,8 +88,8 @@ class AccountingServiceTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
await self.accounting_service.remove_balance(0, balance_to_remove, "TestRef")
|
await self.accounting_service.remove_balance(0, balance_to_remove, "TestRef")
|
||||||
|
|
||||||
async def test_trying_to_remove_less_than_is_on_account_balance_spawns_correct_transaction(self) -> None:
|
async def test_trying_to_remove_less_than_is_on_account_balance_spawns_correct_transaction(self) -> None:
|
||||||
user_balance = 101
|
user_balance = Decimal("1.01")
|
||||||
balance_to_remove = 100
|
balance_to_remove = Decimal("1.00")
|
||||||
reference = "Yey, a reference"
|
reference = "Yey, a reference"
|
||||||
|
|
||||||
self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[
|
self.mock_database_service.get_all_transactions_for_user = AsyncMock(return_value=[
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user