Files
kuehlschrank/ui/cli.py
T
schn33fuchs 79d441a86e Motor
The raspi now controls a motor to lock unlock
2026-06-07 10:27:22 +02:00

621 lines
20 KiB
Python

from config import ADMIN_PASSWORD
class CLI:
def __init__(self, tracker) -> None:
self.tracker = tracker
self.current_user = None
from raspi.motor import Raspi
self.motor = Raspi()
def run(self):
while True:
self._clear_screen()
self._show_main_menu()
def _clear_screen(self):
import subprocess
import os
subprocess.run("cls" if os.name == "nt" else "clear")
def _show_main_menu(self):
print("=" * 50)
print("DEBT TRACKER")
print("=" * 50)
if self.current_user:
user = self.tracker.get_user_by_id(self.current_user)
debt = self.tracker.get_user_debt(self.current_user)
print(f"\nLogged in as: {user.name}")
print(f"Current Debt: ${debt:.2f}\n")
print("1. Select user")
print("2. View all debts")
print("3. Admin panel")
print("4. Exit")
print()
choice = input("Choose Option: ").strip()
if choice == "1":
self._select_user()
elif choice == "2":
self._view_all_debts()
elif choice == "3":
self._admin_panel()
elif choice == "4":
print("\nGoodbye!")
exit()
else:
self._invalid_choice()
def _select_user(self):
self._clear_screen()
print("=" * 50)
print("SELECT 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):
debt = self.tracker.get_user_debt(user_id)
print(f"{i}. {user.name} (Debt: ${debt:.2f})")
print(f"{len(user_list) + 1}. Back to main menu")
print()
try:
choice = int(input("Choose user: ").strip())
if choice == len(user_list) + 1:
return
if 1 <= choice <= len(user_list):
self.current_user = user_list[choice - 1][0]
self._user_menu()
else:
self._invalid_choice()
except ValueError:
self._invalid_choice()
def _user_menu(self):
while True:
self._clear_screen()
user = self.tracker.get_user_by_id(self.current_user)
debt = self.tracker.get_user_debt(self.current_user)
print("=" * 50)
print(f"USER MENU - {user.name}")
print("=" * 50)
print(f"Current debt: ${debt:.2f}\n")
print("1. Add purchase")
print("2. View my debt")
print("3. Logout")
print()
choice = input("Choose option: ").strip()
if choice == "1":
self._add_purchase()
elif choice == "2":
self._view_user_debt()
elif choice == "3":
self.current_user = None
break
else:
self._invalid_choice()
def _add_purchase(self):
self._clear_screen()
print("=" * 50)
print("ADD PURCHASE")
print("=" * 50)
print()
menu_items = self.tracker.get_items()
item_list = list(menu_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: ").strip())
if choice == len(item_list) + 1:
return
if 1 <= choice <= len(item_list):
selected_item_id = item_list[choice - 1][0]
self._confirm_purchase(selected_item_id)
else:
self._invalid_choice()
except ValueError:
self._invalid_choice()
def _confirm_purchase(self, item_id):
self._clear_screen()
user = self.tracker.get_user_by_id(self.current_user)
item = self.tracker.get_items()[item_id]
print("=" * 50)
print("CONFIRM PURCHASE")
print("=" * 50)
print()
print(f"User: {user.name}")
print(f"Item: {item.name}")
print(f"Price: ${item.price:.2f}")
print()
confirm = input("Add to debt? (y/n): ").strip().lower()
if confirm == "y":
result = self.tracker.add_purchase(self.current_user, item_id)
if result["status"] == "success":
self._clear_screen()
print("=" * 50)
print("PURCHASE ADDED")
print("=" * 50)
print()
print(f"✓ {result['message']}")
print(f"New debt: ${result['new_debt']:.2f}")
print()
self.motor.unlock_async()
input("Press Enter to continue...")
self.motor.lock_async()
else:
print(f"Error: {result['message']}")
input("Press Enter to continue...")
else:
print("Purchase cancelled.")
input("Press Enter to continue...")
def _view_user_debt(self):
self._clear_screen()
user = self.tracker.get_user_by_id(self.current_user)
debt = self.tracker.get_user_debt(self.current_user)
print("=" * 50)
print(f"DEBT - {user.name}")
print("=" * 50)
print()
print(f"Amount owed: ${debt:.2f}")
print()
input("Press Enter to continue...")
def _view_all_debts(self):
self._clear_screen()
print("=" * 50)
print("ALL DEBTS")
print("=" * 50)
print()
all_debts = self.tracker.get_all_debts()
if not all_debts:
print("No users with debt.")
else:
total = 0
for _user_id, debt_info in all_debts.items():
amount = debt_info["debt"]
print(f"{debt_info['name']:.<30} ${amount:>7.2f}")
total += amount
print("-" * 50)
print(f"{'TOTAL':.<30} ${total:>7.2f}")
print()
input("Press Enter to continue...")
def _admin_panel(self):
self._clear_screen()
print("=" * 50)
print("ADMIN PANEL")
print("=" * 50)
print()
password = input("Enter admin password: ").strip()
if password != ADMIN_PASSWORD:
print("Invalid password!")
input("Press Enter to continue...")
return
while True:
self._clear_screen()
print("=" * 50)
print("ADMIN PANEL")
print("=" * 50)
print()
print("1. View all debts")
print("2. Adjust user debt")
print("3. Clear user debt")
print("4. View transaction history")
print("5. Manage users")
print("6. Manage items")
print("7. Open Kühlschrank (Unlock)")
print("8. Close Kühlschrank (Lock)")
print("9. Logout")
print()
choice = input("Choose option: ").strip()
if choice == "1":
self._view_all_debts()
elif choice == "2":
self._adjust_debt()
elif choice == "3":
self._clear_user_debt()
elif choice == "4":
self._view_transaction_history()
elif choice == "5":
self._manage_users()
elif choice == "6":
self._manage_items()
elif choice == "7":
print("Kühlschrank wird geöffnet (Entriegeln)...")
self.motor.unlock_async()
input("Press Enter to continue...")
elif choice == "8":
print("Kühlschrank wird geschlossen (Verriegeln)...")
self.motor.lock_async()
input("Press Enter to continue...")
elif choice == "9":
break
else:
self._invalid_choice()
def _adjust_debt(self):
self._clear_screen()
print("=" * 50)
print("ADJUST DEBT")
print("=" * 50)
print()
users = self.tracker.get_all_users()
user_list = list(users.items())
for i, (user_id, user) in enumerate(user_list, 1):
debt = self.tracker.get_user_debt(user_id)
print(f"{i}. {user.name} - ${debt:.2f}")
print()
try:
choice = int(input("Choose user: ").strip())
if 1 <= choice <= len(user_list):
user_id = user_list[choice - 1][0]
amount_str = input("Amount paid: $").strip()
amount = float(amount_str)
result = self.tracker.adjust_debt(user_id, amount, ADMIN_PASSWORD)
self._clear_screen()
print("=" * 50)
print("DEBT ADJUSTED")
print("=" * 50)
print()
print(f"{result['message']}")
print(f"New debt: ${result['new_debt']:.2f}")
print()
input("Press Enter to continue...")
else:
self._invalid_choice()
except ValueError:
print("Invalid input!")
input("Press Enter to continue...")
def _clear_user_debt(self):
self._clear_screen()
print("=" * 50)
print("CLEAR USER DEBT")
print("=" * 50)
print()
users = self.tracker.get_all_users()
user_list = list(users.items())
for i, (user_id, user) in enumerate(user_list, 1):
debt = self.tracker.get_user_debt(user_id)
print(f"{i}. {user.name} - ${debt:.2f}")
print()
try:
choice = int(input("Choose user: ").strip())
if 1 <= choice <= len(user_list):
user_id = user_list[choice - 1][0]
debt_amount = self.tracker.get_user_debt(user_id)
confirm = input(f"Clear ${debt_amount:.2f}? (y/n): ").strip().lower()
if confirm == "y":
_result = self.tracker.adjust_debt(
user_id, debt_amount, ADMIN_PASSWORD
)
self._clear_screen()
print("=" * 50)
print("DEBT CLEARED")
print("=" * 50)
print()
print(
f"Debt cleared for {self.tracker.get_user_by_id(user_id).name}"
)
print()
input("Press Enter to continue...")
else:
self._invalid_choice()
except ValueError:
print("Invalid input!")
input("Press Enter to continue...")
def _view_transaction_history(self):
self._clear_screen()
print("=" * 50)
print("TRANSACTION HISTORY")
print("=" * 50)
print()
transactions = self.tracker.transactions
if not transactions:
print("No transactions yet.")
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().get(t.item_id)
item_name = item.name if item else ("Abbuchung" if t.item_id in ("adjustment", "Abbuchung") else "Deleted Item")
print(
f"{t.timestamp[:10]} | {user.name:.<20} {item_name:.<15} ${t.amount:.2f}"
)
print()
input("Press Enter to continue...")
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()