sync: auto-sync from GURU-BEAST-ROG at 2026-05-22 13:13:08

Author: Mike Swanson
Machine: GURU-BEAST-ROG
Timestamp: 2026-05-22 13:13:08
This commit is contained in:
2026-05-22 13:13:09 -07:00
parent e0017e96c2
commit 51d55566bf
3 changed files with 270 additions and 8 deletions

View File

@@ -584,14 +584,21 @@ POST `/invoices` pulls all current line items from the ticket into the invoice a
#### Estimates
Estimates (quotes) are standalone or ticket-linked. Verified 2026-05-22 against ACG internal account.
Estimates (quotes) always get an associated ticket with a private note containing links. This is a hard workflow requirement — never create an estimate without the ticket and private note.
**Required fields for POST /estimates:** `customer_id`, `date` (ISO date string `"YYYY-MM-DD"`)
**Optional:** `name` (estimate title), `ticket_id` (link to ticket), `location_id`
**Statuses:** `Fresh` (default), `Approved`, `Declined`
**MANDATORY estimate workflow (4 steps, always in this order):**
1. Create estimate
2. Add line items (with price fix — see below)
3. Create ticket (`do_not_email: true`, `hidden: true` note) with private note containing estimate link + product/source links
4. Link estimate to ticket via PUT, then post a single bot alert with both links
```bash
# Create estimate
# Step 1 — Create estimate
EST_RESP=$(curl -s -X POST "${BASE}/estimates?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
@@ -605,8 +612,9 @@ JSON
ESTIMATE_ID=$(echo "$EST_RESP" | jq -r '.estimate.id')
ESTIMATE_NUM=$(echo "$EST_RESP" | jq -r '.estimate.number')
# Add line item — endpoint is /line_items NOT /add_line_item (that 404s)
# Response: {"estimate": {...}, "line_item": {"id": N, "item": name, "price": rate, ...}}
# Step 2 — Add line item, then fix price via PUT
# NOTE: POST /line_items ignores price_retail for hardware (product 32252) — price stays $0.
# Always follow up with PUT /line_items/{id} to set the price. Verified 2026-05-22.
LI_RESP=$(curl -s -X POST "${BASE}/estimates/${ESTIMATE_ID}/line_items?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
@@ -616,13 +624,57 @@ LI_RESP=$(curl -s -X POST "${BASE}/estimates/${ESTIMATE_ID}/line_items?api_key=$
"description": "<one-line description>",
"quantity": ${QTY},
"price_retail": ${RATE},
"taxable": false
"taxable": true
}
JSON
)
LI_ID=$(echo "$LI_RESP" | jq -r '.line_item.id')
# GET estimate (verify)
# Fix price via PUT (required — POST does not apply price_retail for hardware)
curl -s -X PUT "${BASE}/estimates/${ESTIMATE_ID}/line_items/${LI_ID}?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{"price": ${RATE}, "price_retail": ${RATE}}
JSON
# Step 3 — Create ticket + private note
TICKET_RESP=$(curl -s -X POST "${BASE}/tickets?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"customer_id": ${CUST_ID},
"subject": "<subject matching estimate name>",
"problem_type": "Hardware",
"status": "New",
"priority": "2 Normal",
"user_id": ${TECH_ID},
"do_not_email": true
}
JSON
)
TICKET_ID=$(echo "$TICKET_RESP" | jq -r '.ticket.id')
TICKET_NUM=$(echo "$TICKET_RESP" | jq -r '.ticket.number')
# Private note — hidden, with estimate link + product/source links
curl -s -X POST "${BASE}/tickets/${TICKET_ID}/comment?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"subject": "Estimate Links",
"body": "Estimate #${ESTIMATE_NUM}: https://computerguru.syncromsp.com/estimates/${ESTIMATE_ID}<br><source link description>: <URL><br><cost breakdown>",
"hidden": true,
"do_not_email": true
}
JSON
# Step 4 — Link estimate to ticket + touch to recalculate total
curl -s -X PUT "${BASE}/estimates/${ESTIMATE_ID}?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{"ticket_id": ${TICKET_ID}}
JSON
# GET estimate (verify total recalculated)
curl -s "${BASE}/estimates/${ESTIMATE_ID}?api_key=${API_KEY}" | \
jq '{id: .estimate.id, number: .estimate.number, total: .estimate.total,
lines: [.estimate.line_items[]? | {id, item, name, quantity, price}]}'
@@ -636,11 +688,15 @@ curl -s -X DELETE "${BASE}/estimates/${ESTIMATE_ID}?api_key=${API_KEY}"
**GET /estimates line_items vs POST response:** GET returns `line_items` as an array on `.estimate.line_items[]`. POST `/line_items` returns the line item under `.line_item` (singular, not nested under estimate).
**Estimate total recalculation:** The `total` field on GET /estimates does not update automatically after line item changes. Always do a PUT on the estimate (even a no-op name update) to trigger recalculation, then re-fetch to verify.
**Hardware on estimates:** All hardware line items use a single generic product — `product_id: 32252` ("Hardware", `price_retail: 0.0`). The specific item name and price are set per-line-item via the `name` and `price_retail` fields on each line. Never look up a separate product ID for hardware items on estimates — always use `32252` and vary the description and price per item.
**Hardware line item price bug (verified 2026-05-22):** POST `/estimates/{id}/line_items` ignores `price_retail` for product 32252 — the line item is created at $0. Always follow POST with a PUT to `/estimates/{id}/line_items/{li_id}` passing both `price` and `price_retail`. The PUT succeeds and sets the price correctly.
```bash
# Example hardware line item on an estimate
curl -s -X POST "${BASE}/estimates/${ESTIMATE_ID}/line_items?api_key=${API_KEY}" \
# Example hardware line item on an estimate (POST + required price fix PUT)
LI_RESP=$(curl -s -X POST "${BASE}/estimates/${ESTIMATE_ID}/line_items?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
@@ -652,6 +708,15 @@ curl -s -X POST "${BASE}/estimates/${ESTIMATE_ID}/line_items?api_key=${API_KEY}"
"taxable": true
}
JSON
)
LI_ID=$(echo "$LI_RESP" | jq -r '.line_item.id')
# Required: fix price via PUT
curl -s -X PUT "${BASE}/estimates/${ESTIMATE_ID}/line_items/${LI_ID}?api_key=${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{"price": 649.00, "price_retail": 649.00}
JSON
```
### Display formatting
@@ -803,6 +868,9 @@ echo "$ALERT_OUT"
|---|---|
| Ticket (create / update / close / comment / bill) | `https://computerguru.syncromsp.com/tickets/<ticket.id>` |
| Customer (create) | `https://computerguru.syncromsp.com/customers/<customer.id>` |
| Estimate (create) | `https://computerguru.syncromsp.com/estimates/<estimate.id>` |
**Estimate alert — single post with both links:** When creating an estimate, send ONE alert after all four steps complete (estimate + line items + ticket + link). Include both the ticket link and estimate link in a single message.
**Examples:**
@@ -812,6 +880,10 @@ bash "$CLAUDETOOLS_ROOT/.claude/scripts/post-bot-alert.sh" \
"[SYNCRO] Howard created #32301 (Desert Auto Tech) - Server won't boot -> https://computerguru.syncromsp.com/tickets/110736645"
# Success output: [OK] post-bot-alert: posted to #bot-alerts (message_id=1507055781780918404)
# Estimate created (single alert, both links)
bash "$CLAUDETOOLS_ROOT/.claude/scripts/post-bot-alert.sh" \
"[SYNCRO] Mike created estimate #7188 (Arizona Computer Guru) - ASUS V500 i7 Workstation \$849.99 | ticket #32316 -> https://computerguru.syncromsp.com/tickets/110843061 | https://computerguru.syncromsp.com/estimates/23967407"
# Billed + invoiced
bash "$CLAUDETOOLS_ROOT/.claude/scripts/post-bot-alert.sh" \
"[SYNCRO] Mike billed #32164 (Jerry Burger) - 1.0h remote, \$150.00 -> https://computerguru.syncromsp.com/tickets/110169036"