import os import json from datetime import datetime from utils import load_config, load_json, save_json def get_next_id(data_list, id_prefix, id_field): """Generates the next incremental ID for clients or projects.""" if not data_list: return f"{id_prefix}-001" ids = [int(item[id_field].split('-')[1]) for item in data_list] return f"{id_prefix}-{max(ids) + 1:03d}" def select_or_create_client(data_dir, clients_data): """Allows selecting an active client or creating a new one.""" active_clients = [c for c in clients_data["Clients"] if c.get("Active", True)] print("\n--- Select Client ---") for i, client in enumerate(active_clients, 1): print(f"{i}. {client['Name']}") print(f"{len(active_clients) + 1}. [ADD NEW CLIENT]") choice = input("\nSelect a number: ") if choice == str(len(active_clients) + 1): # Create New Client Flow[cite: 2] new_name = input("Client Name: ") new_rate = float(input("Default Hourly Rate: ") or 0) new_id = get_next_id(clients_data["Clients"], "CLT", "ClientID") new_client = { "ClientID": new_id, "Name": new_name, "Active": True, "BillingAddress": {"Street1": "", "Street2": "", "City": "", "State": "", "PostalCode": "", "Country": ""}, "BillingEmail": "", "DefaultRate": new_rate } clients_data["Clients"].append(new_client) save_json(os.path.join(data_dir, "Clients.json"), clients_data) return new_id else: return active_clients[int(choice) - 1]["ClientID"] def select_or_create_project(data_dir, projects_data, client_id): """Allows selecting an active project for the client or creating a new one.""" client_projects = [p for p in projects_data["Projects"] if p["ClientID"] == client_id and p.get("Active", True)] print("\n--- Select Project ---") print("0. No Project") for i, project in enumerate(client_projects, 1): print(f"{i}. {project['Name']}") print(f"{len(client_projects) + 1}. [ADD NEW PROJECT]") choice = input("\nSelect a number: ") if choice == "0": return "" elif choice == str(len(client_projects) + 1): # Create New Project Flow[cite: 2] new_name = input("Project Name: ") new_rate = float(input("Project Billing Rate (0 for client default): ") or 0) new_id = get_next_id(projects_data["Projects"], "PRJ", "ProjectID") new_project = { "ProjectID": new_id, "ClientID": client_id, "Name": new_name, "BillingRate": new_rate, "Active": True } projects_data["Projects"].append(new_project) save_json(os.path.join(data_dir, "Projects.json"), projects_data) return new_id else: return client_projects[int(choice) - 1]["ProjectID"] def main(): config = load_config() data_dir = config["DataDirectory"] # Load existing data[cite: 2] clients_data = load_json(os.path.join(data_dir, "Clients.json"), {"Clients": []}) projects_data = load_json(os.path.join(data_dir, "Projects.json"), {"Projects": []}) # Collect Entry Details[cite: 2] date_str = input(f"Date (YYYY-MM-DD) [Default: {datetime.now().strftime('%Y-%m-%d')}]: ") or datetime.now().strftime("%Y-%m-%d") duration = float(input("Duration (e.g., 1.5): ")) client_id = select_or_create_client(data_dir, clients_data) project_id = select_or_create_project(data_dir, projects_data, client_id) description = input("Description: ") # Generate Entry[cite: 2] entry_id = datetime.now().strftime("%Y%m%d%H%M%S") entry = { "ID": entry_id, "Date": date_str, "Duration": duration, "ClientID": client_id, "ProjectID": project_id, "Description": description, "Invoiced": False, "InvoiceNumber": "" } # Save to Annual Log[cite: 2] year = date_str.split('-')[0] log_path = os.path.join(data_dir, f"{year}_Time_Log.json") log_data = load_json(log_path, {"Year": int(year), "Entries": []}) log_data["Entries"].append(entry) save_json(log_path, log_data) print(f"\nSuccess: Entry {entry_id} saved to {year}_Time_Log.json") if __name__ == "__main__": main()