add AccountingService

This commit is contained in:
David Rodenkirchen 2024-08-19 11:29:00 +02:00
parent 8b87d78d5d
commit 02134f61f5
5 changed files with 135 additions and 6 deletions

View File

@ -3,12 +3,14 @@ from datetime import datetime
from from_root import from_root
from src.ez_lan_manager.services.AccountingService import AccountingService
from src.ez_lan_manager.services.ConfigurationService import ConfigurationService
from src.ez_lan_manager.services.DatabaseService import DatabaseService
from random import randint
from src.ez_lan_manager.services.UserService import UserService
from src.ez_lan_manager.types.Transaction import Transaction
from src.ez_lan_manager.types.User import User
logger = logging.getLogger(__name__.split(".")[-1])
@ -19,7 +21,16 @@ if __name__ == "__main__":
db_config = configuration_service.get_database_configuration()
db_service = DatabaseService(db_config)
user_service = UserService(db_service)
user_service.create_user("Mamfred", "Peter@peterson.com", "MamaHalloDoo")
accounting_service = AccountingService(db_service, user_service)
#user_service.create_user("Mamfred", "Peter@peterson.com", "MamaHalloDoo")
# db_service.add_transaction(Transaction(
# user_id=19,
# value=50,
# is_debit=True,
# reference="Ein teures Bier",
# transaction_date=datetime.now()
# ))
#print(accounting_service.remove_balance(19, 150, "EinsFuffzig"))
# print(db_service.create_user(f"TestUser{randint(0, 9999)}", f"TestMail{randint(0, 9999)}", "pw123"))
# print(db_service.update_user(
# User(user_id=19, user_name='TestUser838', user_mail='TestMail3142', user_password='pw123', user_first_name=None, user_last_name=None,

View File

@ -0,0 +1,72 @@
import logging
from datetime import datetime
from src.ez_lan_manager.services.DatabaseService import DatabaseService
from src.ez_lan_manager.services.UserService import UserService
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, user_service: UserService) -> None:
self._db_service = db_service
self._user_service = user_service
def add_balance(self, user_id: int, balance_to_add: int, reference: str) -> int:
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 self.get_balance(user_id)
def remove_balance(self, user_id: int, balance_to_remove: int, reference: str) -> int:
current_balance = self.get_balance(user_id)
if (current_balance - balance_to_remove) < 0:
raise InsufficientFundsError
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 self.get_balance(user_id)
def get_balance(self, user_id: int) -> int:
balance_buffer = 0
for transaction in 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
@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

View File

@ -6,6 +6,7 @@ import mariadb
from mariadb import Cursor
from src.ez_lan_manager.types.ConfigurationTypes import DatabaseConfiguration
from src.ez_lan_manager.types.Transaction import Transaction
from src.ez_lan_manager.types.User import User
logger = logging.getLogger(__name__.split(".")[-1])
@ -49,8 +50,7 @@ class DatabaseService:
is_team_member=bool(data[8]),
is_admin=bool(data[9]),
created_at=data[10],
last_updated_at=data[11],
balance=int(data[12])
last_updated_at=data[11]
)
def get_user_by_name(self, user_name: str) -> Optional[User]:
@ -96,13 +96,49 @@ class DatabaseService:
try:
cursor.execute(
"UPDATE users SET user_name=?, user_mail=?, user_password=?, user_first_name=?, user_last_name=?, user_birth_date=?, "
"is_active=?, is_team_member=?, is_admin=?, balance=? WHERE (user_id=?)", (user.user_name, user.user_mail.lower(), user.user_password,
"is_active=?, is_team_member=?, is_admin=? WHERE (user_id=?)", (user.user_name, user.user_mail.lower(), user.user_password,
user.user_first_name, user.user_last_name, user.user_birth_day,
user.is_active, user.is_team_member, user.is_admin,
user.balance, user.user_id)
user.user_id)
)
self._connection.commit()
except mariadb.IntegrityError as e:
logger.warning(f"Aborted duplication entry: {e}")
raise DuplicationError
return user
def add_transaction(self, transaction: Transaction) -> Optional[Transaction]:
cursor = self._get_cursor()
try:
cursor.execute(
"INSERT INTO transactions (user_id, value, is_debit, transaction_date, transaction_reference) "
"VALUES (?, ?, ?, ?, ?)",
(transaction.user_id, transaction.value, transaction.is_debit, transaction.transaction_date, transaction.reference)
)
self._connection.commit()
except Exception as e:
logger.warning(f"Error adding Transaction: {e}")
return
return transaction
def get_all_transactions_for_user(self, user_id: int) -> list[Transaction]:
transactions = []
cursor = self._get_cursor()
try:
cursor.execute("SELECT * FROM transactions WHERE user_id=?", (user_id,))
result = cursor.fetchall()
except mariadb.Error as e:
logger.error(f"Error getting all transactions for user: {e}")
return []
for transaction_raw in result:
transactions.append(Transaction(
user_id=user_id,
value=int(transaction_raw[2]),
is_debit=bool(transaction_raw[3]),
transaction_date=transaction_raw[4],
reference=transaction_raw[5]
))
return transactions

View File

@ -0,0 +1,11 @@
from dataclasses import dataclass
from datetime import datetime
@dataclass(frozen=True)
class Transaction:
user_id: int
value: int
is_debit: bool
reference: str
transaction_date: datetime

View File

@ -17,4 +17,3 @@ class User:
is_admin: bool
created_at: datetime
last_updated_at: datetime
balance: int