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/.

Managing Support Cases in Zoho CRM

The fourth use case in the Zoho CRM business scenario is managing support cases. This page describes the related tasks and the operations you use in the Zoho CRM connector and the other ESB connectors.

Overview

The flow for managing support cases is illustrated in the following diagram. The ESB connectors for Zoho CRM and JIRA will be used to connect to each service. 

  1. Create a case for feedback received for products in Zoho CRM using the insertRecords  operation.

  2. Retrieve the case details from Zoho CRM using the  getRecordsById  operation and t rack the case as an issue in JIRA using the createIssue operation. 

  3. When a particular issue is "Done" in JIRA, retrieve its latest comment using the searchJira operation and update the details in the relevant case in Zoho CRM using the   updateRecords operation.
JIRA operations

Samples

"jiraQuery" will extract the issues from the given time frame.
"issueCaseIdMap" will map the issues in JIRA.

Sample Template for Creating and Retrieving Cases
<!-- This template creates a case in ZohoCRM and then creates a corresponding issue in JIRA using the details retrieved from the created case in ZohoCRM -->
<template name="zohocrm-createAndRetrieveCase" xmlns="http://ws.apache.org/ns/synapse">
	<!-- Zoho CRM parameters -->
	<property name="zohoApiUrl" description="The ZohoCRM API URL" />
	<property name="zohoAccessToken" description="Encrypted alphanumeric string to authenticate the ZohoCRM credentials" />
	<property name="zohoScope" description="ZohoCRM scope. Specify the value as crmapi" />
	<property name="zohoNewFormat" description="The newFormat, an integer determine whether null values should be excluded(1) or included(2)" />
	<property name="zohoVersion" description="Columns selected" />
	<property name="zohoXmlData" description="The xml string containing the data to be inserted" />
	<property name="zohoWfTrigger" description="The wfTrigger parameter is used to trigger the workflow rule while inserting record into CRM account" />
	<property name="zohoDuplicateCheck" description="Checking the duplicate records and throw an error response" />	
	<sequence>
		<!-- zoho CRM properties -->
		<property name="uri.var.zohoApiUrl" expression="json-eval($.zohoApiUrl)"/>
		<property name="uri.var.zohoAccessToken" expression="json-eval($.zohoAccessToken)"/>
		<property name="uri.var.zohoScope" expression="json-eval($.zohoScope)"/>
		<property name="uri.var.zohoNewFormat" expression="json-eval($.zohoNewFormat)"/>
		<property name="uri.var.zohoVersion" expression="json-eval($.zohoVersion)"/>
		<property name="uri.var.zohoXmlData" expression="json-eval($.zohoXmlData)"/>
		<property name="uri.var.zohoWfTrigger" expression="json-eval($.zohoWfTrigger)"/>
		<property name="uri.var.zohoDuplicateCheck" expression="json-eval($.zohoDuplicateCheck)"/>
		<!-- isApproval property was set to false so the case will immediately add to the account and can proceed with other API calls,
			 otherwise manual approving should be needed-->
		<property name="uri.var.zohoIsApproval" value="false"/>
		<property name="uri.var.zohoModuleType" value="Cases"/>	  
	  <!-- zoho CRM create Case-->
      <zohocrm.init>
		  <apiUrl>{$ctx:uri.var.zohoApiUrl}</apiUrl>
		  <accessToken>{$ctx:uri.var.zohoAccessToken}</accessToken>
		  <scope>{$ctx:uri.var.zohoScope}</scope>
      </zohocrm.init>	  
      <zohocrm.insertRecords>
	    <newFormat>{$ctx:uri.var.zohoNewFormat}</newFormat>
        <version>{$ctx:uri.var.zohoVersion}</version>
        <xmlData>{$ctx:uri.var.zohoXmlData}</xmlData>
		<wfTrigger>{$ctx:uri.var.zohoWfTrigger}</wfTrigger>
        <duplicateCheck>{$ctx:uri.var.zohoDuplicateCheck}</duplicateCheck>
        <isApproval>{$ctx:uri.var.zohoIsApproval}</isApproval>
		<moduleType>{$ctx:uri.var.zohoModuleType}</moduleType>
      </zohocrm.insertRecords>
		<call-template target="responseHandlerTemplate">
			<!-- parameter values will be passed on to a sequence template -->
			(
			<with-param name="activityName" value="zohocrm_createCase" />
			|
			) *
		</call-template>
		<!-- Retrieving created case ID --> 
		<property name="uri.var.caseId" expression="json-eval($.response.result.recorddetail.FL[0].content)"/>		
		<!-- Check the availability of caseID to proceed with other API calls -->		
		<filter source="boolean(get-property('uri.var.caseId'))" regex="false">
			<loopback/>
		</filter>	
		<header name="Expires" scope="transport" action="remove" />
		<header name="Content-Type" scope="transport" action="remove" />
		<header name="Date" scope="transport" action="remove" />
		<header name="Server" scope="transport" action="remove" />
		<header name="Transfer-Encoding" scope="transport" action="remove" />
		<header name="Connection" scope="transport" action="remove" />
		<header name="Vary" scope="transport" action="remove" />
		<header name="Content-Encoding" scope="transport" action="remove" />
	  <!-- zoho CRM retrieve created Case-->
      <zohocrm.init>
		  <apiUrl>{$ctx:uri.var.zohoApiUrl}</apiUrl>
		  <accessToken>{$ctx:uri.var.zohoAccessToken}</accessToken>
		  <scope>{$ctx:uri.var.zohoScope}</scope>
      </zohocrm.init>	  
      <zohocrm.getRecordsById>
        <id>{$ctx:uri.var.caseId}</id>
	    <newFormat>{$ctx:uri.var.zohoNewFormat}</newFormat>
        <version>{$ctx:uri.var.zohoVersion}</version>
		<moduleType>{$ctx:uri.var.zohoModuleType}</moduleType>
      </zohocrm.getRecordsById>		
	  <call-template target="responseHandlerTemplate">
		  <!-- parameter values will be passed on to a sequence template -->
		  (
		  <with-param name="activityName" value="zohocrm_getCaseById" />|
		  ) *
	  </call-template>	
	<!-- Retrieving case details --> 
	<property name="uri.var.caseDetails" expression="json-eval($.response.result.Cases.row.FL)"/>  
	<!-- Check the availability of caseDetails to proceed with other API calls -->		
	<filter source="boolean(get-property('uri.var.caseDetails'))" regex="false">
		<loopback/>
	</filter>	
	</sequence>
