fix(syncro): omit contact_id by default; Syncro assigns primary automatically

Only set contact_id when ticket is opened by/regarding a named contact.
Removed address_id, appointment_owner, and do_not_invite fields from the
default gather step — these are edge cases, not routine inputs.
Updated preview template to reflect default primary contact behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 10:02:57 -07:00
parent 04c7bf7564
commit 59ea650865

View File

@@ -306,29 +306,23 @@ Collect in one pass (do not ask field by field):
| 5 | **Do Not Email** | Suppress customer notification on ticket create? (yes for internal/reminder tickets) | | 5 | **Do Not Email** | Suppress customer notification on ticket create? (yes for internal/reminder tickets) |
| 6 | **Due Date** | ISO date | | 6 | **Due Date** | ISO date |
| 7 | **Assigned Tech** | Who owns the ticket. Defaults to API key owner if not specified (mike → 1735, howard → 1750). MUST always be included in the POST payload — never omit. | | 7 | **Assigned Tech** | Who owns the ticket. Defaults to API key owner if not specified (mike → 1735, howard → 1750). MUST always be included in the POST payload — never omit. |
| 8 | **Contact** | Look up from `GET /customers/{id}` → `.contacts[]`; show list, ask user to pick | | 8 | **Contact** | Omit unless the ticket is opened by or specifically regarding a named contact. When omitted, Syncro assigns the customer's primary contact automatically. Only look up and set `contact_id` when the user names a specific person. |
| 9 | **Address/Site** | `address_id` — also comes from customer contacts with address data | | 9 | **Appointment Type** | From table above; omit section if no appointment needed |
| 10 | **Appointment Type** | From table above; omit section if no appointment needed | | 10 | **Location** | Free text; usually blank unless onsite at non-primary address |
| 11 | **Location** | Free text; usually blank unless onsite at non-primary address | | 11 | **Start Time** | ISO8601 datetime; omit if no scheduled appointment |
| 12 | **Start Time** | ISO8601 datetime; omit if no scheduled appointment | | 12 | **End Time** | Default: start + 90 minutes |
| 13 | **End Time** | Default: start + 90 minutes | | 13 | **Asset** | Search `GET /customer_assets?customer_id=N&query=<name>` if a specific device is involved |
| 14 | **Appointment Owner** | Usually same as assigned tech; noted for calendar attribution (not a separate API field — inherits from ticket `user_id`) |
| 15 | **Do Not Invite** | If not onsite, suppress calendar invite — note: not directly controllable via API; inform user if they need this set manually |
| 16 | **Asset** | Search `GET /customer_assets?customer_id=N&query=<name>` if a specific device is involved |
#### Step 2 — Look up customer data **Contact lookup (only when a specific contact is named):**
Before showing the preview, fetch what you need:
```bash ```bash
# Get contacts and addresses curl -s "${BASE}/customers/${CUST_ID}?api_key=${API_KEY}" | \
curl -s "${BASE}/customers/${CUST_ID}?api_key=${API_KEY}" | jq '{contacts: [.customer.contacts[] | {id, name, address1, email}]}' jq '[.customer.contacts[] | {id, name, email}]'
# Search assets
curl -s "${BASE}/customer_assets?customer_id=${CUST_ID}&query=<name>&api_key=${API_KEY}" | jq '[.assets[] | {id, name, asset_type}]'
``` ```
#### Step 3 — Show preview and confirm Match by name, confirm with user, then include `contact_id` in the ticket POST. Never include `contact_id: null` — omit the field entirely when using the default.
#### Step 2 — Show preview and confirm
Display the full ticket before posting. Include all populated fields. Wait for explicit confirmation. Display the full ticket before posting. Include all populated fields. Wait for explicit confirmation.
@@ -342,11 +336,10 @@ Priority: <priority>
Description: <description> Description: <description>
Due Date: <due_date> Due Date: <due_date>
Assigned To: <tech name> Assigned To: <tech name>
Contact: <contact name> Contact: <primary — Syncro default> (or named contact if specified)
Address: <address>
Do Not Email: <yes/no> Do Not Email: <yes/no>
APPOINTMENT APPOINTMENT (omit section if no appointment)
----------- -----------
Type: <type name> Type: <type name>
Start: <start_at> Start: <start_at>
@@ -358,7 +351,7 @@ ASSET: <asset name or none>
Confirm? (yes/no) Confirm? (yes/no)
``` ```
#### Step 4 — Execute (after confirmation) #### Step 3 — Execute (after confirmation)
**Call 1 — Create ticket:** **Call 1 — Create ticket:**
@@ -373,12 +366,7 @@ RESP=$(curl -s -X POST "${BASE}/tickets?api_key=${API_KEY}" \
"status": "New", "status": "New",
"priority": "2 Normal", "priority": "2 Normal",
"user_id": N, "user_id": N,
"due_date": "YYYY-MM-DD", "due_date": "YYYY-MM-DD"
"contact_id": N,
"address_id": N,
"start_at": "ISO8601",
"end_at": "ISO8601",
"asset_ids": [N]
} }
JSON JSON
) )
@@ -386,7 +374,7 @@ TICKET_ID=$(echo "$RESP" | jq -r '.ticket.id')
CUST_ID=$(echo "$RESP" | jq -r '.ticket.customer_id') CUST_ID=$(echo "$RESP" | jq -r '.ticket.customer_id')
``` ```
Omit null/blank fields from the payload before piping. The `'JSON'` quoting on the heredoc opener is required — it suppresses bash variable and backtick expansion inside, which matters when descriptions contain `$` (passwords, prices, regex, etc.). Omit `contact_id` unless a specific contact was named — Syncro assigns the primary automatically. Omit `asset_ids` unless an asset was identified. Omit `do_not_email` unless suppression was requested. Never include fields with null values. The `'JSON'` quoting on the heredoc suppresses `$` expansion inside the payload.
**Call 2 — Post initial description as "Initial Issue" comment:** **Call 2 — Post initial description as "Initial Issue" comment:**