Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/35 add monetary class in income outcome class #15

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 46 additions & 26 deletions in-ou/budget_manager.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import sqlite3
from datetime import datetime
from money import Monetary, Currency


class BudgetManager:
def __init__(self, db_name='budget.db'):
def __init__(self, currency: Currency, db_name='budget.db'):
self.db_name = db_name
self.budget = []
self.create_table()
self.load_budget_from_file()
self.__entry_types = ('income', 'outcome')
self.__currency = currency

def create_connection(self):
return sqlite3.connect(self.db_name)
Expand All @@ -18,7 +22,7 @@ def create_table(self):
CREATE TABLE IF NOT EXISTS budget (
id INTEGER PRIMARY KEY AUTOINCREMENT,
entry_type TEXT NOT NULL,
amount REAL NOT NULL,
amount BIGINT NOT NULL,
description TEXT,
category TEXT,
date TEXT NOT NULL
Expand Down Expand Up @@ -54,33 +58,36 @@ def load_budget_from_file(self):
} for row in rows]
print("Budżet został załadowany z bazy danych.")

def add_budget_entry(self, entry_type, amount, description, category="brak kategorii"):
if entry_type not in ["income", "outcome"]:
def add_budget_entry(self, entry_type: str, entry: Monetary, description: str, category: str="brak kategorii") -> None:
if entry_type not in self.__entry_types:
print("Blad: Nieprawidłowy rodzaj wpisu. Wybierz 'income' lub 'outcome'.") #Zmienić na I / O, czy zostawić pełne słowa?
return
if not isinstance(amount, (int, float)) or amount <= 0:
print("Blad: Kwota musi być liczbą dodatnią.")
if not isinstance(entry, Monetary):
print("Blad: Wpis jest złego typu danych")
return
if entry.amount < 0:
print("Blad: Kwota musi być liczbą nieujemną.")
return
if len(description) > 255:
print("Blad: Opis jest za długi (maksymalnie 255 znaków).")
return