</template>
Sample Proxy for Creating a Case in ZohoCRM and a Corresponding Issue in Jira
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="zohocrm_jira_createCase"
       transports="https"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence onError="faultHandlerSeq">	  
		<!-- Zoho CRM API call related properties -->
		<property name="zohoApiUrl" expression="json-eval($.zohoApiUrl)"/>
		<property name="zohoAccessToken" expression="json-eval($.zohoAccessToken)"/>
		<property name="zohoScope" expression="json-eval($.zohoScope)"/>
		<property name="zohoNewFormat" expression="json-eval($.zohoNewFormat)"/>
		<property name="zohoVersion" expression="json-eval($.zohoVersion)"/>
		<property name="zohoXmlData" expression="json-eval($.zohoXmlData)"/>
		<property name="zohoWfTrigger" expression="json-eval($.zohoWfTrigger)"/>
		<property name="zohoDuplicateCheck" expression="json-eval($.zohoDuplicateCheck)"/>		
		<!-- Jira API call related properties -->
		<property name="jiraAccountUrl" expression="json-eval($.jiraAccountUrl)"/>
        <property name="jiraUsername" expression="json-eval($.jiraUsername)"/>
        <property name="jiraPassword" expression="json-eval($.jiraPassword)"/>
        <property name="jiraProjectKey" expression="json-eval($.jiraProjectKey)"/>
        <property name="jiraSummary" expression="json-eval($.jiraSummary)"/>
        <property name="jiraIssueType" expression="json-eval($.jiraIssueType)"/>		
      <call-template target="zohocrm-createAndRetrieveCase">
	   <!-- parameter values will be passed on to a sequence template -->
	   (
	   <with-param name="zohoApiUrl" value="{$ctx:zohoApiUrl}" /> |
	   <with-param name="zohoAccessToken" value="{$ctx:zohoAccessToken}" /> |
	   <with-param name="zohoScope" value="{$ctx:zohoScope}" /> |
	   <with-param name="zohoNewFormat" value="{$ctx:zohoNewFormat}" /> |
	   <with-param name="zohoVersion" value="{$ctx:zohoVersion}" /> |
	   <with-param name="zohoXmlData" value="{$ctx:zohoXmlData}" /> |
	   <with-param name="zohoWfTrigger" value="{$ctx:zohoWfTrigger}" /> |
	   <with-param name="zohoDuplicateCheck" value="{$ctx:zohoDuplicateCheck}" /> |
	   ) *
	 </call-template>	 
	<script language="js">		 
		var jsn = eval("(" + mc.getProperty("uri.var.caseDetails") + ")");
		for (var i = 0; i &lt; jsn.length ; i++) { 	
			// If the description is present uses it for JIRA Issue creation
			if(jsn[i].val == "Description"){
				mc.setProperty('uri.var.jiraDescription', jsn[i].content);
			}			
		}
		// Empty the description if it was not retrieved from ZohoCRM (will be assigned string null from mc.setProperty())
		if(mc.getProperty('uri.var.jiraDescription') == 'null'){
			mc.setProperty('uri.var.jiraDescription', '');
		}
	</script>
	<header name="Expires" scope="transport" action="remove" />
	<header name="Content-Type" scope="transport" action="remove" />
	<header name="Date" scope="transport" action="remove" />
	<header name="Server" scope="transport" action="remove" />
	<header name="Transfer-Encoding" scope="transport" action="remove" />
	<header name="Connection" scope="transport" action="remove" />
	<header name="Vary" scope="transport" action="remove" />
	<header name="Content-Encoding" scope="transport" action="remove" />	
	<!-- Jira create Issue-->
	 <jira.init>
		<uri>{$ctx:jiraAccountUrl}</uri>
		<username>{$ctx:jiraUsername}</username>
		<password>{$ctx:jiraPassword}</password>
	 </jira.init>
	 <jira.createIssue>
		<projectKey>{$ctx:jiraProjectKey}</projectKey>
		<summary>{$ctx:jiraSummary}</summary>
		<description>{$ctx:uri.var.jiraDescription}</description>
		<issueType>{$ctx:jiraIssueType}</issueType>
	 </jira.createIssue>
	<call-template target="responseHandlerTemplate">
		<!-- parameter values will be passed on to a sequence template -->
		(
		<with-param name="activityName" value="jira_createIssue" />
		|
		) *
	</call-template>
	<loopback/>
      </inSequence>
      <outSequence>
		<property name="messageType" value="application/json" scope="axis2" />
		<!-- Generate the chained response of all the API calls in createLeads -->
		<payloadFactory media-type="json">
			<format>
				{
				"Response":[$1]
				}
			</format>
			<args>
				<arg expression="get-property('uri.var.responseString')" />
			</args>
		</payloadFactory>		
         <send/>
      </outSequence>
   </target>
   <description/>
