feat(psa): implement post_note and update_ticket_status in CW provider
Replaces NotImplementedError stubs with working implementations: - post_note maps note_type to CW flag fields (internalAnalysisFlag, resolutionFlag, detailDescriptionFlag) with appropriate visibility and notification settings - update_ticket_status uses CW JSON Patch format to update status Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -155,7 +155,7 @@ class ConnectWiseProvider(PSAProvider):
|
|||||||
status=data.get("status", {}).get("name") if data.get("status") else None,
|
status=data.get("status", {}).get("name") if data.get("status") else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── Stubs for later slices ────────────────────────────────────────
|
# ── Notes & status updates ───────────────────────────────────────
|
||||||
|
|
||||||
async def post_note(
|
async def post_note(
|
||||||
self,
|
self,
|
||||||
@@ -164,12 +164,71 @@ class ConnectWiseProvider(PSAProvider):
|
|||||||
note_type: str,
|
note_type: str,
|
||||||
member_id: str | None = None,
|
member_id: str | None = None,
|
||||||
) -> PSANote:
|
) -> PSANote:
|
||||||
raise NotImplementedError("Implemented in Slice 4")
|
"""Post a note to a CW ticket.
|
||||||
|
|
||||||
|
Maps ResolutionFlow note types to CW flag fields:
|
||||||
|
- internal_analysis → internalAnalysisFlag (internal only)
|
||||||
|
- resolution → resolutionFlag (internal, triggers notifications)
|
||||||
|
- description → detailDescriptionFlag (external, triggers notifications)
|
||||||
|
"""
|
||||||
|
from app.services.psa.types import NoteType
|
||||||
|
|
||||||
|
flags = {
|
||||||
|
NoteType.INTERNAL_ANALYSIS: {
|
||||||
|
"internalAnalysisFlag": True,
|
||||||
|
"resolutionFlag": False,
|
||||||
|
"detailDescriptionFlag": False,
|
||||||
|
"internalFlag": True,
|
||||||
|
"processNotifications": False,
|
||||||
|
},
|
||||||
|
NoteType.RESOLUTION: {
|
||||||
|
"internalAnalysisFlag": False,
|
||||||
|
"resolutionFlag": True,
|
||||||
|
"detailDescriptionFlag": False,
|
||||||
|
"internalFlag": True,
|
||||||
|
"processNotifications": True,
|
||||||
|
},
|
||||||
|
NoteType.DESCRIPTION: {
|
||||||
|
"internalAnalysisFlag": False,
|
||||||
|
"resolutionFlag": False,
|
||||||
|
"detailDescriptionFlag": True,
|
||||||
|
"internalFlag": False,
|
||||||
|
"processNotifications": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
note_flags = flags.get(note_type, flags[NoteType.INTERNAL_ANALYSIS])
|
||||||
|
|
||||||
|
body: dict = {
|
||||||
|
"text": text,
|
||||||
|
**note_flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
if member_id:
|
||||||
|
body["member"] = {"id": int(member_id)}
|
||||||
|
|
||||||
|
data = await self.client.post(
|
||||||
|
f"/service/tickets/{ticket_id}/notes", json_body=body
|
||||||
|
)
|
||||||
|
|
||||||
|
return PSANote(
|
||||||
|
id=str(data.get("id", "")),
|
||||||
|
text=data.get("text", ""),
|
||||||
|
note_type=note_type,
|
||||||
|
created_at=data.get("dateCreated"),
|
||||||
|
)
|
||||||
|
|
||||||
async def update_ticket_status(
|
async def update_ticket_status(
|
||||||
self, ticket_id: str, status_id: int
|
self, ticket_id: str, status_id: int
|
||||||
) -> PSATicket:
|
) -> PSATicket:
|
||||||
raise NotImplementedError("Implemented in Slice 4")
|
"""Update a CW ticket's status using JSON Patch format."""
|
||||||
|
patch_body = [
|
||||||
|
{"op": "replace", "path": "status", "value": {"id": status_id}}
|
||||||
|
]
|
||||||
|
data = await self.client.patch(
|
||||||
|
f"/service/tickets/{ticket_id}", json_body=patch_body
|
||||||
|
)
|
||||||
|
return self._map_ticket(data)
|
||||||
|
|
||||||
async def list_members(self) -> list[PSAMember]:
|
async def list_members(self) -> list[PSAMember]:
|
||||||
raise NotImplementedError("Implemented in Slice 5")
|
raise NotImplementedError("Implemented in Slice 5")
|
||||||
|
|||||||
Reference in New Issue
Block a user