Initial commit: Handoff Pro MCP server for Kellow Construction
This commit is contained in:
40
scripts/budget_tracker.py
Normal file
40
scripts/budget_tracker.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""Budget tracker: compare estimated vs actual costs."""
|
||||
import json, sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
from lib.db import get_db, row_to_dict, rows_to_list
|
||||
|
||||
def report(job_id):
|
||||
conn = get_db()
|
||||
job = row_to_dict(conn.execute("SELECT * FROM jobs WHERE id=?", (job_id,)).fetchone())
|
||||
if not job: conn.close(); return {"error": "job not found"}
|
||||
estimates = rows_to_list(conn.execute("SELECT * FROM estimates WHERE job_id=?", (job_id,)).fetchall())
|
||||
logs = rows_to_list(conn.execute("SELECT * FROM daily_logs WHERE job_id=?", (job_id,)).fetchall())
|
||||
invoices = rows_to_list(conn.execute("SELECT * FROM invoices WHERE job_id=?", (job_id,)).fetchall())
|
||||
conn.close()
|
||||
|
||||
budgeted = sum(e["total_cost"] for e in estimates) if estimates else 0
|
||||
actual_hours = sum(l["hours_worked"] for l in logs)
|
||||
budgeted_hours = sum(e["labor_hours"] for e in estimates) if estimates else 0
|
||||
invoiced = sum(i["amount_due"] for i in invoices)
|
||||
paid = sum(i["amount_paid"] or 0 for i in invoices)
|
||||
|
||||
hours_variance = actual_hours - budgeted_hours
|
||||
hours_pct = (hours_variance / budgeted_hours * 100) if budgeted_hours else 0
|
||||
|
||||
flags = []
|
||||
if hours_pct > 10: flags.append(f"⚠️ Labor {hours_pct:.0f}% over budget")
|
||||
if paid < invoiced * 0.5 and invoices: flags.append("⚠️ Less than 50% collected")
|
||||
|
||||
return {
|
||||
"job_id": job_id, "client": job.get("client_name"),
|
||||
"budget": {"total_estimated": budgeted, "budgeted_hours": budgeted_hours},
|
||||
"actual": {"hours_worked": actual_hours, "log_entries": len(logs)},
|
||||
"financial": {"invoiced": invoiced, "collected": paid, "outstanding": invoiced - paid},
|
||||
"variance": {"hours": hours_variance, "hours_pct": round(hours_pct, 1)},
|
||||
"flags": flags
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
from lib.db import init_db; init_db()
|
||||
if len(sys.argv) < 2: print(json.dumps({"error": "usage: budget_tracker.py <job_id>"}))
|
||||
else: print(json.dumps(report(sys.argv[1]), indent=2))
|
||||
Reference in New Issue
Block a user