Files

157 lines
3.5 KiB
Python
Raw Permalink Normal View History

"""SQLite database initialization and access for Handoff Pro."""
import json
import os
import sqlite3
import uuid
from datetime import datetime
DB_PATH = os.environ.get("HANDOFF_DB",
os.path.join(os.path.dirname(__file__), "..", "data", "handoff.db"))
SCHEMA = """
CREATE TABLE IF NOT EXISTS jobs (
id TEXT PRIMARY KEY,
user_id TEXT DEFAULT 'kellow',
jobtread_job_id TEXT UNIQUE,
client_name TEXT,
jobtread_customer_id TEXT,
address TEXT,
description TEXT,
status TEXT DEFAULT 'proposal',
created_at TEXT,
updated_at TEXT,
synced_to_jobtread_at TEXT
);
CREATE TABLE IF NOT EXISTS estimates (
id TEXT PRIMARY KEY,
job_id TEXT REFERENCES jobs(id),
jobtread_estimate_id TEXT UNIQUE,
labor_hours REAL DEFAULT 0,
labor_rate REAL DEFAULT 0,
materials_cost REAL DEFAULT 0,
markup_percent REAL DEFAULT 20,
total_cost REAL DEFAULT 0,
notes TEXT,
status TEXT DEFAULT 'draft',
created_at TEXT,
synced_to_jobtread_at TEXT
);
CREATE TABLE IF NOT EXISTS line_items (
id TEXT PRIMARY KEY,
estimate_id TEXT REFERENCES estimates(id),
description TEXT,
category TEXT,
quantity REAL DEFAULT 1,
unit TEXT DEFAULT 'ea',
unit_cost REAL DEFAULT 0,
total REAL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS pricing_catalogs (
id TEXT PRIMARY KEY,
user_id TEXT DEFAULT 'kellow',
name TEXT,
labor_rates TEXT,
material_markups TEXT,
created_at TEXT
);
CREATE TABLE IF NOT EXISTS invoices (
id TEXT PRIMARY KEY,
estimate_id TEXT REFERENCES estimates(id),
job_id TEXT REFERENCES jobs(id),
invoice_number TEXT,
jobtread_invoice_id TEXT UNIQUE,
qbo_invoice_id TEXT,
amount_due REAL DEFAULT 0,
amount_paid REAL DEFAULT 0,
due_date TEXT,
status TEXT DEFAULT 'draft',
created_at TEXT,
synced_to_jobtread_at TEXT,
synced_to_qbo_at TEXT
);
CREATE TABLE IF NOT EXISTS daily_logs (
id TEXT PRIMARY KEY,
job_id TEXT REFERENCES jobs(id),
log_date TEXT,
crew_names TEXT,
hours_worked REAL DEFAULT 0,
notes TEXT,
photos TEXT,
created_at TEXT
);
CREATE TABLE IF NOT EXISTS signatures (
id TEXT PRIMARY KEY,
estimate_id TEXT REFERENCES estimates(id),
client_name TEXT,
signature_data TEXT,
signed_at TEXT
);
CREATE TABLE IF NOT EXISTS client_activity (
id TEXT PRIMARY KEY,
estimate_id TEXT REFERENCES estimates(id),
job_id TEXT REFERENCES jobs(id),
action TEXT,
metadata TEXT,
timestamp TEXT
);
CREATE TABLE IF NOT EXISTS jobtread_sync_log (
id TEXT PRIMARY KEY,
local_id TEXT,
jobtread_id TEXT,
entity_type TEXT,
action TEXT,
status TEXT DEFAULT 'pending',
error_message TEXT,
synced_at TEXT
);
CREATE TABLE IF NOT EXISTS project_milestones (
id TEXT PRIMARY KEY,
job_id TEXT REFERENCES jobs(id),
phase_name TEXT,
start_date TEXT,
end_date TEXT,
status TEXT DEFAULT 'pending'
);
"""
def get_db() -> sqlite3.Connection:
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH, timeout=10)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("PRAGMA busy_timeout=5000")
return conn
def init_db():
conn = get_db()
conn.executescript(SCHEMA)
conn.commit()
conn.close()
def new_id():
return str(uuid.uuid4())[:8]
def now():
return datetime.now().astimezone().isoformat()
def row_to_dict(row):
if row is None:
return None
return dict(row)
def rows_to_list(rows):
return [dict(r) for r in rows]
if __name__ == "__main__":
init_db()
print(json.dumps({"ok": True, "db_path": DB_PATH}))