From 08a4c6600d121744ea891bb857a4c1abdb6ffd73 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Wed, 15 Apr 2026 03:53:26 +0000 Subject: [PATCH] fix(psa): use resources contains identifier for my tickets filter CW resources field is a plain string of member identifiers (login names), not a navigable object. resources/member/id was invalid syntax causing 403. Now resolves the CW member identifier from the cached member list and uses: resources contains '{identifier}' which is the correct condition. Co-Authored-By: Claude Sonnet 4.6 --- backend/app/api/endpoints/integrations.py | 23 ++++++++++++++----- .../app/services/psa/connectwise/provider.py | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/backend/app/api/endpoints/integrations.py b/backend/app/api/endpoints/integrations.py index 4cd08052..34152019 100644 --- a/backend/app/api/endpoints/integrations.py +++ b/backend/app/api/endpoints/integrations.py @@ -387,8 +387,8 @@ async def search_tickets( from app.services.psa.registry import get_provider_for_account from app.services.psa.exceptions import PSAError - # Resolve assigned_to_me → member_id - member_id: str | None = None + # Resolve assigned_to_me → member_identifier (CW login name for resources contains filter) + member_identifier: str | None = None if assigned_to_me: conn_result = await db.execute( select(PsaConnection).where( @@ -405,12 +405,23 @@ async def search_tickets( ) ) mapping = mapping_result.scalar_one_or_none() - if mapping: - member_id = mapping.external_member_id - else: + if not mapping: # No mapping for this user — return empty list return [] + from app.services.psa.registry import get_provider_for_account as _get_provider + from app.services.psa.exceptions import PSAError as _PSAError + try: + _provider = await _get_provider(current_user.account_id, db) + cw_members = await _provider.list_members() + matched = next((m for m in cw_members if m.id == mapping.external_member_id), None) + if matched: + member_identifier = matched.identifier + else: + return [] + except _PSAError: + return [] + # Parse comma-separated board_ids parsed_board_ids: list[int] = [] if board_ids: @@ -426,7 +437,7 @@ async def search_tickets( board_id=board_id, status_id=status_id, include_closed=include_closed, - member_id=member_id, + member_identifier=member_identifier, unassigned=unassigned, board_ids=parsed_board_ids, page=page, diff --git a/backend/app/services/psa/connectwise/provider.py b/backend/app/services/psa/connectwise/provider.py index ca2c473d..49281818 100644 --- a/backend/app/services/psa/connectwise/provider.py +++ b/backend/app/services/psa/connectwise/provider.py @@ -78,8 +78,8 @@ class ConnectWiseProvider(PSAProvider): conditions.append(f"status/id = {filters['status_id']}") if not filters.get("include_closed", False): conditions.append("closedFlag = false") - if filters.get("member_id") is not None: - conditions.append(f"resources/member/id = {filters['member_id']}") + if filters.get("member_identifier") is not None: + conditions.append(f"resources contains '{filters['member_identifier']}'") if filters.get("unassigned", False): conditions.append("resources = null") board_ids: list[int] = filters.get("board_ids") or []