Merge branch 'v20260203-09-autotask-resolution-from-note' into main
This commit is contained in:
commit
ce245f7d49
@ -1 +1 @@
|
|||||||
v20260203-08-autotask-ticketnote-timezone-suffix
|
v20260203-09-autotask-resolution-from-note
|
||||||
|
|||||||
@ -558,6 +558,80 @@ class AutotaskClient:
|
|||||||
return {"id": tid}
|
return {"id": tid}
|
||||||
|
|
||||||
|
|
||||||
|
def update_ticket_resolution(self, ticket_id: int, resolution_text: str) -> Dict[str, Any]:
|
||||||
|
"""Update a Ticket's `resolution` field via PUT /Tickets.
|
||||||
|
|
||||||
|
This follows the validated contract in `autotask_rest_api_postman_test_contract.md`:
|
||||||
|
- Always GET /Tickets/{id} first
|
||||||
|
- PUT /Tickets is a full update, so we copy stabilising fields and change only `resolution`
|
||||||
|
- Status must remain unchanged during the resolution write
|
||||||
|
|
||||||
|
Raises AutotaskError on validation failures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
tid = int(ticket_id)
|
||||||
|
except Exception:
|
||||||
|
tid = 0
|
||||||
|
if tid <= 0:
|
||||||
|
raise AutotaskError("Invalid ticket id.")
|
||||||
|
|
||||||
|
res_txt = str(resolution_text or "")
|
||||||
|
if not res_txt.strip():
|
||||||
|
raise AutotaskError("Resolution text is empty.")
|
||||||
|
|
||||||
|
t = self.get_ticket(tid)
|
||||||
|
if not isinstance(t, dict):
|
||||||
|
raise AutotaskError("Autotask did not return a ticket object.")
|
||||||
|
|
||||||
|
stabilising_fields = [
|
||||||
|
"id",
|
||||||
|
"companyID",
|
||||||
|
"queueID",
|
||||||
|
"title",
|
||||||
|
"priority",
|
||||||
|
"status",
|
||||||
|
"dueDateTime",
|
||||||
|
"ticketCategory",
|
||||||
|
"issueType",
|
||||||
|
"subIssueType",
|
||||||
|
"source",
|
||||||
|
"organizationalLevelAssociationID",
|
||||||
|
]
|
||||||
|
|
||||||
|
missing = [f for f in stabilising_fields if t.get(f) in (None, "")]
|
||||||
|
if missing:
|
||||||
|
raise AutotaskError(
|
||||||
|
"Cannot safely update ticket resolution because required fields are missing: " + ", ".join(missing)
|
||||||
|
)
|
||||||
|
|
||||||
|
existing = str(t.get("resolution") or "")
|
||||||
|
if existing.strip():
|
||||||
|
if res_txt.strip() in existing:
|
||||||
|
new_res = existing
|
||||||
|
else:
|
||||||
|
new_res = existing.rstrip() + "\n\n" + res_txt
|
||||||
|
else:
|
||||||
|
new_res = res_txt
|
||||||
|
|
||||||
|
payload: Dict[str, Any] = {k: t.get(k) for k in stabilising_fields}
|
||||||
|
# Ensure numeric ID is an int for PUT.
|
||||||
|
payload["id"] = int(t.get("id"))
|
||||||
|
# Explicitly keep status unchanged.
|
||||||
|
payload["status"] = t.get("status")
|
||||||
|
payload["resolution"] = new_res
|
||||||
|
|
||||||
|
self.update_ticket(payload)
|
||||||
|
|
||||||
|
# Verify persistence.
|
||||||
|
t2 = self.get_ticket(tid)
|
||||||
|
persisted = str((t2 or {}).get("resolution") or "")
|
||||||
|
if res_txt.strip() not in persisted:
|
||||||
|
raise AutotaskError("Ticket resolution update returned success, but verification failed.")
|
||||||
|
|
||||||
|
return {"id": tid, "resolution_updated": True}
|
||||||
|
|
||||||
|
|
||||||
def create_ticket_note(self, note_payload: Dict[str, Any]) -> Dict[str, Any]:
|
def create_ticket_note(self, note_payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""Create a user-visible note on a Ticket.
|
"""Create a user-visible note on a Ticket.
|
||||||
|
|
||||||
|
|||||||
@ -1914,6 +1914,17 @@ def api_run_checks_autotask_resolve_note():
|
|||||||
}
|
}
|
||||||
), 400
|
), 400
|
||||||
|
|
||||||
|
# Also write the same information into the Ticket resolution field (validated safe update pattern).
|
||||||
|
try:
|
||||||
|
client.update_ticket_resolution(ticket_id, body)
|
||||||
|
except Exception as exc:
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Resolve note was created, but updating the ticket resolution field failed: {exc}",
|
||||||
|
}
|
||||||
|
), 400
|
||||||
|
|
||||||
return jsonify({"status": "ok", "message": "Resolve note posted to Autotask ticket."})
|
return jsonify({"status": "ok", "message": "Resolve note posted to Autotask ticket."})
|
||||||
|
|
||||||
except AutotaskError as exc:
|
except AutotaskError as exc:
|
||||||
@ -1982,6 +1993,18 @@ def api_run_checks_autotask_resolve_note():
|
|||||||
}
|
}
|
||||||
), 400
|
), 400
|
||||||
|
|
||||||
|
# Also write the same information into the Ticket resolution field (validated safe update pattern).
|
||||||
|
try:
|
||||||
|
client.update_ticket_resolution(ticket_id, body)
|
||||||
|
except Exception as exc:
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Ticket note creation is not supported (HTTP 404) and the marker was appended to the description, "
|
||||||
|
f"but updating the ticket resolution field failed: {exc}",
|
||||||
|
}
|
||||||
|
), 400
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
|
|||||||
@ -505,6 +505,13 @@ Changes:
|
|||||||
- Updated Autotask ticket note timestamps to use the configured Backupchecks timezone instead of UTC.
|
- Updated Autotask ticket note timestamps to use the configured Backupchecks timezone instead of UTC.
|
||||||
- Added a timezone suffix to the timestamp in the ticket note (e.g. Europe/Amsterdam).
|
- Added a timezone suffix to the timestamp in the ticket note (e.g. Europe/Amsterdam).
|
||||||
- Ensured all user-visible timestamps written to Autotask follow the timezone setting from Backupchecks.
|
- Ensured all user-visible timestamps written to Autotask follow the timezone setting from Backupchecks.
|
||||||
|
|
||||||
|
## v20260203-09-autotask-resolution-from-note
|
||||||
|
|
||||||
|
- When posting an Autotask “marked as resolved” note, the same text is now also written to the Ticket resolution field.
|
||||||
|
- Resolution updates follow the validated safe pattern: GET the current Ticket first, then PUT with stabilising fields while keeping the status unchanged.
|
||||||
|
- Added verification to ensure the resolution text is persisted after the update.
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
## v0.1.21
|
## v0.1.21
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user