add ticketing service

This commit is contained in:
David Rodenkirchen 2024-08-20 10:57:45 +02:00
parent b1bd1b11b5
commit 96278258ef
5 changed files with 165 additions and 3 deletions

View File

@ -11,6 +11,7 @@ from random import randint
from src.ez_lan_manager.services.MailingService import MailingService
from src.ez_lan_manager.services.NewsService import NewsService
from src.ez_lan_manager.services.TicketingService import TicketingService
from src.ez_lan_manager.services.UserService import UserService
from src.ez_lan_manager.types.News import News
from src.ez_lan_manager.types.Transaction import Transaction
@ -21,13 +22,17 @@ logger = logging.getLogger(__name__.split(".")[-1])
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
configuration_service = ConfigurationService(from_root("config.toml"))
lan_info = configuration_service.get_lan_info()
db_config = configuration_service.get_database_configuration()
db_service = DatabaseService(db_config)
user_service = UserService(db_service)
accounting_service = AccountingService(db_service)
news_service = NewsService(db_service)
mailing_service = MailingService(configuration_service.get_mailing_service_configuration())
#mailing_service.send_email("Hallo von EZ LAN Mananger", "Grüße :)", "davidr.develop@gmail.com")
ticketing_service = TicketingService(lan_info, db_service, accounting_service)
print(ticketing_service.refund_ticket(19))
#print(ticketing_service.get_available_tickets())
#user_service.create_user("Alex", "alex@gmail.com", "MeinPasswort")

View File

@ -8,6 +8,7 @@ from mariadb import Cursor
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration
from src.ez_lan_manager.types.News import News
from src.ez_lan_manager.types.Ticket import Ticket
from src.ez_lan_manager.types.Transaction import Transaction
from src.ez_lan_manager.types.User import User
@ -178,3 +179,75 @@ class DatabaseService:
))
return results
def get_tickets(self) -> list[Ticket]:
results = []
cursor = self._get_cursor()
try:
cursor.execute("SELECT * FROM tickets INNER JOIN users ON tickets.user = users.user_id;", ())
except Exception as e:
logger.warning(f"Error fetching tickets: {e}")
return []
for ticket_raw in cursor.fetchall():
user = self._map_db_result_to_user(ticket_raw[3:])
results.append(Ticket(
ticket_id=ticket_raw[0],
category=ticket_raw[1],
purchase_date=ticket_raw[3],
owner=user
))
return results
def get_ticket_for_user(self, user_id: int) -> Optional[Ticket]:
cursor = self._get_cursor()
try:
cursor.execute("SELECT * FROM tickets INNER JOIN users ON tickets.user = users.user_id WHERE user_id=?;", (user_id, ))
except Exception as e:
logger.warning(f"Error fetching ticket for user: {e}")
return
result = cursor.fetchone()
if not result:
return
user = self._map_db_result_to_user(result[3:])
return Ticket(
ticket_id=result[0],
category=result[1],
purchase_date=result[3],
owner=user
)
def generate_ticket_for_user(self, user_id: int, category: str) -> Optional[Ticket]:
cursor = self._get_cursor()
try:
cursor.execute("INSERT INTO tickets (ticket_category, user) VALUES (?, ?)", (category, user_id))
self._connection.commit()
except Exception as e:
logger.warning(f"Error generating ticket for user: {e}")
return
return self.get_ticket_for_user(user_id)
def change_ticket_owner(self, ticket_id: int, new_owner_id: int) -> bool:
cursor = self._get_cursor()
try:
cursor.execute("UPDATE tickets SET user = ? WHERE ticket_id = ?;", (new_owner_id, ticket_id))
affected_rows = cursor.rowcount
self._connection.commit()
except Exception as e:
logger.warning(f"Error transferring ticket to user: {e}")
return False
return bool(affected_rows)
def delete_ticket(self, ticket_id: int) -> bool:
cursor = self._get_cursor()
try:
cursor.execute("DELETE FROM tickets WHERE ticket_id = ?;", (ticket_id, ))
self._connection.commit()
except Exception as e:
logger.warning(f"Error deleting ticket: {e}")
return False
return True

View File

@ -1,7 +1,73 @@
import logging
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.Ticket import Ticket
logger = logging.getLogger(__name__.split(".")[-1])
class TicketNotAvailableError(Exception):
def __init__(self, category: str):
self.category = category
class UserAlreadyHasTicketError(Exception):
pass
class TicketingService:
def __init__(self) -> None:
pass
def __init__(self, lan_info: LanInfo, db_service: DatabaseService, accounting_service: AccountingService) -> None:
self._lan_info = lan_info
self._db_service = db_service
self._accounting_service = accounting_service
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_available_tickets(self) -> dict[str, int]:
result = self._lan_info.ticket_info.total_available_tickets
all_tickets = self._db_service.get_tickets()
for ticket in all_tickets:
result[ticket.category] -= 1
return result
def purchase_ticket(self, user_id: int, category: str) -> Ticket:
if category not in self._lan_info.ticket_info.categories or self.get_available_tickets()[category] < 1:
raise TicketNotAvailableError(category)
user_balance = self._accounting_service.get_balance(user_id)
if self._lan_info.ticket_info.get_price(category) > user_balance:
raise InsufficientFundsError
if self.get_user_ticket(user_id):
raise UserAlreadyHasTicketError
if new_ticket := self._db_service.generate_ticket_for_user(user_id, category):
self._accounting_service.remove_balance(
user_id,
self._lan_info.ticket_info.get_price(new_ticket.category),
f"TICKET {new_ticket.ticket_id}"
)
logger.debug(f"User {user_id} purchased ticket {new_ticket.ticket_id}")
return new_ticket
raise RuntimeError("An unknown error occurred while purchasing ticket")
def refund_ticket(self, user_id: int) -> bool:
user_ticket = self.get_user_ticket(user_id)
if not user_ticket:
return False
if self._db_service.delete_ticket(user_ticket.ticket_id):
self._accounting_service.add_balance(user_id, self._lan_info.ticket_info.get_price(user_ticket.category), f"TICKET REFUND {user_ticket.ticket_id}")
logger.debug(f"User {user_id} refunded ticket {user_ticket.ticket_id}")
return True
return False
def transfer_ticket(self, ticket_id: int, user_id: int) -> bool:
return self._db_service.change_ticket_owner(ticket_id, user_id)
def get_user_ticket(self, user_id: int) -> Optional[Ticket]:
return self._db_service.get_ticket_for_user(user_id)

View File

@ -1,3 +1,4 @@
from copy import copy
from dataclasses import dataclass
from datetime import datetime
@ -30,6 +31,10 @@ class TicketInfo:
except KeyError:
raise NoSuchCategoryError
@property
def total_available_tickets(self):
return copy(self._available_tickets)
@dataclass(frozen=True)
class MailingServiceConfiguration:
smtp_server: str

View File

@ -0,0 +1,13 @@
from dataclasses import dataclass
from datetime import datetime
from typing import Optional
from src.ez_lan_manager.types.User import User
@dataclass(frozen=True)
class Ticket:
ticket_id: int
category: str
purchase_date: datetime
owner: Optional[User] = None