Replace float with Decimal for price calculations

Fix Decimal precision issue

Fix Decimal precision issue

Fix Decimal precision issue

Fix old prices for tickets

Fix Decimal precision issue
This commit is contained in:
tcprod
2025-02-03 14:32:16 +01:00
parent 98c2d1570c
commit a419ee8885
24 changed files with 342 additions and 235 deletions
@@ -1,4 +1,5 @@
from typing import Callable
from decimal import Decimal
import rio
from rio import Component, Row, Text, IconButton, TextStyle
@@ -9,7 +10,7 @@ MAX_LEN = 24
class CateringCartItem(Component):
article_name: str
article_price: int
article_price: Decimal
article_id: int
list_id: int
remove_item_cb: Callable
@@ -24,7 +25,7 @@ class CateringCartItem(Component):
def build(self) -> rio.Component:
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(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)),
proportions=(19, 5, 2)
)
@@ -1,3 +1,4 @@
from decimal import Decimal
from typing import Callable
import rio
@@ -7,9 +8,10 @@ from src.ez_lan_manager import AccountingService
MAX_LEN = 24
class CateringSelectionItem(Component):
article_name: str
article_price: int
article_price: Decimal
article_id: int
on_add_callback: Callable
is_sensitive: bool
@@ -33,15 +35,16 @@ class CateringSelectionItem(Component):
return top.strip(), bottom.strip()
def build(self) -> rio.Component:
article_name_top, article_name_bottom = self.split_article_name(self.article_name)
return Card(
content=Column(
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(AccountingService.make_euro_string_from_int(self.article_price), style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
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(AccountingService.make_euro_string_from_decimal(self.article_price),
style=TextStyle(fill=self.session.theme.background_color, font_size=0.9)),
IconButton(
icon="material/add",
min_size=2,
@@ -53,7 +56,10 @@ class CateringSelectionItem(Component):
proportions=(19, 5, 2),
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(
Text(
self.additional_info,
@@ -1,4 +1,5 @@
from datetime import datetime
from decimal import Decimal
from typing import Optional
from rio import Component, Column, NumberInput, ThemeContextSwitcher, TextInput, Row, Button, EventHandler
@@ -18,7 +19,7 @@ class NewTransactionForm(Component):
self.new_transaction_cb,
Transaction(
user_id=self.user.user_id,
value=round(self.input_value * 100),
value=Decimal(str(self.input_value)),
is_debit=True,
reference=self.input_reason,
transaction_date=datetime.now()
@@ -30,7 +31,7 @@ class NewTransactionForm(Component):
self.new_transaction_cb,
Transaction(
user_id=self.user.user_id,
value=round(self.input_value * 100),
value=Decimal(str(self.input_value)),
is_debit=False,
reference=self.input_reason,
transaction_date=datetime.now()
@@ -1,3 +1,4 @@
from decimal import Decimal
from typing import Optional, Callable
from rio import Component, Column, Text, TextStyle, Button, Spacer
@@ -9,23 +10,30 @@ class SeatingPlanInfoBox(Component):
is_booking_blocked: bool
seat_id: Optional[str] = None
seat_occupant: Optional[str] = None
seat_price: int = 0
seat_price: Decimal = Decimal("0")
is_blocked: bool = False
def build(self) -> Component:
if not self.show:
return Spacer()
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:
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(
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"{self.seat_occupant}", margin_bottom=1, style=TextStyle(fill=self.session.theme.neutral_color, font_size=1.4), overflow="wrap", justify="center"),
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"{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
) 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(
Text(
f"Buchen",
@@ -1,4 +1,5 @@
from asyncio import sleep, create_task
from decimal import Decimal
import rio
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:"],
"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
)
@@ -158,7 +159,7 @@ class ShoppingCartAndOrders(Component):
),
Row(
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(
fill=self.session.theme.background_color,
font_size=0.8
@@ -1,5 +1,6 @@
from functools import partial
from typing import Callable, Optional
from decimal import Decimal
import rio
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):
description: str
additional_info: str
price: int
price: Decimal
category: str
pressed_cb: Callable
is_enabled: bool
@@ -67,7 +68,7 @@ class TicketBuyCard(Component):
margin_right=1
),
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(
Text("Kaufen", align_x=0.5, margin=0.4),
margin_right=1,
+19 -13
View File
@@ -1,5 +1,6 @@
from random import choice
from typing import Optional
from decimal import Decimal
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:
return Link(
content=Button(
content=Text(self.label, style=self.STYLE, justify="center"),
shape="rectangle",
style="major",
color="success" if self.enabled else "danger",
grow_x=True,
margin_left=0.6,
margin_right=0.6,
margin_top=0.6
content=Button(
content=Text(self.label, style=self.STYLE, justify="center"),
shape="rectangle",
style="major",
color="success" if self.enabled else "danger",
grow_x=True,
margin_left=0.6,
margin_right=0.6,
margin_top=0.6
),
target_url=self.target_url,
align_y=0.5,
grow_y=False
)
class UserInfoBox(Component):
status_change_cb: EventHandler = None
TEXT_STYLE = TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9)
user: Optional[User] = None
user_balance: Optional[int] = 0
user_balance: Optional[Decimal] = Decimal("0")
user_ticket: Optional[Ticket] = None
user_seat: Optional[Seat] = None
@@ -80,8 +82,10 @@ class UserInfoBox(Component):
return Spacer()
return Rectangle(
content=Column(
Text(f"{self.get_greeting()},", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9), justify="center"),
Text(f"{self.user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2), justify="center"),
Text(f"{self.get_greeting()},", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9),
justify="center"),
Text(f"{self.user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2),
justify="center"),
Row(
StatusButton(label="TICKET", target_url="./buy_ticket",
enabled=self.user_ticket is not None),
@@ -91,7 +95,9 @@ class UserInfoBox(Component):
grow_y=False
),
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(
content=Text("Ausloggen", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.6)),
shape="rectangle",