diff --git a/backend/app/services/assistant_chat_service.py b/backend/app/services/assistant_chat_service.py index 184fd744..1e8a5e04 100644 --- a/backend/app/services/assistant_chat_service.py +++ b/backend/app/services/assistant_chat_service.py @@ -154,6 +154,23 @@ To create a fork, append this marker AFTER your [QUESTIONS]/[ACTIONS] markers: - If a question is clearly outside your domain, say so briefly and redirect. - Never fabricate error codes, KB article numbers, or CLI flags. If unsure, say so. +## SPIN-OFF TICKET CREATION + +When you identify a second distinct issue that is clearly separate from the primary topic \ +of this session, suggest creating a spin-off ticket using the [ACTIONS] marker below. \ +Use this sparingly — only when the issue is genuinely independent, not for every tangential mention. + +Format: +[ACTIONS] +[ + { + "label": "Create ticket: ", + "command": "create_spin_off_ticket", + "description": "" + } +] +[/ACTIONS] + ## FINAL REMINDER — THIS OVERRIDES EVERYTHING ABOVE Every single response MUST contain [QUESTIONS] and/or [ACTIONS] markers with valid JSON. \ No exceptions. Not even when forking. A response without at least one of these markers \ diff --git a/backend/tests/test_psa_tickets.py b/backend/tests/test_psa_tickets.py new file mode 100644 index 00000000..ac551373 --- /dev/null +++ b/backend/tests/test_psa_tickets.py @@ -0,0 +1,55 @@ +# backend/tests/test_psa_tickets.py +"""Routing and auth tests for new ticket management endpoints.""" +import pytest + + +@pytest.mark.asyncio +async def test_create_ticket_requires_auth(client): + """POST /tickets returns 401 without auth.""" + response = await client.post( + "/api/v1/integrations/psa/tickets", + json={ + "summary": "Test", "company_id": 1, "board_id": 1, + "status_id": 1, "priority_id": 1 + }, + ) + assert response.status_code == 401 + + +@pytest.mark.asyncio +async def test_list_resources_requires_auth(client): + response = await client.get("/api/v1/integrations/psa/tickets/1/resources") + assert response.status_code == 401 + + +@pytest.mark.asyncio +async def test_search_tickets_returns_paginated_shape(client, auth_headers): + """search endpoint returns TicketListResponse shape when no PSA connected.""" + response = await client.get( + "/api/v1/integrations/psa/tickets/search", + headers=auth_headers, + ) + # No PSA connection → 400 or 502; with PSA → 200 + assert response.status_code in (200, 400, 502) + if response.status_code == 200: + data = response.json() + assert "items" in data + assert "total" in data + assert "page" in data + + +@pytest.mark.asyncio +async def test_update_status_requires_auth(client): + response = await client.patch( + "/api/v1/integrations/psa/tickets/1/status?status_id=5" + ) + assert response.status_code == 401 + + +@pytest.mark.asyncio +async def test_ai_parse_requires_auth(client): + response = await client.post( + "/api/v1/integrations/psa/tickets/ai-parse", + json={"prompt": "New ticket for Acme"}, + ) + assert response.status_code == 401