</proxy>                                                               


Sample Request for Creating a Case in ZohoCRM and a Corresponding Issue in Jira
{
	"zohoApiUrl": "https://crm.zoho.com",
	"zohoAccessToken": "0c255a80ed272cb8a57e4f688f89741f",
	"zohoScope": "crmapi",
	"zohoNewFormat": 2,
	"zohoVersion": 2,
	"zohoXmlData": "<Cases><row no=\"1\"><FL val=\"Subject\">ERR</FL></row></Cases>",
	"zohoWfTrigger": true,
	"zohoDuplicateCheck": "2",
	"jiraAccountUrl":"http://cd-pdissanayake:8080",
	"jiraUsername":"admin",
	"jiraPassword":"1qaz2wsx@",
	"jiraProjectKey":"SI",
	"jiraSummary":"issueOnPrabodhaPCSummary",
	"jiraIssueType":"New Feature"
}
Sample Template for Updating Issue
<!-- This template updates an issue in JIRA by adding a comment and then creates the same comment in corresponding case inside ZohoCRM case -->
<template name="zohocrm-updateIssue" xmlns="http://ws.apache.org/ns/synapse">
	<!-- Zoho CRM parameters -->
	<parameter name="zohoApiUrl" description="The Zoho api URL" />
	<parameter name="zohoAccessToken" description="Encrypted alphanumeric string to authenticate the Zoho credentials" />
	<parameter name="zohoScope" description="Zoho CRM scope, Specify the value as crmapi" />
	<parameter name="zohoNewFormat" description="The newFormat, an integer determine whether null values should be excluded(1) or included(2)" />
	<parameter name="zohoVersion" description="Columns selected" />
	<parameter name="zohoWfTrigger" description="The wfTrigger parameter is used to trigger the workflow rule while inserting record into CRM account" />
	<parameter name="zohoCaseId" description="Zoho Case ID, to add the comment. This should be the corresponding case of the JIRA issue." />
	<parameter name="comment" description="Comment to be updated in ZohoCRM Case" />
	<sequence>
		<!-- zoho CRM properties -->
		<property name="uri.var.zohoApiUrl" expression="$func:zohoApiUrl"/>
		<property name="uri.var.zohoAccessToken" expression="$func:zohoAccessToken"/>
		<property name="uri.var.zohoScope" expression="$func:zohoScope"/>
		<property name="uri.var.zohoNewFormat" expression="$func:zohoNewFormat"/>
		<property name="uri.var.zohoVersion" expression="$func:zohoVersion"/>
		<property name="uri.var.zohoWfTrigger" expression="$func:zohoWfTrigger"/>
		<property name="uri.var.zohoCaseId" expression="$func:zohoCaseId"/>
		<property name="uri.var.zohoModuleType" value="Cases"/>
		<property name="uri.var.comment" expression="$func:comment"/>
		<script language="js">
         <![CDATA[
			 var comment = mc.getProperty("uri.var.comment");
			 var xmlData = '<Cases> <row no=\"1\"> <FL val=\"Internal Comments\">' + comment + '</FL> </row> </Cases>';
			 mc.setProperty('uri.var.zohoXmlData', xmlData);
		 ]]>
		</script>
	  <!-- zoho CRM insert comment to Case -->
      <zohocrm.init>
		  <apiUrl>{$ctx:uri.var.zohoApiUrl}</apiUrl>
		  <accessToken>{$ctx:uri.var.zohoAccessToken}</accessToken>
		  <scope>{$ctx:uri.var.zohoScope}</scope>
      </zohocrm.init>
      <zohocrm.updateRecords>
		<newFormat>{$ctx:uri.var.zohoNewFormat}</newFormat>
        <version>{$ctx:uri.var.zohoVersion}</version>
        <id>{$ctx:uri.var.zohoCaseId}</id>
        <xmlData>{$ctx:uri.var.zohoXmlData}</xmlData>
        <wfTrigger>{$ctx:uri.var.zohoWfTrigger}</wfTrigger>
		<moduleType>{$ctx:uri.var.zohoModuleType}</moduleType>
      </zohocrm.updateRecords>
		<call-template target="responseHandlerTemplate">
			<!-- parameter values will be passed on to a sequence template -->
			(
			<with-param name="activityName" value="zohocrm_insertCommentForCase" />
			|
			) *
		</call-template>
	</sequence>
