Gemini did alot of things
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
ADMIN_PASSWORD = "admin123"
|
||||
|
||||
# Use UUIDs or simple string IDs
|
||||
REGISTERED_USERS = {"user_1": "Alice", "user_2": "Bob", "user_3": "Charlie"}
|
||||
REGISTERED_USERS = {"1": "Alice", "2": "Bob", "3": "Charlie"}
|
||||
|
||||
MENU_ITEMS = {
|
||||
"item_1": {"name": "Coffee", "price": 2.50},
|
||||
|
||||
@@ -62,9 +62,18 @@ class Tracker:
|
||||
if user_id not in self.users:
|
||||
return {"status": "error", "message": "User not found"}
|
||||
|
||||
if user_id not in self.debts:
|
||||
self.debts[user_id] = 0.0
|
||||
self.debts[user_id] -= amount
|
||||
self.data_manager.save_debts(self.debts)
|
||||
|
||||
from uuid import uuid4
|
||||
from core.transaction import Transaction
|
||||
|
||||
transaction = Transaction(str(uuid4()), user_id, "adjustment", -amount)
|
||||
self.transactions.append(transaction)
|
||||
self.data_manager.save_transactions(self.transactions)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": f"Reduced debt by {amount}",
|
||||
@@ -84,3 +93,71 @@ class Tracker:
|
||||
|
||||
def get_items(self):
|
||||
return self.items
|
||||
|
||||
def set_user_pin(self, user_id, pin):
|
||||
if user_id not in self.users:
|
||||
return {"status": "error", "message": "User not found"}
|
||||
self.users[user_id].pin = pin
|
||||
self.data_manager.save_users(self.users)
|
||||
return {"status": "success", "message": "PIN updated successfully"}
|
||||
|
||||
def add_user(self, user_id, name):
|
||||
from core.user import User
|
||||
if user_id in self.users:
|
||||
return {"status": "error", "message": "User ID already exists"}
|
||||
self.users[user_id] = User(user_id, name, "4242")
|
||||
self.data_manager.save_users(self.users)
|
||||
return {"status": "success", "message": f"User {name} created successfully"}
|
||||
|
||||
def remove_user(self, user_id):
|
||||
if user_id not in self.users:
|
||||
return {"status": "error", "message": "User not found"}
|
||||
name = self.users[user_id].name
|
||||
del self.users[user_id]
|
||||
if user_id in self.debts:
|
||||
del self.debts[user_id]
|
||||
self.data_manager.save_users(self.users)
|
||||
self.data_manager.save_debts(self.debts)
|
||||
return {"status": "success", "message": f"User {name} removed successfully"}
|
||||
|
||||
def edit_user(self, user_id, name, pin=None):
|
||||
if user_id not in self.users:
|
||||
return {"status": "error", "message": "User not found"}
|
||||
self.users[user_id].name = name
|
||||
if pin is not None:
|
||||
self.users[user_id].pin = pin
|
||||
self.data_manager.save_users(self.users)
|
||||
return {"status": "success", "message": f"User {name} updated successfully"}
|
||||
|
||||
def add_item(self, item_id, name, price):
|
||||
from core.item import Item
|
||||
if item_id in self.items:
|
||||
return {"status": "error", "message": "Item ID already exists"}
|
||||
try:
|
||||
price_val = float(price)
|
||||
except ValueError:
|
||||
return {"status": "error", "message": "Invalid price value"}
|
||||
self.items[item_id] = Item(item_id, name, price_val)
|
||||
self.data_manager.save_items(self.items)
|
||||
return {"status": "success", "message": f"Item {name} created successfully"}
|
||||
|
||||
def remove_item(self, item_id):
|
||||
if item_id not in self.items:
|
||||
return {"status": "error", "message": "Item not found"}
|
||||
name = self.items[item_id].name
|
||||
del self.items[item_id]
|
||||
self.data_manager.save_items(self.items)
|
||||
return {"status": "success", "message": f"Item {name} removed successfully"}
|
||||
|
||||
def edit_item(self, item_id, name, price):
|
||||
if item_id not in self.items:
|
||||
return {"status": "error", "message": "Item not found"}
|
||||
try:
|
||||
price_val = float(price)
|
||||
except ValueError:
|
||||
return {"status": "error", "message": "Invalid price value"}
|
||||
self.items[item_id].name = name
|
||||
self.items[item_id].price = price_val
|
||||
self.data_manager.save_items(self.items)
|
||||
return {"status": "success", "message": f"Item {name} updated successfully"}
|
||||
|
||||
|
||||
+7
-3
@@ -1,14 +1,18 @@
|
||||
class User:
|
||||
def __init__(self, id, name) -> None:
|
||||
def __init__(self, id, name, pin="4242") -> None:
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.debt = 0.0
|
||||
self.pin = pin
|
||||
|
||||
def to_json(self):
|
||||
return {"id": self.id, "name": self.name, "debt": self.debt}
|
||||
return {"id": self.id, "name": self.name, "debt": self.debt, "pin": self.pin}
|
||||
|
||||
@staticmethod
|
||||
def from_json(data):
|
||||
user = User(data["id"], data["name"])
|
||||
pin = data.get("pin")
|
||||
if pin is None:
|
||||
pin = "4242"
|
||||
user = User(data["id"], data["name"], pin)
|
||||
user.debt = data["debt"]
|
||||
return user
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import sys
|
||||
from core.tracker import Tracker
|
||||
from storage.data_manager import DataManager
|
||||
from config import REGISTERED_USERS, MENU_ITEMS
|
||||
from ui.cli import CLI
|
||||
|
||||
|
||||
def init_data(tracker, data_manager):
|
||||
@@ -27,6 +27,20 @@ def main():
|
||||
|
||||
init_data(tracker, dm)
|
||||
|
||||
if "--cli" in sys.argv:
|
||||
from ui.cli import CLI
|
||||
cli = CLI(tracker)
|
||||
cli.run()
|
||||
else:
|
||||
try:
|
||||
from ui.kivy import KivyUI
|
||||
gui = KivyUI(tracker)
|
||||
gui.run()
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
print(f"Kivy GUI konnte nicht geladen werden ({e}). Starte CLI-Modus...")
|
||||
from ui.cli import CLI
|
||||
cli = CLI(tracker)
|
||||
cli.run()
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import unittest
|
||||
from core.tracker import Tracker
|
||||
from storage.data_manager import DataManager
|
||||
from core.user import User
|
||||
from core.item import Item
|
||||
import shutil
|
||||
import os
|
||||
|
||||
|
||||
class TestTracker(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.test_dir = "test_data"
|
||||
self.dm = DataManager(self.test_dir)
|
||||
self.tracker = Tracker(self.dm)
|
||||
|
||||
# Setup dummy user and item
|
||||
self.tracker.users = {"test_user": User("test_user", "Test Alice")}
|
||||
self.tracker.items = {"test_item": Item("test_item", "Test Coffee", 2.50)}
|
||||
self.tracker.debts = {}
|
||||
self.tracker.transactions = []
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.exists(self.test_dir):
|
||||
shutil.rmtree(self.test_dir)
|
||||
|
||||
def test_adjust_debt_new_user(self):
|
||||
# Verify adjust_debt does not raise KeyError on uninitialized user debt
|
||||
res = self.tracker.adjust_debt("test_user", 2.0, "admin123")
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertEqual(self.tracker.get_user_debt("test_user"), -2.0)
|
||||
|
||||
def test_add_purchase(self):
|
||||
res = self.tracker.add_purchase("test_user", "test_item")
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertEqual(self.tracker.get_user_debt("test_user"), 2.50)
|
||||
self.assertEqual(len(self.tracker.transactions), 1)
|
||||
|
||||
def test_default_pin(self):
|
||||
user = User("new_user", "New User")
|
||||
self.assertEqual(user.pin, "4242")
|
||||
|
||||
def test_add_user(self):
|
||||
res = self.tracker.add_user("test_user_2", "Test Bob")
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertEqual(self.tracker.users["test_user_2"].name, "Test Bob")
|
||||
self.assertEqual(self.tracker.users["test_user_2"].pin, "4242")
|
||||
def test_remove_user(self):
|
||||
res = self.tracker.remove_user("test_user")
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertNotIn("test_user", self.tracker.users)
|
||||
self.assertNotIn("test_user", self.tracker.debts)
|
||||
|
||||
def test_edit_user(self):
|
||||
res = self.tracker.edit_user("test_user", "Updated Name", "9999")
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertEqual(self.tracker.users["test_user"].name, "Updated Name")
|
||||
self.assertEqual(self.tracker.users["test_user"].pin, "9999")
|
||||
|
||||
def test_add_item(self):
|
||||
res = self.tracker.add_item("new_item", "Donut", 1.80)
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertEqual(self.tracker.items["new_item"].name, "Donut")
|
||||
self.assertEqual(self.tracker.items["new_item"].price, 1.80)
|
||||
|
||||
def test_remove_item(self):
|
||||
res = self.tracker.remove_item("test_item")
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertNotIn("test_item", self.tracker.items)
|
||||
|
||||
def test_edit_item(self):
|
||||
res = self.tracker.edit_item("test_item", "Premium Coffee", 3.20)
|
||||
self.assertEqual(res["status"], "success")
|
||||
self.assertEqual(self.tracker.items["test_item"].name, "Premium Coffee")
|
||||
self.assertEqual(self.tracker.items["test_item"].price, 3.20)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -235,7 +235,9 @@ class CLI:
|
||||
print("2. Adjust user debt")
|
||||
print("3. Clear user debt")
|
||||
print("4. View transaction history")
|
||||
print("5. Logout")
|
||||
print("5. Manage users")
|
||||
print("6. Manage items")
|
||||
print("7. Logout")
|
||||
print()
|
||||
|
||||
choice = input("Choose option: ").strip()
|
||||
@@ -249,6 +251,10 @@ class CLI:
|
||||
elif choice == "4":
|
||||
self._view_transaction_history()
|
||||
elif choice == "5":
|
||||
self._manage_users()
|
||||
elif choice == "6":
|
||||
self._manage_items()
|
||||
elif choice == "7":
|
||||
break
|
||||
else:
|
||||
self._invalid_choice()
|
||||
@@ -357,9 +363,10 @@ class CLI:
|
||||
else:
|
||||
for t in sorted(transactions, key=lambda x: x.timestamp, reverse=True):
|
||||
user = self.tracker.get_user_by_id(t.user_id)
|
||||
item = self.tracker.get_items()[t.item_id]
|
||||
item = self.tracker.get_items().get(t.item_id)
|
||||
item_name = item.name if item else ("Adjustment" if t.item_id == "adjustment" else "Deleted Item")
|
||||
print(
|
||||
f"{t.timestamp[:10]} | {user.name:.<20} {item.name:.<15} ${t.amount:.2f}"
|
||||
f"{t.timestamp[:10]} | {user.name:.<20} {item_name:.<15} ${t.amount:.2f}"
|
||||
)
|
||||
|
||||
print()
|
||||
@@ -368,3 +375,226 @@ class CLI:
|
||||
def _invalid_choice(self):
|
||||
print("Invalid choice. Please try again.")
|
||||
input("Press Enter to continue...")
|
||||
|
||||
def _manage_users(self):
|
||||
while True:
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("MANAGE USERS")
|
||||
print("=" * 50)
|
||||
print()
|
||||
print("1. Add user")
|
||||
print("2. Edit user")
|
||||
print("3. Remove user")
|
||||
print("4. Back to admin panel")
|
||||
print()
|
||||
choice = input("Choose option: ").strip()
|
||||
if choice == "1":
|
||||
self._cli_add_user()
|
||||
elif choice == "2":
|
||||
self._cli_edit_user()
|
||||
elif choice == "3":
|
||||
self._cli_remove_user()
|
||||
elif choice == "4":
|
||||
break
|
||||
else:
|
||||
self._invalid_choice()
|
||||
|
||||
def _cli_add_user(self):
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("ADD USER")
|
||||
print("=" * 50)
|
||||
print()
|
||||
name = input("Enter new user's name: ").strip()
|
||||
if not name:
|
||||
print("Name cannot be empty!")
|
||||
input("Press Enter to continue...")
|
||||
return
|
||||
import uuid
|
||||
user_id = f"user_{uuid.uuid4().hex[:8]}"
|
||||
res = self.tracker.add_user(user_id, name)
|
||||
print(res["message"])
|
||||
input("Press Enter to continue...")
|
||||
|
||||
def _cli_edit_user(self):
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("EDIT USER")
|
||||
print("=" * 50)
|
||||
print()
|
||||
users = self.tracker.get_all_users()
|
||||
user_list = list(users.items())
|
||||
for i, (user_id, user) in enumerate(user_list, 1):
|
||||
print(f"{i}. {user.name} (PIN: {user.pin})")
|
||||
print(f"{len(user_list) + 1}. Cancel")
|
||||
print()
|
||||
try:
|
||||
choice = int(input("Choose user to edit: ").strip())
|
||||
if choice == len(user_list) + 1:
|
||||
return
|
||||
if 1 <= choice <= len(user_list):
|
||||
user_id = user_list[choice - 1][0]
|
||||
user = users[user_id]
|
||||
new_name = input(f"Enter new name (leave empty to keep '{user.name}'): ").strip()
|
||||
new_pin = input(f"Enter new PIN (leave empty to keep '{user.pin}'): ").strip()
|
||||
name = new_name if new_name else user.name
|
||||
pin = new_pin if new_pin else user.pin
|
||||
if len(pin) < 4:
|
||||
print("PIN must be at least 4 digits!")
|
||||
input("Press Enter to continue...")
|
||||
return
|
||||
res = self.tracker.edit_user(user_id, name, pin)
|
||||
print(res["message"])
|
||||
input("Press Enter to continue...")
|
||||
else:
|
||||
self._invalid_choice()
|
||||
except ValueError:
|
||||
self._invalid_choice()
|
||||
|
||||
def _cli_remove_user(self):
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("REMOVE USER")
|
||||
print("=" * 50)
|
||||
print()
|
||||
users = self.tracker.get_all_users()
|
||||
user_list = list(users.items())
|
||||
for i, (user_id, user) in enumerate(user_list, 1):
|
||||
print(f"{i}. {user.name}")
|
||||
print(f"{len(user_list) + 1}. Cancel")
|
||||
print()
|
||||
try:
|
||||
choice = int(input("Choose user to remove: ").strip())
|
||||
if choice == len(user_list) + 1:
|
||||
return
|
||||
if 1 <= choice <= len(user_list):
|
||||
user_id = user_list[choice - 1][0]
|
||||
confirm = input(f"Are you sure you want to delete {users[user_id].name}? (y/n): ").strip().lower()
|
||||
if confirm == "y":
|
||||
res = self.tracker.remove_user(user_id)
|
||||
print(res["message"])
|
||||
input("Press Enter to continue...")
|
||||
else:
|
||||
self._invalid_choice()
|
||||
except ValueError:
|
||||
self._invalid_choice()
|
||||
|
||||
def _manage_items(self):
|
||||
while True:
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("MANAGE ITEMS")
|
||||
print("=" * 50)
|
||||
print()
|
||||
print("1. Add item")
|
||||
print("2. Edit item")
|
||||
print("3. Remove item")
|
||||
print("4. Back to admin panel")
|
||||
print()
|
||||
choice = input("Choose option: ").strip()
|
||||
if choice == "1":
|
||||
self._cli_add_item()
|
||||
elif choice == "2":
|
||||
self._cli_edit_item()
|
||||
elif choice == "3":
|
||||
self._cli_remove_item()
|
||||
elif choice == "4":
|
||||
break
|
||||
else:
|
||||
self._invalid_choice()
|
||||
|
||||
def _cli_add_item(self):
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("ADD ITEM")
|
||||
print("=" * 50)
|
||||
print()
|
||||
name = input("Enter item name: ").strip()
|
||||
if not name:
|
||||
print("Name cannot be empty!")
|
||||
input("Press Enter to continue...")
|
||||
return
|
||||
price_str = input("Enter price ($): ").strip()
|
||||
try:
|
||||
price = float(price_str)
|
||||
if price < 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
print("Invalid price!")
|
||||
input("Press Enter to continue...")
|
||||
return
|
||||
import uuid
|
||||
item_id = f"item_{uuid.uuid4().hex[:8]}"
|
||||
res = self.tracker.add_item(item_id, name, price)
|
||||
print(res["message"])
|
||||
input("Press Enter to continue...")
|
||||
|
||||
def _cli_edit_item(self):
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("EDIT ITEM")
|
||||
print("=" * 50)
|
||||
print()
|
||||
items = self.tracker.get_items()
|
||||
item_list = list(items.items())
|
||||
for i, (item_id, item) in enumerate(item_list, 1):
|
||||
print(f"{i}. {item.name} (${item.price:.2f})")
|
||||
print(f"{len(item_list) + 1}. Cancel")
|
||||
print()
|
||||
try:
|
||||
choice = int(input("Choose item to edit: ").strip())
|
||||
if choice == len(item_list) + 1:
|
||||
return
|
||||
if 1 <= choice <= len(item_list):
|
||||
item_id = item_list[choice - 1][0]
|
||||
item = items[item_id]
|
||||
new_name = input(f"Enter new name (leave empty to keep '{item.name}'): ").strip()
|
||||
new_price_str = input(f"Enter new price (leave empty to keep '${item.price:.2f}'): ").strip()
|
||||
name = new_name if new_name else item.name
|
||||
price = item.price
|
||||
if new_price_str:
|
||||
try:
|
||||
price = float(new_price_str)
|
||||
if price < 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
print("Invalid price!")
|
||||
input("Press Enter to continue...")
|
||||
return
|
||||
res = self.tracker.edit_item(item_id, name, price)
|
||||
print(res["message"])
|
||||
input("Press Enter to continue...")
|
||||
else:
|
||||
self._invalid_choice()
|
||||
except ValueError:
|
||||
self._invalid_choice()
|
||||
|
||||
def _cli_remove_item(self):
|
||||
self._clear_screen()
|
||||
print("=" * 50)
|
||||
print("REMOVE ITEM")
|
||||
print("=" * 50)
|
||||
print()
|
||||
items = self.tracker.get_items()
|
||||
item_list = list(items.items())
|
||||
for i, (item_id, item) in enumerate(item_list, 1):
|
||||
print(f"{i}. {item.name} (${item.price:.2f})")
|
||||
print(f"{len(item_list) + 1}. Cancel")
|
||||
print()
|
||||
try:
|
||||
choice = int(input("Choose item to remove: ").strip())
|
||||
if choice == len(item_list) + 1:
|
||||
return
|
||||
if 1 <= choice <= len(item_list):
|
||||
item_id = item_list[choice - 1][0]
|
||||
confirm = input(f"Are you sure you want to delete {items[item_id].name}? (y/n): ").strip().lower()
|
||||
if confirm == "y":
|
||||
res = self.tracker.remove_item(item_id)
|
||||
print(res["message"])
|
||||
input("Press Enter to continue...")
|
||||
else:
|
||||
self._invalid_choice()
|
||||
except ValueError:
|
||||
self._invalid_choice()
|
||||
|
||||
|
||||
+1956
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user