51 lines
2.1 KiB
Python
51 lines
2.1 KiB
Python
|
|
"""Scope of work generator from estimates."""
|
||
|
|
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
|
||
|
|
|
||
|
|
STANDARD_CLAUSES = """
|
||
|
|
## General Conditions
|
||
|
|
|
||
|
|
- All work performed in accordance with local building codes and regulations
|
||
|
|
- Contractor to obtain all necessary permits unless otherwise noted
|
||
|
|
- Work area to be kept clean and debris removed daily
|
||
|
|
- Final cleanup included upon project completion
|
||
|
|
|
||
|
|
## Warranty
|
||
|
|
|
||
|
|
- 1-year workmanship warranty on all labor
|
||
|
|
- Manufacturer warranties apply to all materials and fixtures
|
||
|
|
|
||
|
|
## Exclusions
|
||
|
|
|
||
|
|
- Unforeseen conditions (mold, asbestos, structural damage) — addressed via change order
|
||
|
|
- Owner-supplied materials — contractor not responsible for defects
|
||
|
|
- Landscaping, exterior painting, or work not explicitly listed above
|
||
|
|
- Furniture moving or storage
|
||
|
|
"""
|
||
|
|
|
||
|
|
def generate(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()
|
||
|
|
|
||
|
|
lines = [f"# Scope of Work — {job.get('client_name','Client') if job else 'Client'}",
|
||
|
|
f"**Project:** {job.get('description','') if job else ''}",
|
||
|
|
f"**Address:** {job.get('address','') if job else ''}", "", "## Work Items", ""]
|
||
|
|
for i, item in enumerate(items, 1):
|
||
|
|
if item["category"] == "labor":
|
||
|
|
lines.append(f"{i}. **{item['description']}** — {item['quantity']} {item['unit']}")
|
||
|
|
lines.append(STANDARD_CLAUSES)
|
||
|
|
scope = "\n".join(lines)
|
||
|
|
return {"scope": scope, "estimate_id": estimate_id, "items_count": len(items)}
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
from lib.db import init_db; init_db()
|
||
|
|
if len(sys.argv) < 2: print(json.dumps({"error": "usage: scope_generator.py <estimate_id>"}))
|
||
|
|
else:
|
||
|
|
r = generate(sys.argv[1])
|
||
|
|
print(r.get("scope", json.dumps(r)))
|