Files
ELM/src/elm/pages/MyBalancePage.py
T
2026-05-29 23:17:28 +02:00

243 lines
11 KiB
Python

from __future__ import annotations
import logging
from asyncio import sleep
from datetime import datetime
from decimal import Decimal, ROUND_DOWN
from typing import Optional
from rio import Component, Column, Row, Text, Spacer, page, Rectangle, GuardEvent, Revealer, Image, NumberInput
from rio.event import on_populate
from elm.types import UserSession, Transaction
from elm.services import AccountingService
from elm.components import ElmButton
logger = logging.getLogger(__name__.split(".")[-1])
class TransactionRow(Component):
transaction_time: datetime
transaction_title: str
transaction_amount: Decimal
is_debit: bool
def build(self) -> Component:
color = self.session.theme.danger_color if self.is_debit else self.session.theme.success_color
return Rectangle(
content=Row(
Text(
f"{self.transaction_time.strftime('%d.%m.%y')} /",
justify="left",
font_size=0.8,
margin_left=0.5,
fill=color
),
Text(
self.transaction_title,
justify="left",
font_size=0.8,
margin_left=0.5,
fill=color,
overflow="ellipsize",
grow_x=True
),
Text(
f"{'-' if self.is_debit else '+'}{str(self.transaction_amount.quantize(Decimal('.01'), rounding=ROUND_DOWN))}",
justify="right",
font_size=0.8,
margin_right=0.5,
fill=color
),
margin_bottom=0.5,
margin_top=0.5
),
hover_fill=self.session.theme.background_color,
transition_time=0.2
)
def my_balance_page_guard(event: GuardEvent) -> Optional[str]:
try:
_ = event.session[UserSession].user_name
return None
except KeyError:
return "/"
@page(name="My Balance", url_segment="balance", guard=my_balance_page_guard)
class MyBalancePage(Component):
current_balance: str = "-"
last_20_transactions: list[Transaction] = []
bank_revealer_open: bool = False
paypal_revealer_open: bool = False
payment_qr_image: bytes = bytes()
paypal_charge_amount: float = 0.00
paypal_charge_in_progress: bool = False
@on_populate
async def async_init(self) -> None:
self.current_balance = self.session[AccountingService].make_euro_string_from_decimal(
await self.session[AccountingService].get_balance(self.session[UserSession].user_name)
)
self.last_20_transactions = (await self.session[AccountingService].get_transaction_history(self.session[UserSession].user_name))[:20]
self.payment_qr_image = self.session[AccountingService].make_payment_qr_image(
"Einfach Zocken Gaming Gesellschaft",
"GENODE51BIK",
"DE47517624340019856607",
f"AUFLADUNG - {self.session[UserSession].user_name}")
async def check_if_paypal_process_done(self) -> None:
await sleep(2)
if await self.session[AccountingService].has_user_open_orders(self.session[UserSession].user_name):
self.session.create_task(self.check_if_paypal_process_done())
else:
self.paypal_charge_in_progress = False
self.paypal_charge_amount = 0.00
self.current_balance = self.session[AccountingService].make_euro_string_from_decimal(
await self.session[AccountingService].get_balance(self.session[UserSession].user_name)
)
self.last_20_transactions = (await self.session[AccountingService].get_transaction_history(self.session[UserSession].user_name))[:20]
self.paypal_revealer_open = False
async def pay_with_paypal(self) -> None:
self.paypal_charge_in_progress = True
logger.info("Starting PayPal transaction over %s for user %s", f"{self.paypal_charge_amount}", self.session[UserSession].user_name)
amount = Decimal(self.paypal_charge_amount)
try:
approval_url = await self.session[AccountingService].start_paypal_process(self.session[UserSession].user_name, amount)
except Exception as e:
logger.error(e)
return
self.session.open_url_in_browser(approval_url)
self.session.create_task(self.check_if_paypal_process_done())
async def toggle_bank_revealer(self) -> None:
self.bank_revealer_open = not self.bank_revealer_open
async def toggle_paypal_revealer(self) -> None:
self.paypal_revealer_open = not self.paypal_revealer_open
def build(self) -> Component:
col_row = Column if self.session.is_mobile() else Row
transaction_rows = []
for transaction in sorted(self.last_20_transactions, key=lambda t: t.transaction_date, reverse=True):
transaction_rows.append(
TransactionRow(
transaction_time=transaction.transaction_date,
transaction_title=transaction.title,
transaction_amount=transaction.value,
is_debit=transaction.is_debit
)
)
return col_row(
Column(
Rectangle(
content=Column(
Rectangle(
content=Rectangle(
content=Text("Guthaben", margin=0.5, selectable=False, overflow="wrap"),
fill=self.session.theme.header_box_background_color,
margin=0.4
),
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color,
),
Column(
Text(
text=self.current_balance,
justify="center",
font_size=2,
grow_x=True,
grow_y=True,
margin_top=2,
margin_bottom=1
),
Spacer(),
margin=1,
spacing=1
)
),
fill=self.session.theme.box_color,
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color
),
Rectangle(
content=Column(
Rectangle(
content=Rectangle(
content=Text("Guthaben aufladen", margin=0.5, selectable=False, overflow="wrap"),
fill=self.session.theme.header_box_background_color,
margin=0.4
),
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color,
),
Column(
ElmButton(text="Banküberweißung", style="small" if self.session.is_mobile() else "normal", on_press=self.toggle_bank_revealer),
Revealer(header=None, is_open=self.bank_revealer_open, content=Column(
Text("QR Code", justify="center"),
Image(self.payment_qr_image, min_width=14, min_height=14, margin_bottom=1),
Text("Bankverbindung", justify="center"),
Text("Empfänger: Einfach Zocken Gaming Gesellschaft", justify="left", overflow="wrap", font_size=0.7),
Text("IBAN: DE47517624340019856607", justify="left", overflow="wrap", font_size=0.7),
Text("BIC: GENODE51BIK", justify="left", overflow="wrap", font_size=0.7),
Text(f"Verwendungszweck: AUFLADUNG - {self.session[UserSession].user_name}", justify="left", overflow="wrap", font_size=0.7),
spacing=1
)),
ElmButton(text="Paypal", style="small" if self.session.is_mobile() else "normal", on_press=self.toggle_paypal_revealer),
Revealer(header=None, is_open=self.paypal_revealer_open, content=Column(
NumberInput(label="Summe", decimals=2, value=self.bind().paypal_charge_amount, suffix_text=""),
ElmButton(text="Jetzt aufladen", style="small" if self.session.is_mobile() else "normal", on_press=self.pay_with_paypal, is_loading=self.paypal_charge_in_progress),
spacing=1
)),
margin=1,
spacing=1
)
),
fill=self.session.theme.box_color,
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color
),
Spacer(),
spacing=1
),
Column(
Rectangle(
content=Column(
Rectangle(
content=Rectangle(
content=Text("Letzte Transaktionen", margin=0.5, selectable=False, overflow="wrap"),
fill=self.session.theme.header_box_background_color,
margin=0.4
),
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color,
),
Column(
Rectangle(
content=Row(
Text("Datum / Titel", justify="left", font_size=0.8, margin_left=0.5),
Text("Betrag", justify="right", font_size=0.8, margin_right=0.5),
margin_bottom=0.5,
margin_top=0.5
)
),
*transaction_rows,
spacing=0.5,
margin=1
)
),
fill=self.session.theme.box_color,
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color
),
Spacer(),
spacing=1,
grow_x=True
),
spacing=1,
margin=1,
margin_right=2
)