diff --git a/.last-branch b/.last-branch index 1bd40ee..882b180 100644 --- a/.last-branch +++ b/.last-branch @@ -1 +1 @@ -v20260120-06-routes-inbox-indent-fix +v20260120-07-autotask-psa-resolution-handling diff --git a/containers/backupchecks/src/backend/app/main/routes_run_checks.py b/containers/backupchecks/src/backend/app/main/routes_run_checks.py index ce3acb8..3fd2370 100644 --- a/containers/backupchecks/src/backend/app/main/routes_run_checks.py +++ b/containers/backupchecks/src/backend/app/main/routes_run_checks.py @@ -115,7 +115,7 @@ def _resolve_internal_ticket_for_job( if ticket.resolved_at is None: ticket.resolved_at = now - if getattr(ticket, "resolved_origin", None) is None: + if not (getattr(ticket, "resolved_origin", None) or "").strip(): ticket.resolved_origin = origin # Resolve all still-open scopes. @@ -420,12 +420,33 @@ def _poll_autotask_ticket_states_for_runs(*, run_ids: list[int]) -> None: ) # If terminal in PSA: resolve internally. - if internal_ticket is not None and status_int in AUTOTASK_TERMINAL_STATUS_IDS: + resolved_at = None + try: + if isinstance(t, dict): + resolved_at_raw = t.get("resolvedDateTime") or t.get("completedDate") or t.get("completedDateTime") + else: + resolved_at_raw = None + if resolved_at_raw: + s = str(resolved_at_raw).replace("Z", "+00:00") + resolved_at = datetime.fromisoformat(s) + if resolved_at.tzinfo is not None: + resolved_at = resolved_at.astimezone(timezone.utc).replace(tzinfo=None) + except Exception: + resolved_at = None + + is_terminal = False + if status_int in AUTOTASK_TERMINAL_STATUS_IDS: + is_terminal = True + if resolved_at is not None: + is_terminal = True + + if internal_ticket is not None and is_terminal: _resolve_internal_ticket_for_job( ticket=internal_ticket, job=job, run_ids=[int(x.id) for x in runs_for_ticket if getattr(x, "id", None)], - now=now, + now=resolved_at or now, + origin="Resolved by PSA", ) try: diff --git a/docs/changelog.md b/docs/changelog.md index 21ced4f..fe83e04 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -408,6 +408,20 @@ Changes: - Repaired indentation of link_open_internal_tickets_to_run logic to prevent runtime exceptions. - Restored application startup stability by resolving Python IndentationError issues. +## v20260120-07-autotask-psa-resolution-handling + +- Added support for linking existing Autotask tickets (Phase 2.2) using Autotask REST queries. +- Implemented ticket listing by company with exclusion of terminal tickets (status != Complete). +- Added search support for existing tickets by exact ticketNumber and by title (contains). +- Implemented authoritative validation of selected Autotask tickets via GET /Tickets/{id}. +- Defined terminal ticket detection based on: + - status == Complete (5) + - OR completedDate is set + - OR resolvedDateTime is set. +- Ensured terminal Autotask tickets automatically resolve the corresponding internal Backupchecks ticket. +- Preserved legacy internal Ticket and TicketJobRun creation/linking so Tickets overview, Tickets/Remarks, and Job Details continue to function identically to manually linked tickets. +- Ensured resolution timestamps are derived from Autotask (resolvedDateTime / completedDate) instead of using current time. + *** ## v0.1.21