from config import ADMIN_PASSWORD class CLI: def __init__(self, tracker) -> None: self.tracker = tracker self.current_user = None 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) self._clear_screen() print("=" * 50) print("PURCHASE ADDED") print("=" * 50) print() print(f"✓ {result['message']}") print(f"New debt: ${result['new_debt']:.2f}") print() 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. 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": 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 ("Adjustment" if t.item_id == "adjustment" 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()