Files
2026-05-09 09:42:43 -05:00

78 lines
2.8 KiB
Python

import os
from utils import load_config, load_json
def main():
config = load_config()
data_dir = config["DataDirectory"]
# Load supporting data
clients_data = load_json(os.path.join(data_dir, "Clients.json"), {"Clients": []})
projects_data = load_json(os.path.join(data_dir, "Projects.json"), {"Projects": []})
# Map IDs for quick lookup
client_map = {c["ClientID"]: c["Name"] for c in clients_data["Clients"]}
project_map = {p["ProjectID"]: p["Name"] for p in projects_data["Projects"]}
project_rates = {p["ProjectID"]: p.get("BillingRate", 0) for p in projects_data["Projects"]}
client_rates = {c["ClientID"]: c["DefaultRate"] for c in clients_data["Clients"]}
log_files = [f for f in os.listdir(data_dir) if f.endswith("_Time_Log.json")]
# Structure: { ClientName: { ProjectName: { hours: 0, amount: 0 } } }
report = {}
for file_name in log_files:
logs = load_json(os.path.join(data_dir, file_name), {"Entries": []})
for entry in logs.get("Entries", []):
if not entry.get("Invoiced", False):
c_id = entry["ClientID"]
p_id = entry["ProjectID"]
c_name = client_map.get(c_id, f"Unknown ({c_id})")
p_name = project_map.get(p_id, "No Project")
# Determine rate
rate = project_rates.get(p_id, 0)
if rate == 0:
rate = client_rates.get(c_id, 0)
hours = float(entry.get("Duration", 0))
amount = hours * rate
if c_name not in report:
report[c_name] = {}
if p_name not in report[c_name]:
report[c_name][p_name] = {"hours": 0.0, "amount": 0.0}
report[c_name][p_name]["hours"] += hours
report[c_name][p_name]["amount"] += amount
# Print Report
print("\n" + "="*50)
print("UNBILLED TIME REPORT")
print("="*50)
if not report:
print("No unbilled entries found.")
return
grand_total_amount = 0
for client, projects in sorted(report.items()):
print(f"\nCLIENT: {client}")
print("-" * 30)
client_total_h = 0
client_total_a = 0
for project, stats in projects.items():
print(f" {project:<20} {stats['hours']:>6.2f} hrs ${stats['amount']:>8.2f}")
client_total_h += stats['hours']
client_total_a += stats['amount']
print(f" {'Total:':<20} {client_total_h:>6.2f} hrs ${client_total_a:>8.2f}")
grand_total_amount += client_total_a
print("\n" + "="*50)
print(f"GRAND TOTAL UNBILLED: ${grand_total_amount:,.2f}")
print("="*50 + "\n")
if __name__ == "__main__":
main()