115 lines
4.3 KiB
Python
115 lines
4.3 KiB
Python
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() |