</template>
Sample Proxy for Following Up on Issues
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="zohocrm_jira_followupIssues"
       transports="https"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence onError="faultHandlerSeq">	  		
		<!-- Jira API call related properties -->
		<property name="jiraAccountUrl" expression="json-eval($.jiraAccountUrl)"/>
        <property name="jiraUsername" expression="json-eval($.jiraUsername)"/>
        <property name="jiraPassword" expression="json-eval($.jiraPassword)"/>
        <property name="jiraQuery" expression="json-eval($.jiraQuery)"/>
        <property name="jiraMaxResult" expression="json-eval($.jiraMaxResult)"/>
		<property name="jiraStartFrom" expression="json-eval($.jiraStartFrom)"/>	
		<property name="jiraFields" value="comment"/>			
		<!-- Zoho CRM API call related properties -->
		<property name="zohoApiUrl" expression="json-eval($.zohoApiUrl)"/>
		<property name="zohoAccessToken" expression="json-eval($.zohoAccessToken)"/>
		<property name="zohoScope" expression="json-eval($.zohoScope)"/>
		<property name="zohoNewFormat" expression="json-eval($.zohoNewFormat)"/>
		<property name="zohoVersion" expression="json-eval($.zohoVersion)"/>
		<property name="zohoWfTrigger" expression="json-eval($.zohoWfTrigger)"/>		
		<property name="issueCaseIdMap" expression="json-eval($.issueCaseIdMap)"/>
		<property name="uri.var.responseBuilder" value="" scope="operation" />
		<property name="uri.var.index" value="0" scope="operation" />			
		<!-- Jira Retrieve all issues -->
		<jira.init>
           <uri>{$ctx:jiraAccountUrl}</uri>
           <username>{$ctx:jiraUsername}</username>
           <password>{$ctx:jiraPassword}</password>
        </jira.init>
        <jira.searchJira>
           <query>{$ctx:jiraQuery}</query>
		   <maxResult>{$ctx:jiraMaxResult}</maxResult>
		   <startFrom>{$ctx:jiraStartFrom}</startFrom>
		   <fields>{$ctx:jiraFields}</fields>
        </jira.searchJira>		
		<call-template target="responseHandlerTemplate">
			<!-- parameter values will be passed on to a sequence template -->
			(
			<with-param name="activityName" value="jira_searchIssues" />
			|
			) *
		</call-template>			
		<property name="uri.var.getIssuesResponseString" expression="get-property('uri.var.responseString')" scope="operation" />	
		<property name="messageType" value="application/xml" scope="axis2" />
		<property name="uri.var.issuesCount" expression="count(//issues)" scope="operation" />
		<filter xpath="0 = get-property('operation', 'uri.var.issuesCount')">
			<then>
				<payloadFactory media-type="json">
					<format>
						{
						"activity":"zohocrm_retrieveIssuesFailure",
						"activityResponse":"No issues were found according to the provided JQL"
						}
					</format>
				</payloadFactory>
				<call-template target="responseHandlerTemplate">
					<!-- parameter values will be passed on to a sequence template -->
					(
					<with-param name="activityName" value="zohocrm_getIssuesFailure" />
					|
					) *
				</call-template>
				<property name="uri.var.responseBuilder" expression="json-eval($)" scope="operation" />
				<loopback />
			</then>
		</filter>
		<!-- Clears the rsponseString to avoid it being appended multiple times -->
			<property name="uri.var.responseString" value="" />
			<iterate id="leadsIterator" expression="//issues" sequential="true" continueParent="true"
				preservePayload="true">
				<target>
					<sequence>
						<property name="uri.var.jiraIssueKey" expression="(//*/key)[1]/text()" />
						<property name="uri.var.comment" expression="(//*/comments/body)[last()]/text()"/>
						<script language="js">
							var jiraIssueId = mc.getProperty('uri.var.jiraIssueKey');
							var issueCaseIdMap = eval("("+mc.getProperty('issueCaseIdMap')+")");
							var zohoCaseId = issueCaseIdMap[jiraIssueId];
							mc.setProperty('uri.var.zohoCaseId', zohoCaseId);
						</script>						
						<call-template target="zohocrm-updateIssue">
							<!-- parameter values will be passed on to a sequence template -->
							(
							<with-param name="zohoApiUrl" value="{$ctx:zohoApiUrl}" />
							|
							<with-param name="zohoAccessToken" value="{$ctx:zohoAccessToken}" />
							|
							<with-param name="zohoScope" value="{$ctx:zohoScope}" />
							|
							<with-param name="zohoNewFormat" value="{$ctx:zohoNewFormat}" />
							|
							<with-param name="zohoVersion" value="{$ctx:zohoVersion}" />
							|
							<with-param name="zohoWfTrigger" value="{$ctx:zohoWfTrigger}" />		
							|
							<with-param name="zohoCaseId" value="{$ctx:uri.var.zohoCaseId}" />
							|
							<with-param name="comment" value="{$ctx:uri.var.comment}" />
							|
							) *
						</call-template>
						<property name="uri.var.index" expression="get-property('operation','uri.var.index') + 1" scope="operation" />
						<property name="uri.var.responseBuilder"
							expression="fn:concat(get-property('operation','uri.var.responseBuilder'), get-property('uri.var.responseString') , ', ')"
							scope="operation" />
					</sequence>
				</target>
			</iterate>
			<filter xpath="get-property('operation', 'uri.var.index') = get-property('operation', 'uri.var.issuesCount')">
				<then>
					<!-- Remove the final comma appended inside the iterator mediator for final response generation inside the outsequence -->
					<property name="uri.var.responseBuilder"
						expression="fn:substring(get-property('operation', 'uri.var.responseBuilder'), 0, fn:string-length(get-property('operation', 'uri.var.responseBuilder')))"
						scope="operation" />
					<loopback />
				</then>
			</filter>	
      </inSequence>
      <outSequence>
        <property name="messageType" value="application/json" scope="axis2" />		
			<!-- Generate the chained response of all the API calls in createLeads -->
			<payloadFactory media-type="json">
				<format>
					{
					"Response":[
					$1,
					$2
					]
					}
				</format>
				<args>
					<arg expression="get-property('operation', 'uri.var.getIssuesResponseString')" />
					<arg expression="get-property('operation', 'uri.var.responseBuilder')" />
				</args>
			</payloadFactory>
			<send />
		</outSequence>
	</target>
	<description />
</proxy>                                                                               
Sample Request for Following Up on Issues
{
	"jiraAccountUrl":"http://cd-dvirajith:8080",
	"jiraUsername":"admin",
	"jiraPassword":"admin",
	"jiraQuery":"status%3D%22done%22%20AND%20updated%3EstartOfDay()",
	"jiraMaxResult":"30",
	"jiraStartFrom":"0",
	"issueCaseIdMap":{"TES-23":"1264711000000091001","TES-18":"1264711000000072003"},
	"zohoApiUrl":"https://crm.zoho.com",
	"zohoAccessToken":"5fba482fb322c85b26783f68ee7900ae",
	"zohoScope":"crmapi",
	"zohoNewFormat":"1",
	"zohoVersion":"1",
	"zohoWfTrigger":false
}