entry = {
record = {
"type": entry_type,
"amount": amount,
"amount": entry.amount,
"description": description,
"category": category,
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.budget.append(entry)
self.budget.append(record)
self.save_budget_to_file()
print(f"Pomyślnie dodano wpis: {entry_type}, - {amount} PLN, opis: {description}, kategoria: {category}")
print(f"Pomyślnie dodano wpis: {entry_type} - {entry}, opis: {description}, kategoria: {category}")

def add_budget_entry_input(self): #Dodawanie wpisów z inputem, również do usunięcia w przyszłości.
while True:
entry_type = input(
"Wprowadź rodzaj wpisu ('income' dla dochodu lub 'outcome' dla wydatku, lub 'exit' aby zakończyć): ").strip().lower() # To samo co wyżej, może warto zmienić na I/O?
if entry_type in ["income", "outcome"]:
if entry_type in self.__entry_types:
break
elif entry_type == "exit":
print("Zakończono dodawanie wpisu.")
Expand All @@ -106,6 +113,8 @@ def add_budget_entry_input(self): #Dodawanie wpisów z inputem, również do usu
if not category:
category = "Brak kategorii" # domyśla kategoria

amount = Monetary.major_to_minor_unit(amount, self.__currency)
amount = Monetary(amount, self.__currency)
self.add_budget_entry(entry_type, amount, description, category)

def show_budget(self):
Expand All @@ -115,21 +124,24 @@ def show_budget(self):
sorted_budget = sorted(self.budget, key=lambda x: x['date'])
for i, entry in enumerate(sorted_budget, 1):
category = entry.get('category', 'Brak kategorii')
print(f"{i}. {entry['type']}: {entry['amount']} PLN, {entry['description']} "
amount = Monetary(entry['amount'], self.__currency)
print(f"{i}. {entry['type']}: {amount}, {entry['description']} "
f"(Kategoria: {category}, Data: {entry['date']})")
# status konta ( wydatki, przychody, saldo )
def show_budget_summary(self):
if not self.budget:
print("Brak danych do podsumowania.")
return
try:
income = sum(entry['amount'] for entry in self.budget if entry['type'] == 'income')
incomes = sum(entry['amount'] for entry in self.budget if entry['type'] == 'income')
expenses = sum(entry['amount'] for entry in self.budget if entry['type'] == 'outcome')
balance = income - expenses
incomes = Monetary(incomes, self.__currency)
expenses = Monetary(expenses, self.__currency)
balance = incomes - expenses
print("Podsumowanie budżetu:")
print(f" - Dochody: {income:.2f} PLN")
print(f" - Wydatki: {expenses:.2f} PLN")
print(f" - Saldo: {balance:.2f} PLN")
print(f" - Dochody: {incomes}")
print(f" - Wydatki: {expenses}")
print(f" - Saldo: {balance}")
except KeyError as e:
print(f"Blad: brakuje klucza w danych wpisu budzetowego ({e})")
#filtracja TYLKO przychodów zamiast ogólnych wpisów
Expand All @@ -142,7 +154,8 @@ def show_incomes_by_category(self, category):
return
print(f"Lista dochodów w kategorii '{category}':")
for i, entry in enumerate(incomes, 1):
print(f"{i}. Kwota: {entry['amount']} PLN, Opis: {entry['description']}, Data: {entry['date']}")
entry_monetary = Monetary(entry['amount'], self.__currency)
print(f"{i}. Kwota: {entry_monetary}, Opis: {entry['description']}, Data: {entry['date']}")
except KeyError as e:
print(f"Błąd: Brakuje klucza w danych budżetu ({e}).")
except Exception as e:
Expand All @@ -157,7 +170,8 @@ def show_outcomes_by_category(self, category):
return
print(f"Lista wydatków w kategorii '{category}:")
for i, entry in enumerate(outcomes, 1):
print(f"{i}. Kwota: {entry['amount']} PLN, Opis: {entry['description']}, Data: {entry['date']}")
entry_monetary = Monetary(entry['amount'], self.__currency)
print(f"{i}. Kwota: {entry_monetary}, Opis: {entry['description']}, Data: {entry['date']}")
except KeyError as e:
print(f"Błąd: Brakuje klucza w danych budżetu ({e}).")
except Exception as e:
Expand All @@ -172,7 +186,8 @@ def show_incomes(self):
return
print("Lista dochodów: ")
for i, entry in enumerate(incomes, 1):
print(f"{i}. Kwota: {entry['amount']} PLN, Opis: {entry['description']}, Kategoria: "
entry_monetary = Monetary(entry['amount'], self.__currency)
print(f"{i}. Kwota: {entry_monetary}, Opis: {entry['description']}, Kategoria: "
f"{entry.get('category', 'Brak kategorii')}, Data: {entry['date']}")
except KeyError as e:
print(f"Błąd: Brakuje klucza w danych budżetu ({e}). ")
Expand All @@ -187,7 +202,8 @@ def show_outcomes(self):
return
print("Lista wydatków: ")
for i, entry in enumerate(outcomes, 1):
print(f"{i}. Kwota: {entry['amount']} PLN, Opis: {entry['description']}, "
entry_monetary = Monetary(entry['amount'], self.__currency)
print(f"{i}. Kwota: {entry_monetary}, Opis: {entry['description']}, "
f"Kategoria: {entry.get('category', 'Brak kategorii')}, Data: {entry['date']}")
except KeyError as e:
print(f"Błąd: Brakuje klucza w danych budżetu ({e}).")
Expand All @@ -197,7 +213,8 @@ def show_outcomes(self):
def edit_budget_entry(self, index):
try:
entry = self.budget[index - 1]
print(f"Edycja wpisu: {entry['type']}: {entry['amount']} PLN, {entry['description']}")
entry_monetary = Monetary(entry['amount'], self.__currency)
print(f"Edycja wpisu: {entry['type']}: {entry_monetary}, {entry['description']}")

#Tu użytkownik wpisuje nowe dane, Value Error wystarczy czy coś więcej?
new_type = input("Nowy typ (income/outcome): ").strip().lower()
Expand All @@ -207,7 +224,9 @@ def edit_budget_entry(self, index):
try:
new_amount = input("Nowa kwota: ").strip()
if new_amount:
entry["amount"] = float(new_amount)
new_amount = float(new_amount)
new_amount = Monetary.major_to_minor_unit(new_amount, self.__currency)
new_amount = Monetary(new_amount, self.__currency)
except ValueError:
print("Błąd: niepoprawna kwota. Pozostawiono starą wartość.")

Expand All @@ -217,7 +236,7 @@ def edit_budget_entry(self, index):
# Pokazanie zmian przed zapisaniem
print("\nProponowane zmiany:")
print(f" - Typ: {entry['type']}")
print(f" - Kwota: {entry['amount']:.2f} PLN")
print(f" - Kwota: {new_amount}")
print(f" - Opis: {entry['description']}")
print(f" - Kategoria: {entry['category']}")

Expand All @@ -226,7 +245,7 @@ def edit_budget_entry(self, index):
if confirm != "tak":
print("Edycja anulowana.")
return

entry["amount"] = new_amount.amount
# Aktualizacja daty i zapisanie zmian
entry["date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.save_budget_to_file()
Expand All @@ -241,7 +260,8 @@ def delete_budget_entry(self, index):
try:
print(f"Próba usunięcia wpisu o indeksie: {index}")
entry = self.budget.pop(index - 1)
entry_monetary = Monetary(entry['amount'], self.__currency)
self.save_budget_to_file()
print(f"Wpis usunięty: {entry['type']} - {entry['amount']} PLN, {entry['description']}")
print(f"Wpis usunięty: {entry['type']} - {entry_monetary}, {entry['description']}")
except IndexError:
print(f"Nie ma wpisu z podanym indeksem: {index}")
43 changes: 27 additions & 16 deletions in-ou/income-outcome-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,39 @@
import os
from datetime import datetime
from budget_manager import BudgetManager
from money import Monetary, Currency
from currencies import PLN


currency_for_test = PLN
class TestBudgetManager(unittest.TestCase):
def setUp(self):
self.test_db = 'test_budget.db'
self.manager = BudgetManager(db_name=self.test_db)
self.manager = BudgetManager(currency_for_test, db_name=self.test_db)

def tearDown(self):
if os.path.exists(self.test_db):
os.remove(self.test_db)

def test_add_budget_entry(self):
money = Monetary.major_to_minor_unit(100.50, currency_for_test)
self.manager.add_budget_entry(
entry_type='income',
amount=100.50,
entry = Monetary(money, currency_for_test),
description='Test income',
category='Test category'
)
self.manager.load_budget_from_file()
self.assertEqual(len(self.manager.budget), 1)
self.assertEqual(self.manager.budget[0]['type'], 'income')
self.assertEqual(self.manager.budget[0]['amount'], 100.50)
self.assertEqual(self.manager.budget[0]['amount'], 10050)
self.assertEqual(self.manager.budget[0]['description'], 'Test income')
self.assertEqual(self.manager.budget[0]['category'], 'Test category')

def test_delete_budget_entry(self):
money = Monetary.major_to_minor_unit(50, currency_for_test)
self.manager.add_budget_entry(
entry_type='income',
amount=50,
entry = Monetary(money, currency_for_test),
description='To delete',
category='Test'
)
Expand All @@ -40,32 +44,37 @@ def test_delete_budget_entry(self):
self.assertEqual(len(self.manager.budget), 0)

def test_show_budget_summary(self):
money = Monetary.major_to_minor_unit(200, currency_for_test)
self.manager.add_budget_entry(
entry_type='income',
amount=200,
entry = Monetary(money, currency_for_test),
description='Test income',
category='Category1'
)
money = Monetary.major_to_minor_unit(50, currency_for_test)
self.manager.add_budget_entry(
entry_type='outcome',
amount=50,
entry = Monetary(money, currency_for_test),
description='Test outcome',
category='Category2'
)
self.manager.load_budget_from_file()

income = sum(entry['amount'] for entry in self.manager.budget if entry['type'] == 'income')
outcome = sum(entry['amount'] for entry in self.manager.budget if entry['type'] == 'outcome')
income = Monetary(income, currency_for_test)
outcome = Monetary(outcome, currency_for_test)
balance = income - outcome

self.assertEqual(income, 200)
self.assertEqual(outcome, 50)
self.assertEqual(balance, 150)
self.assertEqual(income.amount, 20000)
self.assertEqual(outcome.amount, 5000)
self.assertEqual(balance.amount, 15000)

def test_edit_budget_entry(self):
money = Monetary.major_to_minor_unit(100, currency_for_test)
self.manager.add_budget_entry(
entry_type='income',
amount=100,
entry = Monetary(money, currency_for_test),
description='Initial description',
category='Initial category'
)
Expand All @@ -74,11 +83,13 @@ def test_edit_budget_entry(self):
entry_index = 1
new_type = 'outcome'
new_amount = 75.50
new_amount = Monetary.major_to_minor_unit(new_amount, currency_for_test)
new_amount = Monetary(new_amount, currency_for_test)
new_description = 'Updated description'
new_category = 'Updated category'

self.manager.budget[entry_index - 1]['type'] = new_type
self.manager.budget[entry_index - 1]['amount'] = new_amount
self.manager.budget[entry_index - 1]['amount'] = new_amount.amount
self.manager.budget[entry_index - 1]['description'] = new_description
self.manager.budget[entry_index - 1]['category'] = new_category

Expand All @@ -87,14 +98,14 @@ def test_edit_budget_entry(self):

edited_entry = self.manager.budget[0]
self.assertEqual(edited_entry['type'], new_type)
self.assertEqual(edited_entry['amount'], new_amount)
self.assertEqual(edited_entry['amount'], new_amount.amount)
self.assertEqual(edited_entry['description'], new_description)
self.assertEqual(edited_entry['category'], new_category)

def test_show_incomes(self):
self.manager.add_budget_entry(
entry_type='income',
amount=300,
entry=Monetary(300, currency_for_test),
description='Income test',
category='Income category'
)
Expand All @@ -106,7 +117,7 @@ def test_show_incomes(self):
def test_show_outcomes(self):
self.manager.add_budget_entry(
entry_type='outcome',
amount=150,
entry=Monetary(150, currency_for_test),
description='Outcome test',
category='Outcome category'
)
Expand All @@ -117,4 +128,4 @@ def test_show_outcomes(self):


if __name__ == '__main__':
unittest.main()
unittest.main()