This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.
Ticket Tracking in FreshDesk
The first use case in the FreshDesk business scenario is ticket tracking, which involves ticket assignment, ticket resolution and ticket closure. This page describes the relevant tasks and the operations you use in the FreshDesk connector and the other ESB connectors.
Overview
The flow for ticket tracking is illustrated in the following diagram. We will use the ESB connectors for Nexmo, ActiveCollab, Gmail and SurveyGizmo to connect to each service. ActiveCollab is a strong Project Management tool that can be used throughout the project life cycle, which allows keeping track of tasks. Gmail can be used to send e-mails or reminders as e-mails to relevant people.Â
Prerequisite
As an offline process, create a ticket in FreshDesk to proceed with ticket assignment.
Ticket Assignment
In ticket assignment, you retrieve tickets and their notes, and then create the notes as tasks in ActiveCollab. Once you create the tasks, you need to send an e-mail to the assignee via Gmail.Â
- Retrieve assigned tickets from FreshDesk using getTicket.Â
- Retrieve details of the assignee of the ticket from FreshDesk using getUser.Â
- Send an SMS with the ticket assignment details to the assignee of the ticket via Nexmo using sendMessage. The updateTicket operation in FreshDesk can be used to update theÂ
smsAlertSent
custom field of the ticket. - In ActiveCollab, create a new task under a specific project with the details of the FreshDesk ticket's note, using createTask.
- Send an e-mail to the assignee via Gmail using sendMail to inform about the new task added in ActiveCollab.
FreshDesk operations
ActiveCollab operations
Gmail operations
Nexmo operations
Samples
<?xml version="1.0" encoding="UTF-8"?> <proxy xmlns="http://ws.apache.org/ns/synapse" name="freshdesk_ticketAssignment" transports="https,http" statistics="disable" trace="disable" startOnLoad="true"> <target> <inSequence onError="faultHandlerSeq"> <!--Freshdesk Properties--> <property name="freshdesk.apiUrl" expression="json-eval($.freshdeskApiUrl)" /> <property name="freshdesk.apiKey" expression="json-eval($.freshdeskApiKey)" /> <!--Nexmo Properties--> <property name="nexmo.apiUrl" expression="json-eval($.nexmoApiUrl)" /> <property name="nexmo.apiSecret" expression="json-eval($.nexmoApiSecret)" /> <property name="nexmo.apiKey" expression="json-eval($.nexmoApiKey)" /> <!--ActiveCollab Properties--> <property name="activeCollab.apiUrl" expression="json-eval($.activeCollabApiUrl)" /> <property name="activeCollab.apiToken" expression="json-eval($.activeCollabApiToken)" /> <property name="activeCollab.projectId" expression="json-eval($.activeCollabProjectId)" /> <!--Gmail Properties--> <property name="gmail.username" expression="json-eval($.gmailUsername)" /> <property name="gmail.oAuthAccessToken" expression="json-eval($.gmailOAuthAccessToken)" /> <!--Common Properties--> <property name="resendSms" expression="json-eval($.resendSms)" /> <property name="responseString" value="" scope="operation" /> <property name="processName" value="freshdesk_ticketAssignment" scope="operation" /> <property name="activityName" value="freshdesk_sendTaskNotificationViaGmail" scope="operation" /> <!--If the user didn't mention about the user's preference for resending the SMS to those who have already received one, set "resendSms" as "false".--> <filter source="get-property('resendSms')" regex="true"> <then> <property name="resendSms" value="true" type="BOOLEAN" /> </then> <else> <property name="resendSms" value="false" type="BOOLEAN" /> </else> </filter> <!--Getting the count of the ticket IDs that the user passed--> <property name="ticketIdsCount" expression="count(//jsonObject/freshdeskTicketIds)" scope="operation" /> <property name="ticketIdIndex" expression="0" scope="operation" /> <!-- Checking whether the user provided at least one ticketId in order to fetch their details--> <filter xpath="get-property('operation', 'ticketIdsCount') = get-property('operation', 'ticketIdIndex')"> <!--If the user didn't provide at least one ticket ID to process, display a custom error message.--> <then> <property name="id" value="{}" /> <property name="message" value="No ticket Ids are provided in order to notify the assignees. Please provide at least one ticket Id." /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicket" /> <with-param name="status" value="Error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </then> <else> <!--Iterate through all the ticket IDs taken from the array.--> <iterate continueParent="true" id="ticketIdIterator" preservePayload="true" expression="//jsonObject/freshdeskTicketIds" sequential="true"> <target> <sequence> <!--Retrieving one ticket at a time from the ticketId array.--> <property name="freshdesk.ticketId" expression="//freshdeskTicketIds/text()" /> <freshdesk.init> <apiUrl>{$ctx:freshdesk.apiUrl}</apiUrl> <apiKey>{$ctx:freshdesk.apiKey}</apiKey> <format>json</format> </freshdesk.init> <freshdesk.getTicket> <id>{$ctx:freshdesk.ticketId}</id> </freshdesk.getTicket> <property name="freshdeskSmsAlertSent" expression="//jsonObject/helpdesk_ticket/custom_field/*[fn:starts-with(local-name(), 'smsalertsent')]/text()" /> <property name="freshdeskCustomFieldName" expression="name(//jsonObject/helpdesk_ticket/custom_field/*[fn:starts-with(local-name(), 'smsalertsent')])" /> <!---Extract the custom field value of the property.--> <property name="responseId" expression="json-eval($.helpdesk_ticket.id)" /> <!--Checking the existence of the ticket--> <filter source="boolean(get-property('responseId'))" regex="false"> <!-- If error occurred, display the API error message along with a custom generated error.--> <then> <property name="apiErrorResponse" expression="json-eval($.errors.error)" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Failed to retrieve the ticket: ', get-property('apiErrorResponse'))" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicket" /> <with-param name="status" value="Error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If successful, check the status of the ticket.--> <else> <property name="ticketStatus" expression="json-eval($.helpdesk_ticket.status_name)" /> <!--Checking the status of the ticket--> <filter xpath="get-property('ticketStatus') = 'Closed' or get-property('ticketStatus') = 'Resolved'"> <!--If the ticket is already Resolved or Closed, display a custom message informing that those tickets will be skipped by notifying the assignees.--> <then> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Failed to send notification to the assignee since the ticket is already ', get-property('ticketStatus'))" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicketAndNotifyAssignee" /> <with-param name="status" value="Skipped" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If the ticket is still pending to be resolved--> <else> <!--Retrieve required details of the ticket.--> <property name="ticketSubject" expression="json-eval($.helpdesk_ticket.subject)" /> <property name="ticketDueBy" expression="json-eval($.helpdesk_ticket.due_by)" /> <property name="ticketPriority" expression="json-eval($.helpdesk_ticket.priority)" /> <property name="ticketPriorityName" expression="json-eval($.helpdesk_ticket.priority_name)" /> <property name="assigneeId" expression="json-eval($.helpdesk_ticket.responder_id)" /> <property name="assigneeName" expression="json-eval($.helpdesk_ticket.responder_name)" /> <property name="ticketNotesCount" expression="count(//jsonObject/helpdesk_ticket/notes)" scope="operation" /> <property name="ticketNoteBody" expression="json-eval($.helpdesk_ticket.notes[1].note.body)" /> <!--Checking the existence of the assignee--> <filter source="boolean(get-property('assigneeId'))" regex="false"> <!--If the ticket is not assigned to anyone, display a custom error message.--> <then> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Failed to send notification to the assignee since the ticket is not assigned to anyone.')" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicketAndNotifyAssignee" /> <with-param name="status" value="Skipped" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If there is an assignee, retrieve the details of the assignee.--> <else> <freshdesk.init> <apiKey>{$ctx:freshdesk.apiKey}</apiKey> <apiUrl>{$ctx:freshdesk.apiUrl}</apiUrl> <format>json</format> </freshdesk.init> <freshdesk.getUser> <userId>{$ctx:assigneeId}</userId> </freshdesk.getUser> <property name="responseId" expression="json-eval($.user.id)" /> <!--Checking the existence of the assignee's details--> <filter source="boolean(get-property('responseId'))" regex="false"> <!--If an error occurred while retrieving the assignee's details, display an error message.--> <then> <property name="apiErrorResponse" expression="json-eval($.errors.error)" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Failed to retrieve the assignee details: ', get-property('apiErrorResponse'))" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getAssigneeDetails" /> <with-param name="status" value="Error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If the assignee's details are successfully retrieved, extract the e-mail address and the mobile number.--> <else> <property name="assigneeEmail" expression="json-eval($.user.email)" /> <property name="assigneeMobileNumber" expression="json-eval($.user.mobile)" /> <!--Checking the existence of the assignee's mobile number--> <filter source="boolean(get-property('assigneeMobileNumber'))" regex="false"> <!--If the mobile number is not set for the assignee, display a custom error message.--> <then> <property name="id" expression="fn:concat('freshdesk_assigneeId:', get-property('assigneeId'))" /> <property name="message" value="Failed to send SMS notification to the assignee since the mobile number is not set" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getAssigneeDetails" /> <with-param name="status" value="Skipped" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If the mobile number is set for the assignee, send a text message through Nexmo.--> <else> <!--Check whether a message has already been sent to the assignee about the ticket and whether the user wishes to resend the SMS to the assignees who have already received an SMS regarding the specific ticket.--> <filter xpath="get-property('freshdeskSmsAlertSent') != '' and not(get-property('resendSms'))"> <!--If the user requested not to resend the SMS, display a message indicating that the process has been skipped.--> <then> <property name="message" value="Failed to create task in ActiveCollab since the ticket does not have any notes" /> <!--Call the responseHandler template.--> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" value="Skipped to resend the text message to the assignee based on the user's preference." /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicketAndNotifyAssigneeViaSMS" /> <with-param name="status" value="Skipped" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If not, send the text message to the assignee.--> <else> <!--Construct the text message including the ticket details.--> <property name="textMessage" expression="fn:concat('Please note that the following ticket at Freshdesk is still not Resolved or Closed.\nTicket Id :', get-property('freshdesk.ticketId') , '\nSubject : ', get-property('ticketSubject'), '\nStatus : ', get-property('ticketStatus'), '\nDue By : ', fn:substring-before(get-property('ticketDueBy'), 'T') , '\nPriority : ', get-property('ticketPriorityName'))" /> <!--Call the template in order to send the text message from Nexmo to the assignee.--> <property name="nexmo.responseIds" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <call-template target="sendNotifications"> <with-param name="nexmo.apiUrl" value="{$ctx:nexmo.apiUrl}" /> <with-param name="nexmo.apiKey" value="{$ctx:nexmo.apiKey}" /> <with-param name="nexmo.apiSecret" value="{$ctx:nexmo.apiSecret}" /> <with-param name="nexmo.to" value="{$ctx:assigneeMobileNumber}" /> <with-param name="nexmo.from" value="Freshdesk" /> <with-param name="nexmo.text" value="{$ctx:textMessage}" /> <with-param name="nexmo.responseIds" value="{$ctx:nexmo.responseIds}" /> </call-template> <property name="responseStatus" expression="json-eval($.messages[0].status)" /> <!--Checking the status of the sent SMS--> <filter source="get-property('responseStatus')" regex="0"> <then> <property name="freshdesk.customFieldUpdate" expression="fn:concat('{ "', get-property('freshdeskCustomFieldName'), '" : "true" }')" /> <!--Update the Ticket in Freshdesk indicating that an SMS alert has been sent to the user.--> <freshdesk.init> <apiUrl>{$ctx:freshdesk.apiUrl}</apiUrl> <format>json</format> <apiKey>{$ctx:freshdesk.apiKey}</apiKey> </freshdesk.init> <freshdesk.updateTicket> <ticketId>{$ctx:freshdesk.ticketId}</ticketId> <customField>{$ctx:freshdesk.customFieldUpdate}</customField> </freshdesk.updateTicket> <property name="responseId" expression="json-eval($.ticket.display_id)" /> <!--Checking the existence of the diplay_id of the given ticket--> <filter source="boolean(get-property('responseId'))" regex="false"> <!--If an error had occurred, display the API error message along with a custom generated error.--> <then> <property name="apiErrorResponse" expression="json-eval($.errors.error)" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Failed to update the custom field [smsAlertSent] of the ticket: ', get-property('apiErrorResponse'))" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicket" /> <with-param name="status" value="Error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> </filter> <!--End of filter: Checking the existence of the diplay_id of the given ticket--> </then> </filter> <!--END of filter: Checking the status of the sent SMS--> </else> </filter> <!--END of filter: Checking the resendSms field--> </else> </filter> <!--END of filter: Checking the existence of the assignee's mobile number--> <!--Check whether the ticket has at least one note--> <property name="ticketNotesIndex" expression="0" scope="operation" /> <!--Checking the existence of notes in the ticket--> <filter xpath="get-property('operation', 'ticketNotesCount') = get-property('operation', 'ticketNotesIndex')"> <!--If the ticket does not have notes, then display a custom error message.--> <then> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" value="Failed to create task in ActiveCollab since the ticket does not have any notes" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="freshdesk_getTicketNoteAndCreateTaskInActiveCollab" /> <with-param name="status" value="Skipped" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!--If the ticket has any notes, get the very first note and add it to activeCollab as a task in the given project--> <else> <!--Priority Mapping: (Freshdesk,ActiveCollab) = (1,-1), (2,0), (3,1), (4,2)--> <switch source="get-property('ticketPriority')"> <case regex="1"> <property name="ticketPriority" value="-1" /> </case> <case regex="2"> <property name="ticketPriority" value="0" /> </case> <case regex="3"> <property name="ticketPriority" value="1" /> </case> <case regex="4"> <property name="ticketPriority" value="2" /> </case> </switch> <!--Creating the note of the ticket as a task in the given project in activeCollab--> <activecollab.init> <apiUrl>{$ctx:activeCollab.apiUrl}</apiUrl> <apiToken>{$ctx:activeCollab.apiToken}</apiToken> <format>json</format> </activecollab.init> <activecollab.createTask> <projectId>{$ctx:activeCollab.projectId}</projectId> <taskBody>{$ctx:ticketNoteBody}</taskBody> <name>{$ctx:ticketSubject}</name> <dueOn>{$ctx:ticketDueBy}</dueOn> <visibility>1</visibility> <priority>{$ctx:ticketPriority}</priority> </activecollab.createTask> <!--Check whether the repose returns an ID.--> <property name="responseId" expression="json-eval($.id)" /> <!--Checking the successful response of the created task--> <filter source="boolean(get-property('responseId'))" regex="false"> <!--In case an error occurs, display a custom generated error message.--> <then> <property name="apiErrorResponse" expression="json-eval($.field_errors.name)" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Failed to add note as a task in ActiveCollab: ', get-property('apiErrorResponse'))" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="activecollab_createTask" /> <with-param name="status" value="Error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <else> <property name="activecollab.taskId" expression="json-eval($.task_id)" /> <property name="activecollab.permalink" expression="json-eval($.permalink)" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" value="Successfully added the note of the ticket as a task in ActiveCollab." /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="activecollab_createTask" /> <with-param name="status" value="Success" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <!--Constructing the freshDeskTicketId custom field value--> <property name="activecollab.customFreshDeskTaskId" expression="fn:concat('[{"key":"custom_field_1","value":"',get-property('freshdesk.ticketId'),'"},{"key":"custom_field_2","value":"ID:',get-property('assigneeId'),'/ Email:',get-property('assigneeEmail'),'"}]')" /> <!--Update the activeCollab task's custom field "freshDeskTicketId" setting the ID of the ticket in FreshDesk.--> <activecollab.init> <apiUrl>{$ctx:activeCollab.apiUrl}</apiUrl> <apiToken>{$ctx:activeCollab.apiToken}</apiToken> <format>json</format> </activecollab.init> <activecollab.updateTask> <taskId>{$ctx:activecollab.taskId}</taskId> <projectId>{$ctx:activeCollab.projectId}</projectId> <customFields>{$ctx:activecollab.customFreshDeskTaskId}</customFields> </activecollab.updateTask> <property name="responseId" expression="json-eval($.id)" /> <!--Checking whether the task has been updated successfully--> <filter source="boolean(get-property('responseId'))" regex="false"> <then> <property name="apiErrorResponse" expression="json-eval($.field_errors.name)" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <property name="message" expression="fn:concat('Task is added in ActiveCollab. However failed to update the freshDeskTicket id: ', get-property('apiErrorResponse'))" /> <!--Call the responseHandler template.--> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="activecollab_createTask" /> <with-param name="status" value="Error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <!-- If the update is successful, retrieve the email of the ticket's assignee and send an email through Gmail.--> <else> <property name="emailSubject" value="Task created in ActiveCollab " /> <property name="emailMessage" expression="fn:concat('Hi ',get-property('assigneeName'),',Please note that a task is created in ActiveCollab for the ticket that you are assigned for. Find the details as below. Ticket Id :' , get-property('freshdesk.ticketId'), '; Link to the task in ActiveCollab: ', get-property('activecollab.permalink'))" /> <property name="responseIds" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <!--Send email notifications to responders.--> <call-template target="sendNotifications"> <with-param name="gmail.username" value="{$ctx:gmail.username}" /> <with-param name="gmail.oAuthAccessToken" value="{$ctx:gmail.oAuthAccessToken}" /> <with-param name="gmail.subject" value="{$ctx:emailSubject}" /> <with-param name="gmail.toRecipients" value="{$ctx:assigneeEmail}" /> <with-param name="gmail.textContent" value="{$ctx:emailMessage}" /> <with-param name="gmail.responseIds" value="{$ctx:responseIds}" /> </call-template> </else> </filter> <!--END of filter: Checking whether the task has been updated successfully--> </else> </filter> <!--END of filter: Checking the successful response of the created task--> </else> </filter> <!--END of filter: Checking the existence of notes in the ticket--> </else> </filter> <!--END of filter: Checking the existence of the assignee's details--> </else> </filter> <!--END of filter: Checking the existence of the assignee--> </else> </filter> <!--END of filter: Checking the status of the ticket--> </else> </filter> <!--END of filter: Checking the existence of the ticket--> <!--Increment the user count.--> <property name="ticketIdIndex" expression="get-property('operation', 'ticketIdIndex') + 1" scope="operation" /> </sequence> </target> </iterate> <!--END of the iterator: checking all the ticketIds--> </else> </filter> <!--END of filter: checking whether there are sufficient ticket IDs to process--> <!--FOR EACH User: END--> <filter xpath="get-property('operation', 'ticketIdsCount') = get-property('operation', 'ticketIdIndex')"> <then> <loopback /> </then> </filter> </inSequence> <outSequence> <property name="messageType" value="application/json" scope="axis2" /> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"freshdesk_ticketAssignment", "activityResponse": [$1] } }</format> <args> <arg expression="get-property('operation', 'responseString')" /> </args> </payloadFactory> <send /> </outSequence> </target> <description /> </proxy>
{ "freshdeskApiUrl":"https://scenario.freshdesk.com", "freshdeskApiKey":"BQR7RBSD7ybpPcUAz", "freshdeskTicketIds":["12"], "nexmoApiUrl":"https://rest.nexmo.com", "nexmoApiKey":"", "nexmoApiSecret":"", "resendSms" : true, "activeCollabApiUrl":"https://sam.manageprojects.com", "activeCollabApiToken":"1-FP9QEo95E6T5HmLh6RHWzDUiolKfmDqRioxMDvF8", "activeCollabProjectId":"3", "gmailUsername":"wso2connector.abdera@gmail.com", "gmailOAuthAccessToken":"ya29.2QBfAw8mMlHWFV4F72TcMUXxpHMljV2AEiKEXtmw1A3PzdmFTPjXeJJg2TraSMMava5__n5hRMEoHA" }
Ticket Resolution
In ticket completion, you resolve and close a ticket.Â
- Retrieve all tasks via ActiveCollab using listTasks.
- Retrieve details of a particular task via ActiveCollab using getTask.
- In ActiveCollab, mark the task as completed using completeContext.
- Retrieve details of a particular ticket via FreshDesk using getTicket.
- Retrieve details of a specific user via FreskDesk using getUser.Â
- In FreshDesk, update the ticket status toÂ
resolved
 using updateTicket. - In SurveyGizmo, update the survey to capture the feedback using updateSurvey and send it to the requester via Gmail using sendMail.
ActiveCollab operations
FreshDesk operations
SurveyGizmo operations
Gmail operations
Samples
<?xml version="1.0" encoding="UTF-8"?> <proxy xmlns="http://ws.apache.org/ns/synapse" name="freshdesk_resolveTicketsAndSendSurvey" transports="https,http" statistics="disable" trace="disable" startOnLoad="true"> <target> <inSequence onError="faultHandlerSeq"> <!--Freshdesk Properties--> <property name="freshdesk.apiUrl" expression="json-eval($.freshdeskApiUrl)" /> <property name="freshdesk.apiKey" expression="json-eval($.freshdeskApiKey)" /> <!--ActiveCollab Properties--> <property name="activecollab.apiUrl" expression="json-eval($.activecollabApiUrl)" /> <property name="activecollab.apiToken" expression="json-eval($.activecollabApiToken)" /> <!--SurveyGizmo Properties--> <property name="surveygizmo.apiUrl" expression="json-eval($.surveygizmoApiUrl)" /> <property name="surveygizmo.username" expression="json-eval($.surveygizmoUsername)" /> <property name="surveygizmo.password" expression="json-eval($.surveygizmoPassword)" /> <property name="surveygizmo.surveyId" expression="json-eval($.surveygizmoSurveyId)" /> <!--GMail Properties--> <property name="gmail.username" expression="json-eval($.gmailUsername)" /> <property name="gmail.oauthAccessToken" expression="json-eval($.gmailAauthAccessToken)" /> <!--Operation Scoped Properties--> <property name="activityName" value="freshdesk_sendSurveyToAssigneeViaGMAil" scope="operation" /> <property name="responseString" value="" scope="operation" /> <property name="noOfProjects" expression="count(//jsonObject/activecollabProjectTasks)" scope="operation" /> <property name="projectIndex" expression="0" scope="operation" /> <property name="noOfTasks" expression="0" scope="operation" /> <property name="taskIndex" expression="0" scope="operation" /> <!--If the activeCollabProjectTasks Map is empty, send an error message to the user and terminate the scenario.--> <filter xpath="get-property('operation', 'noOfProjects') = get-property('operation', 'projectIndex')"> <then> <payloadFactory media-type="json"> <format>{ "Response":{ "activity":"freshdesk_resolveTicketsAndSendSurvey", "activityResponse":"activecollabProjectTasks array is empty - No entries to process." } } </format> </payloadFactory> <respond /> </then> <else> <!--FOR EACH ProjectTask in activeCollabProjectTasks Map: BEGIN--> <iterate continueParent="false" id="projects" expression="//jsonObject/activecollabProjectTasks" sequential="true"> <target> <sequence> <!--Increment the Project Count by 1.--> <property name="projectIndex" expression="get-property('operation', 'projectIndex') + 1" scope="operation" /> <!--Store the ActiveCollab ProjectId.--> <property name="activecollab.projectId" expression="//activecollabProjectTasks/projectId/text()" /> <property name="activecollab.completeAllTasks" expression="//activecollabProjectTasks/completeAllTasks/text()" /> <!--START: If the user has specified (by providing the value "true") to close all the tasks in the particular project in ActiveCollab. --> <filter xpath="boolean(get-property('activecollab.completeAllTasks')) and fn:lower-case(get-property('activecollab.completeAllTasks')) = fn:lower-case('true')"> <then> <!--List all tasks in a particular project in ActiveCollab.--> <activecollab.init> <apiUrl>{$ctx:activecollab.apiUrl}</apiUrl> <apiToken>{$ctx:activecollab.apiToken}</apiToken> <format>json</format> </activecollab.init> <activecollab.listTasks> <projectId>{$ctx:activecollab.projectId}</projectId> </activecollab.listTasks> <sequence key="removeResponseHeaders" /> <!--No. of tasks in the project--> <property name="tasksReturned" expression="count(//jsonArray/jsonElement)" /> <!--START: Proceed only if there are any tasks in the ActiveCollab project.--> <filter xpath="get-property('tasksReturned') = 0.0"> <then> <property name="id" expression="fn:concat('activecollab_projectId:', get-property('activecollab.projectId'))" /> <!--Call the Response Handler Template --> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="activecollab_listTasksToProcess" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="Empty" /> <with-param name="message" value="No non-archived tasks were found in the ActiveCollab Project." /> </call-template> </then> <else> <!--Increment the no. of tasks to be processed.--> <property name="noOfTasks" expression="get-property('operation','noOfTasks') + count(//jsonArray/jsonElement)" scope="operation" /> <!--FOR EACH Task: BEGIN--> <iterate continueParent="false" id="tasks" expression="//jsonArray/jsonElement" sequential="true"> <target> <sequence> <property name="activecollab.taskId" expression="//jsonElement/task_id/text()" /> <property name="activecollab.isCompleted" expression="//jsonElement/is_completed/text()" /> <!--Freshdesk Ticket ID retrieved from ActiveCollab custom field. --> <property name="freshdesk.ticketId" expression="//jsonElement/custom_fields/custom_field_1/value/text()" /> <!--Build the ID String. activeCollab_projectId, activeCollab_taskId, freshdesk_ticketId.--> <property name="id" expression="fn:concat('activeCollab_projectId:', get-property('activecollab.projectId'), ',activeCollab_taskId:', get-property('activecollab.taskId'), ',freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <sequence key="freshdesk-resolveTicketsAndSendSurvey" /> <!--Increment the Task Count.--> <property name="taskIndex" expression="get-property('operation','taskIndex') + 1" scope="operation" /> </sequence> </target> </iterate> <!--FOR EACH Task: END--> </else> </filter> <!--START: Proceed only if there are any tasks in the ActiveCollab project.--> </then> <else> <!--No. of tasks in the project--> <property name="noOfTasks" expression="count(//activecollabProjectTasks/taskIds)" /> <property name="taskIndex" expression="0" /> <!--START: Proceed only if there are any tasks in the ActiveCollab project.--> <filter xpath="get-property('noOfTasks') = get-property('taskIndex')"> <then> <property name="id" expression="fn:concat('activecollab_projectId:', get-property('activecollab.projectId'))" /> <!--Call the Response Handler template.--> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="activecollab_listTasksToProcess" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="Empty" /> <with-param name="message" value="No non-archived tasks were found in the ActiveCollab Project." /> </call-template> </then> <else> <!--Increment the no. of entries to be deleted.--> <property name="noOfTasks" expression="get-property('operation','noOfTasks') + count(//activecollabProjectTasks/taskIds)" scope="operation" /> <!--FOR EACH Task: BEGIN--> <iterate continueParent="false" id="tasks" expression="//activecollabProjectTasks/taskIds" sequential="true"> <target> <sequence> <property name="activecollab.taskId" expression="//taskIds/text()" /> <!--Retrieve the task in ActiveCollab.--> <activecollab.init> <apiUrl>{$ctx:activecollab.apiUrl}</apiUrl> <apiToken>{$ctx:activecollab.apiToken}</apiToken> <format>json</format> </activecollab.init> <activecollab.getTask> <taskId>{$ctx:activecollab.taskId}</taskId> <projectId>{$ctx:activecollab.projectId}</projectId> </activecollab.getTask> <sequence key="removeResponseHeaders" /> <property name="activecollab.isCompleted" expression="json-eval($.is_completed)" /> <!--Freshdesk Ticket ID retrieved from the ActiveCollab custom field--> <property name="freshdesk.ticketId" expression="json-eval($.custom_fields.custom_field_1.value)" /> <!--Build the ID String. activeCollab_projectId, activeCollab_taskId, freshdesk_ticketId.--> <property name="id" expression="fn:concat('activeCollab_projectId:', get-property('activecollab.projectId'), ',activeCollab_taskId:', get-property('activecollab.taskId'), ',freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <sequence key="freshdesk-resolveTicketsAndSendSurvey" /> <!--Increment the Task Count.--> <property name="taskIndex" expression="get-property('operation','taskIndex') + 1" scope="operation" /> </sequence> </target> </iterate> <!--FOR EACH Task: END--> </else> </filter> <!--START: Proceed only if there are any tasks in the ActiveCollab project.--> </else> </filter> <!--START: If the user has specified to close all the tasks in the particular project in ActiveCollab--> </sequence> </target> </iterate> <!--FOR EACH ProjectTask in activeCollabProjectTasks Map: END--> <filter xpath="get-property('operation', 'noOfTasks') = get-property('operation', 'taskIndex') and get-property('operation', 'noOfProjects') = get-property('operation', 'projectIndex')"> <then> <loopback /> </then> </filter> </else> </filter> </inSequence> <outSequence> <payloadFactory media-type="json"> <format>{ "Response":{ "activity":"freshdesk_resolveTicketsAndSendSurvey", "activityResponse":[$1] } } </format> <args> <arg expression="get-property('operation','responseString')" /> </args> </payloadFactory> <property name="messageType" value="application/json" scope="axis2" /> <send /> </outSequence> </target> <description /> </proxy>
{ "freshdeskApiUrl":"https://wso2connector.freshdesk.com", "freshdeskApiKey":"afPF6MikMUseTd4egbu", "activecollabApiUrl":"https://wso2.manageprojects.com", "activecollabApiToken":"1-qMUQeMdZsgeTe0SIuc3KTYyNKZN7zTlaC2fe2i5i", "surveygizmoApiUrl":"https://restapi.surveygizmo.com", "surveygizmoUsername":"freshdesk01.scenario@gmail.com", "surveygizmoPassword":"7cfec3d1deabd4ea4ef6e3253468197e", "surveygizmoSurveyId":"1995120", "gmailUsername":"canvas.scenario.demo", "gmailAauthAccessToken":"ya29.EgFQk2dhlmPzHm1IjCf9RVXlhydwHzNI9zltk60fWgH-7SR0wP2grT89hmLqrKLMnp5NjqL-FXNgPQ", "activecollabProjectTasks":[ { "projectId":2, "completeAllTasks": true, "taskIds":[1,2] } ] }
Ticket Closure
- Retrieve a list of tickets via FreshDesk using listTickets.
- Retrieve a particular ticket from FreshDesk using getTicket.Â
- Retrieve details of a specific user from FreskDesk using getUser.Â
- In FreshDesk, update the ticket status from
resolved
toclosed
 using updateTicket. - Retrieve completed survey details from SurveyGizmo using listResponses and send the survey rating to the agent through Gmail using sendMail.
FreshDesk operations
SurveyGizmo operations
Gmail operations
Samples
<?xml version="1.0" encoding="UTF-8"?> <proxy xmlns="http://ws.apache.org/ns/synapse" name="freshdesk_sendSurveyResponseToAgent" transports="https,http" statistics="disable" trace="disable" startOnLoad="true"> <target> <inSequence onError="faultHandlerSeq"> <!--Freshdesk Properties--> <property name="freshdesk.apiUrl" expression="json-eval($.freshdeskApiUrl)" /> <property name="freshdesk.apiKey" expression="json-eval($.freshdeskApiKey)" /> <property name="freshdesk.resolvedTicketsViewId" expression="json-eval($.freshdeskResolvedTicketsViewId)" /> <!--SurveyGizmo Properties--> <property name="surveygizmo.apiUrl" expression="json-eval($.surveygizmoApiUrl)" /> <property name="surveygizmo.username" expression="json-eval($.surveygizmoUsername)" /> <property name="surveygizmo.password" expression="json-eval($.surveygizmoPassword)" /> <property name="surveygizmo.surveyId" expression="json-eval($.surveygizmoSurveyId)" /> <!--GMail Properties--> <property name="gmail.username" expression="json-eval($.gmailUsername)" /> <property name="gmail.oauthAccessToken" expression="json-eval($.gmailAauthAccessToken)" /> <!--Operation Scoped Properties--> <property name="responseString" value="" scope="operation" /> <property name="activityName" value="freshdesk_sendSurveyResponseToAgentViaGMAil" scope="operation" /> <property name="noOfTickets" expression="count(//jsonObject/freshdeskTickets)" scope="operation" /> <property name="ticketIndex" expression="0" scope="operation" /> <!--START: If at least one FreshDesk ticket ID is provided, process that. If no FreshDesk Ticket IDs are provided, check whether a viewId is provided.--> <filter xpath="get-property('operation', 'noOfTickets') = get-property('operation', 'ticketIndex')"> <then> <!--START: Proceed with the scenario only if a viewId is provided.--> <filter source="boolean(get-property('freshdesk.resolvedTicketsViewId'))" regex="false"> <then> <payloadFactory media-type="json"> <format>{ "Response":{ "activity":"freshdesk_sendSurveyResponseToAgent", "activityResponse":"freshdeskTickets array is empty AND freshdeskResolvedTicketsViewId is not provided - No tickets to process." } } </format> </payloadFactory> <respond /> </then> <else> <!--Get all the "Resolved" tickets.--> <freshdesk.init> <apiUrl>{$ctx:freshdesk.apiUrl}</apiUrl> <format>json</format> <apiKey>{$ctx:freshdesk.apiKey}</apiKey> </freshdesk.init> <freshdesk.listTickets> <filterType>customticketviews</filterType> <viewId>{$ctx:freshdesk.resolvedTicketsViewId}</viewId> </freshdesk.listTickets> <sequence key="removeResponseHeaders" /> <!--No. of resolved tickets in FreshDesk.--> <property name="noOfTickets" expression="count(//jsonArray/jsonElement)" scope="operation" /> <property name="ticketIndex" expression="0" scope="operation" /> <!-- START: Proceed to get the survey response, if at least one ticket is returned.--> <filter xpath="get-property('operation', 'noOfTickets') = get-property('operation', 'ticketIndex')"> <then> <payloadFactory media-type="json"> <format>{ "Response":{ "activity":"freshdesk_sendSurveyResponseToAgent", "activityResponse":"No tickets are in the resolved state." } } </format> </payloadFactory> <respond /> </then> <else> <!--FOR EACH Freshdesk Ticket retrieved: BEGIN--> <iterate continueParent="false" id="tickets" expression="//jsonArray/jsonElement" sequential="true"> <target> <sequence> <!--Store the Freshdesk Ticket Details --> <property name="freshdesk.ticketId" expression="//jsonElement/display_id/text()" /> <property name="freshdesk.ticketSubject" expression="//jsonElement/subject/text()" /> <property name="freshdesk.ticketStatus" expression="//jsonElement/status/text()" /> <property name="freshdesk.ticketResponderId" expression="//jsonElement/responder_id/text()" /> <property name="freshdesk.surveyGizmoId" expression="//jsonElement/custom_field/*[fn:starts-with(local-name(), 'surveygizmoid')]/text()" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <sequence key="freshdesk-sendSurveyResponseToAgent" /> <!--Increment the Ticket Count --> <property name="ticketIndex" expression="get-property('operation','ticketIndex') + 1" scope="operation" /> </sequence> </target> </iterate> <!--FOR EACH FreshDesk Ticket retrieved: END--> <filter xpath="get-property('operation', 'noOfTickets') = get-property('operation', 'ticketIndex')"> <then> <loopback /> </then> </filter> </else> </filter> <!-- END: Proceed to get the survey response, if at least one ticket is returned.--> </else> </filter> <!--END: Proceed with the scenario only if a viewId is provided.--> </then> <else> <!--FOR EACH FreshDesk Ticket ID in the freshdeskTickets array: BEGIN--> <iterate continueParent="false" id="tickets" expression="//jsonObject/freshdeskTickets" sequential="true"> <target> <sequence> <!--Store the FreshDesk Ticket ID.--> <property name="freshdesk.ticketId" expression="//freshdeskTickets/text()" /> <property name="id" expression="fn:concat('freshdesk_ticketId:', get-property('freshdesk.ticketId'))" /> <!--Retrieve the particular ticket from FreshDesk and check the ticket status.--> <freshdesk.init> <apiUrl>{$ctx:freshdesk.apiUrl}</apiUrl> <format>json</format> <apiKey>{$ctx:freshdesk.apiKey}</apiKey> </freshdesk.init> <freshdesk.getTicket> <id>{$ctx:freshdesk.ticketId}</id> </freshdesk.getTicket> <sequence key="removeResponseHeaders" /> <!--Store the Freshdesk ticket details.--> <property name="freshdesk.ticketSubject" expression="json-eval($.helpdesk_ticket.subject)" /> <property name="freshdesk.ticketStatus" expression="json-eval($.helpdesk_ticket.status)" /> <property name="freshdesk.ticketResponderId" expression="json-eval($.helpdesk_ticket.responder_id)" /> <property name="freshdesk.surveyGizmoId" expression="//jsonObject/helpdesk_ticket/custom_field/*[fn:starts-with(local-name(), 'surveygizmoid')]/text()" /> <sequence key="freshdesk-sendSurveyResponseToAgent" /> <!--Increment the Ticket Count.--> <property name="ticketIndex" expression="get-property('operation','ticketIndex') + 1" scope="operation" /> </sequence> </target> </iterate> <!--FOR EACH Freshdesk Ticket ID in the freshdeskTickets array: END--> <filter xpath="get-property('operation', 'noOfTickets') = get-property('operation', 'ticketIndex')"> <then> <loopback /> </then> </filter> </else> </filter> <!--END: If at least one FreshDesk ID is provided, proceed with that. If no FreshDesk Ticket IDs are provided, check whether a viewId is provided.--> </inSequence> <outSequence> <payloadFactory media-type="json"> <format>{ "Response":{ "activity":"freshdesk_sendSurveyResponseToAgent", "activityResponse":[$1] } } </format> <args> <arg expression="get-property('operation','responseString')" /> </args> </payloadFactory> <property name="messageType" value="application/json" scope="axis2" /> <send /> </outSequence> </target> <description /> </proxy>
{ "freshdeskApiUrl":"https://wso2connector.freshdesk.com", "freshdeskApiKey":"afPF6MikMUseTd4egbu", "surveygizmoApiUrl":"https://restapi.surveygizmo.com", "surveygizmoUsername":"freshdesk.scenario@gmail.com", "surveygizmoPassword":"7cfec3d1deabd4ea4ef6e3253468197e", "gmailUsername":"canvas.scenario.demo", "gmailAauthAccessToken":"ya29.CgGEBCtmuSP8EBOlMhfsQVbs_w56lf9XN17NUHop28tbbWo_xO1bf2KxO-xbJXI2BKOpEvSMjDqyxA", "freshdeskTickets":[], "freshdeskResolvedTicketsViewId":"5000223519" }