import logging from datetime import datetime from src.ez_lan_manager.services.DatabaseService import DatabaseService from src.ez_lan_manager.types.Transaction import Transaction logger = logging.getLogger(__name__.split(".")[-1]) class InsufficientFundsError(Exception): pass class AccountingService: def __init__(self, db_service: DatabaseService) -> None: self._db_service = db_service async def add_balance(self, user_id: int, balance_to_add: int, reference: str) -> int: await self._db_service.add_transaction(Transaction( user_id=user_id, value=balance_to_add, is_debit=False, reference=reference, 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}") return await self.get_balance(user_id) async def remove_balance(self, user_id: int, balance_to_remove: int, reference: str) -> int: current_balance = await self.get_balance(user_id) if (current_balance - balance_to_remove) < 0: raise InsufficientFundsError await self._db_service.add_transaction(Transaction( user_id=user_id, value=balance_to_remove, is_debit=True, reference=reference, 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}") return await self.get_balance(user_id) async def get_balance(self, user_id: int) -> int: balance_buffer = 0 for transaction in await self._db_service.get_all_transactions_for_user(user_id): if transaction.is_debit: balance_buffer -= transaction.value else: balance_buffer += transaction.value return balance_buffer async def get_transaction_history(self, user_id: int) -> list[Transaction]: return await self._db_service.get_all_transactions_for_user(user_id) @staticmethod def make_euro_string_from_int(cent_int: int) -> 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) if as_str[0] == "-": is_negative = True as_str = as_str[1:] 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