136 lines
4.0 KiB
Python
136 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""NH Broadband install packet builder for the live scheduling step."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
|
|
def load_request(path: str | Path) -> dict[str, Any]:
|
|
data = yaml.safe_load(Path(path).read_text()) or {}
|
|
data.setdefault("contact", {})
|
|
data.setdefault("service", {})
|
|
data.setdefault("call_log", [])
|
|
data.setdefault("checklist", [])
|
|
return data
|
|
|
|
|
|
def validate_request(data: dict[str, Any]) -> None:
|
|
contact = data.get("contact", {})
|
|
for field in ("name", "phone"):
|
|
if not contact.get(field, "").strip():
|
|
raise ValueError(f"contact.{field} is required")
|
|
|
|
service = data.get("service", {})
|
|
for field in ("address", "city", "state"):
|
|
if not service.get(field, "").strip():
|
|
raise ValueError(f"service.{field} is required")
|
|
|
|
if not data.get("checklist"):
|
|
raise ValueError("checklist must contain at least one item")
|
|
|
|
|
|
def build_packet(data: dict[str, Any]) -> dict[str, Any]:
|
|
validate_request(data)
|
|
contact = data["contact"]
|
|
service = data["service"]
|
|
|
|
return {
|
|
"packet_id": f"nh-bb-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}",
|
|
"generated_utc": datetime.now(timezone.utc).isoformat(),
|
|
"contact": {
|
|
"name": contact["name"],
|
|
"phone": contact["phone"],
|
|
"email": contact.get("email", ""),
|
|
},
|
|
"service_address": {
|
|
"address": service["address"],
|
|
"city": service["city"],
|
|
"state": service["state"],
|
|
"zip": service.get("zip", ""),
|
|
},
|
|
"desired_plan": data.get("desired_plan", "residential-fiber"),
|
|
"call_log": data.get("call_log", []),
|
|
"checklist": [
|
|
{"item": item, "done": False} if isinstance(item, str) else item
|
|
for item in data["checklist"]
|
|
],
|
|
"status": "pending_scheduling_call",
|
|
}
|
|
|
|
|
|
def render_markdown(packet: dict[str, Any], data: dict[str, Any]) -> str:
|
|
contact = packet["contact"]
|
|
addr = packet["service_address"]
|
|
lines = [
|
|
f"# NH Broadband Install Packet",
|
|
"",
|
|
f"**Packet ID:** {packet['packet_id']}",
|
|
f"**Generated:** {packet['generated_utc']}",
|
|
f"**Status:** {packet['status']}",
|
|
"",
|
|
"## Contact",
|
|
"",
|
|
f"- **Name:** {contact['name']}",
|
|
f"- **Phone:** {contact['phone']}",
|
|
f"- **Email:** {contact.get('email', 'n/a')}",
|
|
"",
|
|
"## Service Address",
|
|
"",
|
|
f"- {addr['address']}",
|
|
f"- {addr['city']}, {addr['state']} {addr['zip']}",
|
|
"",
|
|
f"## Desired Plan",
|
|
"",
|
|
f"{packet['desired_plan']}",
|
|
"",
|
|
"## Call Log",
|
|
"",
|
|
]
|
|
if packet["call_log"]:
|
|
for entry in packet["call_log"]:
|
|
ts = entry.get("timestamp", "n/a")
|
|
outcome = entry.get("outcome", "n/a")
|
|
notes = entry.get("notes", "")
|
|
lines.append(f"- **{ts}** — {outcome}")
|
|
if notes:
|
|
lines.append(f" - {notes}")
|
|
else:
|
|
lines.append("_No calls logged yet._")
|
|
|
|
lines.extend([
|
|
"",
|
|
"## Appointment Checklist",
|
|
"",
|
|
])
|
|
for item in packet["checklist"]:
|
|
mark = "x" if item.get("done") else " "
|
|
lines.append(f"- [{mark}] {item['item']}")
|
|
|
|
lines.append("")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Build NH Broadband install packet.")
|
|
parser.add_argument("request", help="Path to install request YAML")
|
|
parser.add_argument("--markdown", action="store_true", help="Render markdown instead of JSON")
|
|
args = parser.parse_args()
|
|
|
|
data = load_request(args.request)
|
|
packet = build_packet(data)
|
|
if args.markdown:
|
|
print(render_markdown(packet, data))
|
|
else:
|
|
print(json.dumps(packet, indent=2))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|