This commit is contained in:
2026-05-09 09:34:25 -05:00
parent 6c1b55158d
commit 2b376a4f91
8 changed files with 545 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
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()