v2.0
This commit is contained in:
+115
@@ -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()
|
||||
Reference in New Issue
Block a user