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/.
Medical Campaigns in Cliniko
The first use case in the Cliniko business scenario is medical campaigns. This page describes the relevant tasks and the operations you use in the Cliniko connector and the other ESB connectors.Â
Overview
The flow for medical campaigns is illustrated in the following diagram. The ESB connectors for Eventbrite, Cliniko and Google Calendar will be used to connect to each service.
Create medical campaigns as events/tickets in Eventbrite and publish those events, which is an offline process.Â
Note
Event organizers should be practitioners in Cliniko.
- Retrieve all the patients from the Cliniko API using the listPatients operation.
- Retrieve appointment types from the Cliniko API using the getAppointmentType operation.
- Retrieve event attendees from the Eventbrite API using the getEventAttendees operation.
- If the patient does not exist create the patient in the Cliniko API using the createPatient operation.
- Retrieve the specified practitioner from the Cliniko API using the getPractitioner operation.
- Retrieve the business ID from the Cliniko API using the listBusinesses operation.
- Retrieve the availability of the practitioner from the Cliniko API using the getNextAvailableTime operation.
- Retrieve the appointments for a patient from the Cliniko API using the listAppointments operation.
- Create an appointment in the Cliniko API using the createAppointment operation.
- Create a calendar event for the appointment in the Google Calendar API using the createEvent operation.
Eventbrite operations
- getEventAttendees
Cliniko operations
- listPatients
- getAppointmentType
- createPatient
- getPractitioner
- listBusinesses
- getNextAvailableTime
- listAppointments
- createAppointment
Google Calendar operations
Prerequisites
- The ticket class description should contain the practitioner ID in Cliniko for whom the appointment should be created. Please adhere to the following format:
e.g. Red Eye (Practitioner ID:41213)
Samples
<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. WSO2 Inc. licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- This template creates appointments in cliniko and events in Google Calendar --> <template xmlns="http://ws.apache.org/ns/synapse" name="createAppointments"> <!--Cliniko parameters--> <parameter name="cliniko.apiKey" description="Encrypted alphanumeric string to authenticate the cliniko credentials." /> <parameter name="cliniko.apiUrl" description="The cliniko API URL." /> <parameter name="cliniko.patientId" description="ID of the cliniko patient." /> <parameter name="cliniko.practionerId" description="ID of the cliniko practitioner." /> <parameter name="cliniko.appointmentTypeId" description="ID of the cliniko appointment type." /> <parameter name="cliniko.appointmentNote" description="Note of the appointment." /> <parameter name="cliniko.accountName" description="Name of the cliniko account." /> <!-- GoogleCalender parameters--> <parameter name="googlecalendar.accessToken" description="Encrypted alphanumeric string to authenticate the googlecalendar credentials." /> <parameter name="googlecalendar.apiUrl" description="The googlecalendar API URL." /> <parameter name="googlecalendar.calendarId" description="The ID of the common calender." /> <!-- Common parameters--> <parameter name="shared.timeZone" description="Time zone in which the application runs." /> <parameter name="common.id" description="ID of the resource from the appointment details are taken." /> <sequence> <property name="cliniko.apiKey" expression="$func:cliniko.apiKey" /> <property name="cliniko.apiUrl" expression="$func:cliniko.apiUrl" /> <property name="cliniko.patientId" expression="$func:cliniko.patientId" /> <property name="cliniko.practionerId" expression="$func:cliniko.practionerId" /> <property name="cliniko.appointmentTypeId" expression="$func:cliniko.appointmentTypeId" /> <property name="cliniko.appointmentNote" expression="$func:cliniko.appointmentNote" /> <property name="cliniko.accountName" expression="$func:cliniko.accountName" /> <property name="common.id" expression="$func:common.id" /> <property name="googlecalendar.accessToken" expression="$func:googlecalendar.accessToken" /> <property name="googlecalendar.apiUrl" expression="$func:googlecalendar.apiUrl" /> <property name="googlecalendar.calendarId" expression="$func:googlecalendar.calendarId" /> <property name="shared.timeZone" expression="$func:shared.timeZone" /> <!--Call cliniko connector getPractitioner method to get practitioner --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.getPractitioner> <practitionerId>{$ctx:cliniko.practionerId}</practitionerId> </cliniko.getPractitioner> <!-- Get the response status. --> <property name="responseStatus" expression="$axis2:HTTP_SC" /> <!-- START: Proceed only if the getPractitioner call is successful. --> <filter xpath="get-property('responseStatus') != 200"> <then> <!-- Append an error message to be sent to the user. --> <property name="cliniko.errorResponse" expression="json-eval($)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_getPractitioner" /> <with-param name="id" value="{$ctx:id.empty}" /> <with-param name="status" value="error" /> <with-param name="message" value="The appointment has not been created since the practitioner ID is not given." /> </call-template> </then> <else> <property name="uri.var.cliniko.user" expression="json-eval($.user.links.self)" /> <!--Get the email address of the practitioner using the getUser API method --> <header name="Accept" value="application/json" scope="transport" /> <header name="Content-Type" value="application/json" scope="transport" /> <header name="Authorization" expression="fn:concat('Basic ', base64Encode(fn:concat(get-property('cliniko.apiKey'), ':')))" scope="transport" /> <call> <endpoint> <http method="get" uri-template="{uri.var.cliniko.user}" /> </endpoint> </call> <property name="cliniko.practitionerEmail" expression="json-eval($.email)" /> <!--Call cliniko connector listBusinesses method to get the business ID --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listBusinesses /> <property name="cliniko.businessId" expression="json-eval($.businesses[0].id)" /> <!--Call cliniko connector getNextAvailableTime method to get the availability of the practitioner --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.getNextAvailableTime> <practitionerId>{$ctx:cliniko.practionerId}</practitionerId> <appointmentTypeId>{$ctx:cliniko.appointmentTypeId}</appointmentTypeId> <businessId>{$ctx:cliniko.businessId}</businessId> </cliniko.getNextAvailableTime> <property name="cliniko.appointmentStart" expression="json-eval($.appointment_start)" /> <property name="uri.var.urlQuery" action="remove" /> <sequence key="removeResponseHeaders" /> <!--Call cliniko connector listAppointments method to list appointments for a patient --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listAppointments> <patientId>{$ctx:cliniko.patientId}</patientId> </cliniko.listAppointments> <property name="cliniko.appointmentCount" expression="//appointments" /> <!-- START: Proceed only if there is at least one appointment --> <filter xpath="get-property('cliniko.appointmentCount') != 0.0"> <then> <!--Check the possibility of creating new appointments to the patient with the required practitioner--> <script language="js"><![CDATA[payload = mc.getPayloadJSON(); var appointmentArray = payload.appointments; var requestPractioner = ''+mc.getProperty('cliniko.practionerId'); var nextTime = mc.getProperty('cliniko.appointmentStart'); var proceed = 0; for(var i=0;i<appointmentArray.length;i++) { var practitionerUrl = ''+appointmentArray[i].practitioner.links.self; var practionerId=practitionerUrl.substring(practitionerUrl.lastIndexOf('/') + 1); var cancelTime = appointmentArray[i].cancellation_time; if(cancelTime == null) { var endTime = appointmentArray[i].appointment_end; var startTime = appointmentArray[i].appointment_start; if(practionerId == requestPractioner) { var sdf = java.text.SimpleDateFormat.getInstance(); sdf= new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC")); var currentTime = sdf.format(new java.util.Date()); if(endTime>currentTime) { proceed = 1; mc.setProperty('cliniko.newAppointments',"true"); break; } } else { if(startTime<=nextTime && endTime>=nextTime) { mc.setProperty('cliniko.newPractitionerApp',"true"); break; } } } } if(proceed == 0) { var timeZone = mc.getProperty('shared.timeZone'); var hours = parseInt((timeZone.split(':')[0])*60); var mins = parseInt(timeZone.split(':')[1]); var timeGap = hours+mins; var timeFormat = "yyyy-MM-dd'T'HH:mm:ss"; var newStartTime = ''+new java.text.SimpleDateFormat(timeFormat).format(new java.util.Date(new java.text.SimpleDateFormat(timeFormat).parse(nextTime).getTime() + timeGap*60*1000))+timeZone; var newEndTime = new java.text.SimpleDateFormat(timeFormat).format(new java.util.Date(new java.text.SimpleDateFormat(timeFormat).parse(newStartTime).getTime() + 30*60*1000))+timeZone; mc.setProperty('cliniko.appointmentEndTime',newEndTime); mc.setProperty('cliniko.appointmentStartTime',newStartTime); } ]]> </script> </then> </filter> <!-- END: Proceed only if there is at least one appointment --> <!-- START: Process only if there are no new appointments for the patient with the given practitioner --> <filter source="boolean(get-property('cliniko.newAppointments'))" regex="false"> <then> <!--Call cliniko connector createAppointment method to create an appointment --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.createAppointment> <appointmentEndTime>{$ctx:cliniko.appointmentEndTime}</appointmentEndTime> <appointmentStartTime>{$ctx:cliniko.appointmentStartTime}</appointmentStartTime> <notes>{$ctx:cliniko.appointmentNote}</notes> <patientId>{$ctx:cliniko.patientId}</patientId> <practitionerId>{$ctx:cliniko.practionerId}</practitionerId> <appointmentTypeId>{$ctx:cliniko.appointmentTypeId}</appointmentTypeId> <businessId>{$ctx:cliniko.businessId}</businessId> </cliniko.createAppointment> <property name="cliniko.appointmentId" expression="json-eval($.id)" /> <!-- START: Append the response message according to the createAppointment response --> <filter source="boolean(get-property('cliniko.appointmentId'))" regex="false"> <then> <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_patientId:',get-property('cliniko.patientId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($)" /> <!--Call the responseHandler template--> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_createAppointment" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <else> <!-- START: Append the response message according to the the time overlapping of the appointments of patients --> <filter source="boolean(get-property('cliniko.newPractitionerApp'))" regex="true"> <then> <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" /> <property name="status" value="success" /> <property name="message" value="An appointment has been successfully created. But there is a time overlap." /> <!--Call the responseHandler template--> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_createAppointment" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> <else> <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" /> <property name="status" value="success" /> <property name="message" value="An appointment has been successfully created." /> <!--Call the responseHandler template--> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_createAppointment" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <property name="googlecalendar.attendees" expression="fn:concat('[{"email":"',get-property('cliniko.practitionerEmail'),'"}]')" /> <property name="googlecalendar.description" expression="fn:concat('Appointment :',get-property('cliniko.appointmentNote'))" /> <property name="googlecalendar.summary" expression="fn:concat('Appointment - ',get-property('cliniko.accountName'))" /> <payloadFactory media-type="json"> <format>{ "start": { "dateTime": "$1" }, "end": { "dateTime": "$2" } }</format> <args> <arg expression="get-property('cliniko.appointmentStartTime')" /> <arg expression="get-property('cliniko.appointmentEndTime')" /> </args> </payloadFactory> <property name="googlecalendar.eventStart" expression="json-eval($.start)" /> <property name="googlecalendar.eventEnd" expression="json-eval($.end)" /> <!--Call googlecalendar connector createEvent for the appointment --> <googlecalendar.init> <apiUrl>{$ctx:googlecalendar.apiUrl}</apiUrl> <accessToken>{$ctx:googlecalendar.accessToken}</accessToken> </googlecalendar.init> <googlecalendar.createEvent> <calendarId>{$ctx:googlecalendar.calendarId}</calendarId> <description>{$ctx:googlecalendar.description}</description> <summary>{$ctx:googlecalendar.summary}</summary> <start>{$ctx:googlecalendar.eventStart}</start> <end>{$ctx:googlecalendar.eventEnd}</end> <attendees>{$ctx:googlecalendar.attendees}</attendees> <sendNotifications>true</sendNotifications> </googlecalendar.createEvent> <property name="googleCalendar.eventId" expression="json-eval($.id)" /> <!-- START: Append the response message according to the createEvent response --> <filter source="boolean(get-property('googleCalendar.eventId'))" regex="false"> <then> <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($)" /> </then> <else> <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'),',googlecalendar_eventId:',get-property('googleCalendar.eventId'))" /> <property name="status" value="success" /> <property name="message" value="A calendar event has been successfully created for the practitioner." /> </else> </filter> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="googleCalendar_createEvent" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </else> </filter> <!-- END: Append the response message according to the the time overlapping of the appointments of patients --> </else> </filter> <!-- END: Append the response message according to the createAppointment response --> </then> </filter> <!-- END: Process only if there are no new appointments for the patient with the given practitioner --> </else> </filter> <!-- END: Proceed only if the getPractitioner call is successful. --> </sequence> </template>
<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. WSO2 Inc. licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!--This scenario will create appointments in Cliniko and events in Google Calendar using events in EventBrite. --> <proxy xmlns="http://ws.apache.org/ns/synapse" name="cliniko_retrieveEventsAndCreateAppointments" transports="https,http" statistics="disable" trace="disable" startOnLoad="true"> <target> <inSequence onError="faultHandlerSeq"> <!-- Cliniko Properties --> <property name="cliniko.apiUrl" expression="get-property('registry', 'connectors/Cliniko/apiUrl')" /> <property name="cliniko.apiKey" expression="get-property('registry', 'connectors/Cliniko/apiKey')" /> <property name="cliniko.appointmentType" expression="json-eval($.cliniko.appointmentType)" /> <!-- EventBrite parameters. --> <property name="eventBrite.apiUrl" expression="get-property('registry', 'connectors/Eventbrite/apiUrl')" /> <property name="eventBrite.accessToken" expression="get-property('registry', 'connectors/Eventbrite/accessToken')" /> <property name="eventBrite.eventId" expression="json-eval($.eventBrite.eventId)" /> <!-- GoogleCalendar Properties --> <property name="googlecalendar.apiUrl" expression="get-property('registry', 'connectors/Googlecalendar/apiUrl')" /> <property name="googlecalendar.accessToken" expression="get-property('registry', 'connectors/Googlecalendar/accessToken')" /> <property name="googlecalendar.calendarId" expression="json-eval($.googlecalendar.calendarId)" /> <!-- Shared Properties --> <property name="shared.timeZone" expression="json-eval($.shared.timeZone)" /> <!-- Operation scoped properties --> <property name="responseString" value="" scope="operation" /> <property name="uri.var.apiUrl" expression="get-property('eventBrite.apiUrl')" /> <property name="uri.var.eventId" expression="get-property('eventBrite.eventId')" /> <property name="uri.var.accessToken" expression="get-property('eventBrite.accessToken')" /> <property name="REQUEST_HOST_HEADER" value="www.eventbriteapi.com" scope="axis2" /> <call> <endpoint> <http method="get" uri-template="{+uri.var.apiUrl}/v3/events/{+uri.var.eventId}/ticket_classes/?token={uri.var.accessToken}" /> <property name="Accept" value="*/*" scope="transport" /> </endpoint> </call> <!-- START: Proceed only if the call is successful. --> <filter source="$axis2:HTTP_SC" regex="200"> <then> <property name="eventBrite.ticket.classes" expression="json-eval($.ticket_classes)" /> <script language="js"> <![CDATA[ var ticketClasses = eval("("+mc.getProperty('eventBrite.ticket.classes')+")"); var ticketID = ''; var ticketDesc = ''; var ticketName = ''; var payload = {sources:[]}; for(var i = 0; i<ticketClasses.length; i++) { ticketID = ticketClasses[i].id; ticketDesc = ticketClasses[i].description; ticketName = ticketClasses[i].name; payload.sources.push({ "ticketID" : ticketID, "ticketDesc" : ticketDesc, "ticketName" : ticketName}); } mc.setPayloadJSON(payload); ]]> </script> <property name="eventBrite.ticketClassObject" expression="json-eval($.sources)" /> </then> <else> <property name="id" value="{}" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.error_description)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="eventBrite_listTicketClasses" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </else> </filter> <!-- END: Proceed only if the call is successful. --> <!--Call cliniko connector listPatients method to list all the patients --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listPatients /> <!-- Get the response status. --> <property name="responseStatus" expression="$axis2:HTTP_SC" /> <!-- START: Proceed only if the call is successful. --> <filter xpath="get-property('responseStatus') = 200"> <then> <!--Construct an object to store the patient's email and the ID--> <script language="js"> <![CDATA[ payload = mc.getPayloadJSON(); var patientArray = payload.patients; var patientObj = {}; for(var i=0;i<patientArray.length;i++) { patientObj[patientArray[i].email] = patientArray[i].id; } for(var key in patientObj) { var id = patientObj[key]; } mc.setPayloadJSON(patientObj); ]]> </script> <property name="cliniko.patientObject" expression="json-eval($.)" /> </then> <else> <property name="message" expression="json-eval($)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_listPatients" /> <with-param name="id" value="{$ctx:id.empty}" /> <with-param name="status" value="error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </else> </filter> <!-- END: Proceed only if the call is successful. --> <!--Call cliniko connector getAppointmentType method to get appointment types --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.getAppointmentType /> <!-- START: Proceed only if the call is successful. --> <filter xpath="get-property('responseStatus') = 200"> <then> <!--Get the ID of the given appointmentType--> <script language="js"> <![CDATA[ payload = mc.getPayloadJSON(); var appointmentTypeArray = payload.appointment_types; var appType = mc.getProperty('cliniko.appointmentType'); for(var i=0;i<appointmentTypeArray.length;i++) { var name = appointmentTypeArray[i].name; if(appType.toLowerCase() == name.toLowerCase()) { var id = ''+appointmentTypeArray[i].id; mc.setProperty('cliniko.appointmentTypeId',id); break; } } ]]> </script> <!-- START: Proceed only if the appointmentType is existing. --> <filter source="boolean(get-property('cliniko.appointmentTypeId') )" regex="false"> <then> <property name="id" value="{}" /> <property name="status" value="skipped" /> <property name="message" value="The given Appointment Type is invalid." /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="cliniko_listAppointmentTypes" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </then> </filter> <!-- END: Proceed only if the appointmentType is existing. --> </then> <else> <property name="message" expression="json-eval($)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_getAppointmentType" /> <with-param name="id" value="{$ctx:id.empty}" /> <with-param name="status" value="error" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </else> </filter> <!-- END: Proceed only if the call is successful. --> <!--Extract cliniko_getSettingsSeq to get details of cliniko account--> <sequence key="cliniko_getSettingsSeq" /> <sequence key="removeResponseHeaders" /> <header name="Strict-Transport-Security" action="remove" scope="transport" /> <header name="Host" action="remove" scope="transport" /> <header name="Host" value="www.eventbriteapi.com" scope="transport" /> <!--Call eventbrite connector getEventAttendees method--> <eventbrite.init> <apiUrl>{$ctx:eventBrite.apiUrl}</apiUrl> <accessToken>{$ctx:eventBrite.accessToken}</accessToken> </eventbrite.init> <eventbrite.getEventAttendees> <eventId>{$ctx:eventBrite.eventId}</eventId> </eventbrite.getEventAttendees> <!-- START: Proceed only if the call is successful. --> <filter source="$axis2:HTTP_SC" regex="200"> <then> <property name="attendeeIndex" expression="0" scope="operation" /> <property name="eventBrite.attendeeCount" expression="count(//attendees)" /> <!-- START: Proceed only if there is at least one ticket --> <filter xpath="get-property('eventBrite.attendeeCount') = 0.0"> <then> <property name="id" value="{}" /> <property name="status" value="skipped" /> <property name="message" value="There are no attendees to process" /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="eventBrite_getEventAttendees" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </then> </filter> <!-- END: Proceed only if there is at least one ticket --> <!--BEGIN : FOR EACH ticket --> <iterate continueParent="false" id="attendees" expression="//attendees" sequential="true"> <target> <sequence> <property name="eventBrite.attendeeId" expression="json-eval($.attendees.id)" /> <property name="eventBrite.ticketClassId" expression="json-eval($.attendees.ticket_class_id)" /> <property name="eventBrite.attendeeEmail" expression="json-eval($.attendees.profile.email)" /> <property name="eventBrite.attendeeFirstName" expression="json-eval($.attendees.profile.first_name)" /> <property name="eventBrite.attendeeLastName" expression="json-eval($.attendees.profile.last_name)" /> <!--Check whether the patient is already existing using the above created object --> <script language="js"> <![CDATA[ var patientObj = eval("(" + mc.getProperty('cliniko.patientObject') + ")"); var ticketClassObj = eval("(" +mc.getProperty('eventBrite.ticketClassObject') + ")"); var attendeeEmail = mc.getProperty('eventBrite.attendeeEmail'); var attendeeFirstName = mc.getProperty('eventBrite.attendeeFirstName'); var attendeeLastName = mc.getProperty('eventBrite.attendeeLastName'); var ticketClassId = mc.getProperty('eventBrite.ticketClassId'); for(var i = 0; i<ticketClassObj.length ;i++) { if(ticketClassId == ticketClassObj[i].ticketID){ var desc = ticketClassObj[i].ticketDesc; var practioner = desc.match(/\(([^)]+)\)/)[1].split(':')[1]; mc.setProperty("cliniko.practionerId",practioner); break; } } if(patientObj.hasOwnProperty(attendeeEmail)) { var id = ''+patientObj[attendeeEmail]; mc.setProperty("cliniko.patientId",id); } else { mc.setProperty("cliniko.firstName",attendeeFirstName); mc.setProperty("cliniko.lastName",attendeeLastName); } ]]> </script> <!-- START: Proceed according to the existence of the patient in cliniko --> <filter source="boolean(get-property('cliniko.patientId'))" regex="false"> <then> <!--Call cliniko connector createPatient method to create a new patient --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.createPatient> <email>{$ctx:eventBrite.attendeeEmail}</email> <firstName>{$ctx:cliniko.firstName}</firstName> <lastName>{$ctx:cliniko.lastName}</lastName> </cliniko.createPatient> <property name="cliniko.patientId" expression="json-eval($.id)" /> <!-- START: Append the response message according to the createPatient response --> <filter source="boolean(get-property('cliniko.patientId'))" regex="false"> <then> <property name="id" expression="fn:concat('eventBrite_attendeeId:',get-property('eventBrite.attendeeId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($)" /> </then> <else> <property name="id" expression="fn:concat('eventBrite_attendeeId:',get-property('eventBrite.attendeeId'),',cliniko_patientId:',get-property('cliniko.patientId'))" /> <property name="status" value="success" /> <property name="message" value="A patient has been successfully created." /> </else> </filter> <!--Call the responseHandler template --> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_createPatient" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </then> </filter> <!-- END: Proceed according to the existence of the patient in cliniko --> <property name="uri.var.urlQuery" action="remove"/> <!-- START: Process only if the patient is existing --> <filter source="boolean(get-property('cliniko.patientId'))" regex="true"> <then> <!-- Call createAppointments template to create appointments and events --> <call-template target="createAppointments"> <with-param name="cliniko.apiKey" value="{$ctx:cliniko.apiKey}" /> <with-param name="cliniko.apiUrl" value="{$ctx:cliniko.apiUrl}" /> <with-param name="cliniko.patientId" value="{$ctx:cliniko.patientId}" /> <with-param name="cliniko.practionerId" value="{$ctx:cliniko.practionerId}" /> <with-param name="cliniko.accountName" value="{$ctx:cliniko.accountName}" /> <with-param name="common.id" value="{$ctx:eventBrite.attendeeId}" /> <with-param name="cliniko.appointmentNote" value="{$ctx:livechat.ticketName}" /> <with-param name="googlecalendar.apiUrl" value="{$ctx:googlecalendar.apiUrl}" /> <with-param name="googlecalendar.accessToken" value="{$ctx:googlecalendar.accessToken}" /> <with-param name="googlecalendar.calendarId" value="{$ctx:googlecalendar.calendarId}" /> <with-param name="shared.timeZone" value="{$ctx:shared.timeZone}" /> </call-template> </then> </filter> <!-- END: Process only if the patient is existing --> <property name="attendeeIndex" expression="get-property('operation','attendeeIndex') + 1" scope="operation" /> <filter xpath="get-property('operation','attendeeIndex') = get-property('eventBrite.attendeeCount')"> <then> <loopback /> </then> </filter> </sequence> </target> </iterate> <!--END : FOR EACH ticket --> </then> <else> <property name="id" value="{}" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.error_description)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="eventBrite_listTicketClasses" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </else> </filter> <!-- END: Proceed only if the call is successful. --> </inSequence> <outSequence> <property name="messageType" value="application/json" scope="axis2" /> <filter source="boolean(get-property('operation', 'responseString'))" regex="false"> <then> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"cliniko_retrieveEventsAndCreateAppointments", "activityResponse":"No new appointments were created since the patients already have appointments." } }</format> </payloadFactory> </then> <else> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"cliniko_retrieveEventsAndCreateAppointments", "activityResponse":[$1] } }</format> <args> <arg expression="get-property('operation', 'responseString')" /> </args> </payloadFactory> </else> </filter> <send /> </outSequence> </target> <description /> </proxy>
{ "eventBrite": { "eventId": "19311042849" }, "cliniko": { "appointmentType": "Eventbrite Appointments" }, "googlecalendar": { "calendarId": "5nu6p7lmpb1anng51mi391hghs@group.calendar.google.com" }, "shared": { "timeZone": "+05:30" } }
Note
 The following are the parameter descriptions:
The name of the appointment type to which the appointments will be created.Âcliniko.appointmentType:
The ID of the common Google Calendar.googlecalendar.calendarId:
shared.timeZone:
The time zone of both the APIs 'Cliniko' and 'GoogleCalendar'. (e.g. '+05:30').eventBrite.eventId:
The ID of the event to which the appointments will be created.