"""Proposal drafter: generate professional proposals from estimates.""" import json, sys, os from datetime import datetime, timedelta sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from lib.db import get_db, row_to_dict, rows_to_list TEMPLATE = """# Proposal — {client_name} ## {job_description} **Prepared by:** Kellow Construction **Date:** {date} **Valid for:** 30 days --- ## Scope of Work {scope_items} ## Investment Summary | Category | Amount | |----------|--------| | Labor ({labor_hours} hrs @ ${labor_rate}/hr) | ${labor_cost:,.2f} | | Materials | ${materials_cost:,.2f} | | Subtotal | ${subtotal:,.2f} | | Overhead & Profit ({markup_percent}%) | ${markup:,.2f} | | **Total** | **${total_cost:,.2f}** | ## Timeline Estimated duration: {timeline} Projected start: Upon approval and permitting ## Payment Terms - 30% deposit upon contract signing - Progress payments at milestones - Final 10% upon completion and walkthrough ## Exclusions - Permits and fees (handled separately) - Unforeseen structural issues - Owner-supplied materials - Landscaping and exterior work (unless specified) ## Warranty Kellow Construction provides a 1-year workmanship warranty on all labor performed. --- *This proposal is valid for 30 days from the date above. Acceptance constitutes agreement to the terms outlined herein.* """ def draft(estimate_id): conn = get_db() est = row_to_dict(conn.execute("SELECT * FROM estimates WHERE id=?", (estimate_id,)).fetchone()) if not est: conn.close(); return {"error": "estimate not found"} items = rows_to_list(conn.execute("SELECT * FROM line_items WHERE estimate_id=?", (estimate_id,)).fetchall()) job = row_to_dict(conn.execute("SELECT * FROM jobs WHERE id=?", (est["job_id"],)).fetchone()) conn.close() labor_cost = est["labor_hours"] * est["labor_rate"] subtotal = labor_cost + est["materials_cost"] markup = subtotal * (est["markup_percent"] / 100) # Build scope items scope_lines = [] for item in items: scope_lines.append(f"- {item['description']}: {item['quantity']} {item['unit']} @ ${item['unit_cost']:.2f}/{item['unit']}") # Estimate timeline from labor hours weeks = max(1, int(est["labor_hours"] / 40)) timeline = f"{weeks} week{'s' if weeks > 1 else ''}" proposal = TEMPLATE.format( client_name=job.get("client_name", "Client") if job else "Client", job_description=job.get("description", "Project") if job else "Project", date=datetime.now().strftime("%B %d, %Y"), scope_items="\n".join(scope_lines) if scope_lines else "- As discussed", labor_hours=round(est["labor_hours"], 1), labor_rate=est["labor_rate"], labor_cost=labor_cost, materials_cost=est["materials_cost"], subtotal=subtotal, markup_percent=est["markup_percent"], markup=markup, total_cost=est["total_cost"], timeline=timeline, ) return {"proposal": proposal, "estimate_id": estimate_id, "total": est["total_cost"]} if __name__ == "__main__": from lib.db import init_db; init_db() if len(sys.argv) < 2: print(json.dumps({"error": "usage: proposal_drafter.py "})) else: result = draft(sys.argv[1]) if "proposal" in result: print(result["proposal"]) else: print(json.dumps(result))