Added the creation of jobmaterials script and the creation script ofr live updates to the ServiceM8 server (default is -dry-run). Altered inspector.py to now let us view jobmaterials DB.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
from servicem8_quote_template_parser import (
|
||||
QUOTE_TEMPLATE_FORM_UUID,
|
||||
STATE_DB_PATH,
|
||||
init_state_db,
|
||||
load_input_file,
|
||||
parse_quote_template_form_response,
|
||||
record_generated_job_material,
|
||||
)
|
||||
|
||||
BASE_URL = os.getenv("SERVICEM8_BASE_URL", "https://api.servicem8.com/api_1.0")
|
||||
ACCESS_TOKEN = os.getenv("SERVICEM8_ACCESS_TOKEN", "")
|
||||
REQUEST_TIMEOUT = int(os.getenv("SERVICEM8_TIMEOUT", "30"))
|
||||
|
||||
|
||||
def build_payload(job_uuid: str, row: dict) -> dict:
|
||||
return {
|
||||
"job_uuid": job_uuid,
|
||||
"material_uuid": row["material_uuid"],
|
||||
"name": row["name"],
|
||||
"quantity": row["quantity"],
|
||||
"price": row["price"],
|
||||
"displayed_amount": row["displayed_amount"],
|
||||
"displayed_amount_is_tax_inclusive": row["displayed_amount_is_tax_inclusive"],
|
||||
"sort_order": row["sort_order"],
|
||||
}
|
||||
|
||||
|
||||
def create_job_material(session: requests.Session, payload: dict) -> str:
|
||||
response = session.post(f"{BASE_URL}/jobmaterial.json", json=payload, timeout=REQUEST_TIMEOUT)
|
||||
if not response.ok:
|
||||
raise RuntimeError(f"Create failed: HTTP {response.status_code} :: {response.text}")
|
||||
record_uuid = response.headers.get("x-record-uuid", "")
|
||||
if not record_uuid:
|
||||
raise RuntimeError("Create succeeded but x-record-uuid header was missing")
|
||||
return record_uuid
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Create ServiceM8 jobMaterials from a Quote Template form response")
|
||||
parser.add_argument("input", help="Path to JSON file containing full form response payload or a data object with field_data")
|
||||
parser.add_argument("--apply", action="store_true", help="Actually create records in ServiceM8. Default is dry-run.")
|
||||
parser.add_argument("--pretty", action="store_true", help="Pretty-print output JSON")
|
||||
args = parser.parse_args()
|
||||
|
||||
init_state_db(STATE_DB_PATH)
|
||||
|
||||
payload = load_input_file(args.input)
|
||||
parsed = parse_quote_template_form_response(payload)
|
||||
|
||||
form_uuid = parsed.get("form_uuid", "")
|
||||
if form_uuid and form_uuid != QUOTE_TEMPLATE_FORM_UUID:
|
||||
raise SystemExit(f"Not a Quote Template form response: {form_uuid}")
|
||||
|
||||
job_uuid = parsed.get("job_uuid", "")
|
||||
form_response_uuid = parsed.get("form_response_uuid", "")
|
||||
desired_rows = parsed.get("desired_job_materials", [])
|
||||
|
||||
if not job_uuid:
|
||||
raise SystemExit("Missing job_uuid / regarding_object_uuid in form response")
|
||||
|
||||
result = {
|
||||
"mode": "apply" if args.apply else "dry-run",
|
||||
"job_uuid": job_uuid,
|
||||
"form_response_uuid": form_response_uuid,
|
||||
"count": len(desired_rows),
|
||||
"rows": [],
|
||||
"state_db_path": str(STATE_DB_PATH),
|
||||
}
|
||||
|
||||
if not args.apply:
|
||||
for row in desired_rows:
|
||||
result["rows"].append(
|
||||
{
|
||||
"action": "would_create",
|
||||
"kind": row["kind"],
|
||||
"payload": build_payload(job_uuid, row),
|
||||
"source_question": row.get("source_question", ""),
|
||||
"source_field_uuid": row.get("source_field_uuid", ""),
|
||||
}
|
||||
)
|
||||
print(json.dumps(result, indent=2 if args.pretty else None, ensure_ascii=False))
|
||||
return
|
||||
|
||||
if not ACCESS_TOKEN:
|
||||
raise SystemExit("SERVICEM8_ACCESS_TOKEN is required for --apply")
|
||||
|
||||
session = requests.Session()
|
||||
session.headers.update(
|
||||
{
|
||||
"X-Api-Key": ACCESS_TOKEN,
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
)
|
||||
|
||||
for row in desired_rows:
|
||||
api_payload = build_payload(job_uuid, row)
|
||||
created_uuid = create_job_material(session, api_payload)
|
||||
record_generated_job_material(
|
||||
job_uuid=job_uuid,
|
||||
form_response_uuid=form_response_uuid,
|
||||
job_material_uuid=created_uuid,
|
||||
kind=row.get("kind", ""),
|
||||
source_field_uuid=row.get("source_field_uuid", ""),
|
||||
source_question=row.get("source_question", ""),
|
||||
source_text=row.get("name", ""),
|
||||
db_path=STATE_DB_PATH,
|
||||
)
|
||||
result["rows"].append(
|
||||
{
|
||||
"action": "created",
|
||||
"kind": row["kind"],
|
||||
"job_material_uuid": created_uuid,
|
||||
"payload": api_payload,
|
||||
}
|
||||
)
|
||||
|
||||
print(json.dumps(result, indent=2 if args.pretty else None, ensure_ascii=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except Exception as exc:
|
||||
print(str(exc), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user