refactor ticket info config and service
This commit is contained in:
parent
eb7d94d46c
commit
5ed1230fde
@ -1,9 +1,6 @@
|
||||
[lan]
|
||||
name="EZ LAN"
|
||||
iteration="0.5"
|
||||
default_category="NORMAL"
|
||||
tickets={ "LUXUS" = 40, "NORMAL" = 10 }
|
||||
prices={ "LUXUS" = 3000, "NORMAL" = 2500 } # Eurocent
|
||||
date_from="2024-10-30 15:00:00"
|
||||
date_till="2024-11-01 12:00:00"
|
||||
organizer_mail="tech@example.com"
|
||||
@ -25,4 +22,18 @@
|
||||
[seating]
|
||||
base_svg_path=""
|
||||
|
||||
dev_mode_active=false # Supresses E-Mail sending
|
||||
[tickets]
|
||||
[tickets."NORMAL"]
|
||||
total_tickets=30
|
||||
price=2500 # Eurocent
|
||||
description="Normales Ticket"
|
||||
is_default=true
|
||||
|
||||
[tickets."LUXUS"]
|
||||
total_tickets=10
|
||||
price=4000 # Eurocent
|
||||
description="Luxus Ticket"
|
||||
is_default=false
|
||||
|
||||
[misc]
|
||||
dev_mode_active=true # Supresses E-Mail sending
|
||||
|
||||
@ -23,7 +23,7 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe
|
||||
accounting_service = AccountingService(db_service)
|
||||
news_service = NewsService(db_service)
|
||||
mailing_service = MailingService(configuration_service)
|
||||
ticketing_service = TicketingService(configuration_service.get_lan_info(), db_service, accounting_service)
|
||||
ticketing_service = TicketingService(configuration_service.get_ticket_info(), db_service, accounting_service)
|
||||
seating_service = SeatingService(configuration_service.get_seating_configuration(), configuration_service.get_lan_info(), db_service, ticketing_service)
|
||||
catering_service = CateringService(db_service, accounting_service, user_service)
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import tomllib
|
||||
|
||||
from from_root import from_root
|
||||
|
||||
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration, MailingServiceConfiguration, LanInfo, TicketInfo, SeatingConfiguration
|
||||
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration, MailingServiceConfiguration, LanInfo, SeatingConfiguration, TicketInfo
|
||||
|
||||
logger = logging.getLogger(__name__.split(".")[-1])
|
||||
|
||||
@ -58,16 +58,9 @@ class ConfigurationService:
|
||||
def get_lan_info(self) -> LanInfo:
|
||||
try:
|
||||
lan_info = self._config["lan"]
|
||||
ticket_info = TicketInfo(
|
||||
default_category=lan_info["default_category"],
|
||||
categories=list(lan_info["tickets"].keys()),
|
||||
_prices=lan_info["prices"],
|
||||
_available_tickets=lan_info["tickets"]
|
||||
)
|
||||
return LanInfo(
|
||||
name=lan_info["name"],
|
||||
iteration=lan_info["iteration"],
|
||||
ticket_info=ticket_info,
|
||||
date_from=datetime.strptime(lan_info["date_from"], "%Y-%m-%d %H:%M:%S"),
|
||||
date_till=datetime.strptime(lan_info["date_till"], "%Y-%m-%d %H:%M:%S"),
|
||||
organizer_mail=lan_info["organizer_mail"]
|
||||
@ -90,10 +83,24 @@ class ConfigurationService:
|
||||
logger.fatal("Error loading seating configuration, exiting...")
|
||||
sys.exit(1)
|
||||
|
||||
def get_ticket_info(self) -> tuple[TicketInfo, ...]:
|
||||
try:
|
||||
return tuple([TicketInfo(
|
||||
category=value,
|
||||
total_tickets=self._config["tickets"][value]["total_tickets"],
|
||||
price=self._config["tickets"][value]["price"],
|
||||
description=self._config["tickets"][value]["description"],
|
||||
is_default=self._config["tickets"][value]["is_default"]
|
||||
) for value in self._config["tickets"]])
|
||||
except KeyError as e:
|
||||
logger.debug(e)
|
||||
logger.fatal("Error loading seating configuration, exiting...")
|
||||
sys.exit(1)
|
||||
|
||||
@property
|
||||
def APP_VERSION(self) -> str:
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def DEV_MODE_ACTIVE(self) -> bool:
|
||||
return self._config["dev_mode_active"]
|
||||
return self._config["misc"]["dev_mode_active"]
|
||||
|
||||
@ -3,7 +3,7 @@ from typing import Optional
|
||||
|
||||
from src.ez_lan_manager.services.AccountingService import AccountingService, InsufficientFundsError
|
||||
from src.ez_lan_manager.services.DatabaseService import DatabaseService
|
||||
from src.ez_lan_manager.types.ConfigurationTypes import LanInfo
|
||||
from src.ez_lan_manager.types.ConfigurationTypes import TicketInfo
|
||||
from src.ez_lan_manager.types.Ticket import Ticket
|
||||
|
||||
logger = logging.getLogger(__name__.split(".")[-1])
|
||||
@ -16,37 +16,51 @@ class UserAlreadyHasTicketError(Exception):
|
||||
pass
|
||||
|
||||
class TicketingService:
|
||||
def __init__(self, lan_info: LanInfo, db_service: DatabaseService, accounting_service: AccountingService) -> None:
|
||||
self._lan_info = lan_info
|
||||
def __init__(self, ticket_infos: tuple[TicketInfo, ...], db_service: DatabaseService, accounting_service: AccountingService) -> None:
|
||||
self._ticket_infos = ticket_infos
|
||||
self._db_service = db_service
|
||||
self._accounting_service = accounting_service
|
||||
|
||||
async def get_total_tickets(self) -> int:
|
||||
return sum([self._lan_info.ticket_info.get_available_tickets(c) for c in self._lan_info.ticket_info.categories])
|
||||
def get_ticket_info_by_category(self, category: str) -> Optional[TicketInfo]:
|
||||
return next(filter(lambda t: t.category == category, self._ticket_infos), None)
|
||||
|
||||
def get_total_tickets(self) -> int:
|
||||
return sum([t_i.total_tickets for t_i in self._ticket_infos])
|
||||
|
||||
async def get_available_tickets_for_category(self, category: str) -> int:
|
||||
ticket_info = self.get_ticket_info_by_category(category)
|
||||
if not ticket_info or ticket_info.total_tickets < 1:
|
||||
return 0
|
||||
result = ticket_info.total_tickets
|
||||
|
||||
async def get_available_tickets(self) -> dict[str, int]:
|
||||
result = self._lan_info.ticket_info.total_available_tickets
|
||||
all_tickets = await self._db_service.get_tickets()
|
||||
for ticket in all_tickets:
|
||||
result[ticket.category] -= 1
|
||||
if ticket.category == category:
|
||||
result -= 1
|
||||
|
||||
return result
|
||||
|
||||
async def purchase_ticket(self, user_id: int, category: str) -> Ticket:
|
||||
if category not in self._lan_info.ticket_info.categories or (await self.get_available_tickets())[category] < 1:
|
||||
all_categories = [t_i.category for t_i in self._ticket_infos]
|
||||
if category not in all_categories or (await self.get_available_tickets_for_category(category)) < 1:
|
||||
raise TicketNotAvailableError(category)
|
||||
|
||||
user_balance = await self._accounting_service.get_balance(user_id)
|
||||
if self._lan_info.ticket_info.get_price(category) > user_balance:
|
||||
|
||||
ticket_info = self.get_ticket_info_by_category(category)
|
||||
if not ticket_info:
|
||||
raise TicketNotAvailableError(category)
|
||||
|
||||
if ticket_info.price > user_balance:
|
||||
raise InsufficientFundsError
|
||||
|
||||
if self.get_user_ticket(user_id):
|
||||
if await self.get_user_ticket(user_id):
|
||||
raise UserAlreadyHasTicketError
|
||||
|
||||
if new_ticket := await self._db_service.generate_ticket_for_user(user_id, category):
|
||||
await self._accounting_service.remove_balance(
|
||||
user_id,
|
||||
self._lan_info.ticket_info.get_price(new_ticket.category),
|
||||
ticket_info.price,
|
||||
f"TICKET {new_ticket.ticket_id}"
|
||||
)
|
||||
logger.debug(f"User {user_id} purchased ticket {new_ticket.ticket_id}")
|
||||
@ -59,8 +73,9 @@ class TicketingService:
|
||||
if not user_ticket:
|
||||
return False
|
||||
|
||||
if self._db_service.delete_ticket(user_ticket.ticket_id):
|
||||
await self._accounting_service.add_balance(user_id, self._lan_info.ticket_info.get_price(user_ticket.category), f"TICKET REFUND {user_ticket.ticket_id}")
|
||||
ticket_info = self.get_ticket_info_by_category(user_ticket.category)
|
||||
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}")
|
||||
logger.debug(f"User {user_id} refunded ticket {user_ticket.ticket_id}")
|
||||
return True
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
from copy import copy
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@ -17,26 +16,11 @@ class DatabaseConfiguration:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TicketInfo:
|
||||
default_category: str
|
||||
categories: list[str]
|
||||
_prices: dict[str, int]
|
||||
_available_tickets: dict[str, int]
|
||||
|
||||
def get_price(self, category: str) -> int:
|
||||
try:
|
||||
return self._prices[category]
|
||||
except KeyError:
|
||||
raise NoSuchCategoryError
|
||||
|
||||
def get_available_tickets(self, category: str) -> int:
|
||||
try:
|
||||
return self._available_tickets[category]
|
||||
except KeyError:
|
||||
raise NoSuchCategoryError
|
||||
|
||||
@property
|
||||
def total_available_tickets(self):
|
||||
return copy(self._available_tickets)
|
||||
category: str
|
||||
total_tickets: int
|
||||
price: int
|
||||
description: str
|
||||
is_default: bool
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MailingServiceConfiguration:
|
||||
@ -50,7 +34,6 @@ class MailingServiceConfiguration:
|
||||
class LanInfo:
|
||||
name: str
|
||||
iteration: str
|
||||
ticket_info: TicketInfo
|
||||
date_from: datetime
|
||||
date_till: datetime
|
||||
organizer_mail: str
|
||||
|
||||
Loading…
Reference in New Issue
Block a user