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 <noreply@anthropic.com>
This commit is contained in:
@@ -387,8 +387,8 @@ async def search_tickets(
|
|||||||
from app.services.psa.registry import get_provider_for_account
|
from app.services.psa.registry import get_provider_for_account
|
||||||
from app.services.psa.exceptions import PSAError
|
from app.services.psa.exceptions import PSAError
|
||||||
|
|
||||||
# Resolve assigned_to_me → member_id
|
# Resolve assigned_to_me → member_identifier (CW login name for resources contains filter)
|
||||||
member_id: str | None = None
|
member_identifier: str | None = None
|
||||||
if assigned_to_me:
|
if assigned_to_me:
|
||||||
conn_result = await db.execute(
|
conn_result = await db.execute(
|
||||||
select(PsaConnection).where(
|
select(PsaConnection).where(
|
||||||
@@ -405,12 +405,23 @@ async def search_tickets(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
mapping = mapping_result.scalar_one_or_none()
|
mapping = mapping_result.scalar_one_or_none()
|
||||||
if mapping:
|
if not mapping:
|
||||||
member_id = mapping.external_member_id
|
|
||||||
else:
|
|
||||||
# No mapping for this user — return empty list
|
# No mapping for this user — return empty list
|
||||||
return []
|
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
|
# Parse comma-separated board_ids
|
||||||
parsed_board_ids: list[int] = []
|
parsed_board_ids: list[int] = []
|
||||||
if board_ids:
|
if board_ids:
|
||||||
@@ -426,7 +437,7 @@ async def search_tickets(
|
|||||||
board_id=board_id,
|
board_id=board_id,
|
||||||
status_id=status_id,
|
status_id=status_id,
|
||||||
include_closed=include_closed,
|
include_closed=include_closed,
|
||||||
member_id=member_id,
|
member_identifier=member_identifier,
|
||||||
unassigned=unassigned,
|
unassigned=unassigned,
|
||||||
board_ids=parsed_board_ids,
|
board_ids=parsed_board_ids,
|
||||||
page=page,
|
page=page,
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ class ConnectWiseProvider(PSAProvider):
|
|||||||
conditions.append(f"status/id = {filters['status_id']}")
|
conditions.append(f"status/id = {filters['status_id']}")
|
||||||
if not filters.get("include_closed", False):
|
if not filters.get("include_closed", False):
|
||||||
conditions.append("closedFlag = false")
|
conditions.append("closedFlag = false")
|
||||||
if filters.get("member_id") is not None:
|
if filters.get("member_identifier") is not None:
|
||||||
conditions.append(f"resources/member/id = {filters['member_id']}")
|
conditions.append(f"resources contains '{filters['member_identifier']}'")
|
||||||
if filters.get("unassigned", False):
|
if filters.get("unassigned", False):
|
||||||
conditions.append("resources = null")
|
conditions.append("resources = null")
|
||||||
board_ids: list[int] = filters.get("board_ids") or []
|
board_ids: list[int] = filters.get("board_ids") or []
|
||||||
|
|||||||
Reference in New Issue
Block a user