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/.
Notifications in Cliniko
The fourth use case in the Cliniko business scenario is notifications. This page describes the relevant tasks and the operations you use in the Cliniko connector and the other ESB connectors.Â
Overview
The flow for notifications is illustrated in the following diagram. The ESB connectors for Nexmo and Mandrill will be used to connect to each service.
Sending birthday wishes
- Retrieve patients celebrating their birthday from the Cliniko API using the listPatients operation and send them a birthday wish via the Nexmo API using the sendMessage operation.
Cliniko operations
Nexmo operations
Note
The patient should provide the mobile number along with the country code in order to get a successful response. (e.g : 94710425557) Â Â Â Â Â Â
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. --> <!-- send Birthday Wish to the Cliniko Patient. --> <proxy xmlns="http://ws.apache.org/ns/synapse" name="cliniko_sendBirthdayWishes" transports="https,http" startOnLoad="true" trace="disable"> <target> <inSequence> <!-- Cliniko Properties --> <property name="cliniko.apiUrl" expression="get-property('registry', 'connectors/Cliniko/apiUrl')" /> <property name="cliniko.apiKey" expression="get-property('registry', 'connectors/Cliniko/apiKey')" /> <!-- Nexmo Properties --> <property name="nexmo.apiUrl" expression="get-property('registry', 'connectors/Nexmo/apiUrl')" /> <property name="nexmo.apiKey" expression="get-property('registry', 'connectors/Nexmo/apiKey')" /> <property name="nexmo.apiSecret" expression="get-property('registry', 'connectors/Nexmo/apiSecret')" /> <!-- Common properties --> <property name="responseString" value="" scope="operation" /> <!--Call cliniko_getSettingsSeq sequence to get Account Name. --> <sequence key="cliniko_getSettingsSeq" /> <!--Call cliniko connector listPatients method to List cliniko patients . --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listPatients/> <property name="patientCount" expression="count(//patients)"/> <property name="patientIndex" value="0" scope="operation" /> <!-- START: Proceed only if there is at least one patient --> <filter xpath="get-property('patientCount') = 0"> <then> <property name="id" value="{}" /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="cliniko_listPatients" /> <with-param name="status" value="skipped" /> <with-param name="message" value="No Patient to process." /> </call-template> <loopback /> </then> <else> <!--FOR EACH Patient : BEGIN --> <iterate continueParent="false" id="patients" expression="//patients" sequential="true"> <target> <sequence> <property name="cliniko.patientId" expression="json-eval($.patients.id)" /> <property name="cliniko.patientBirthDay" expression="json-eval($.patients.date_of_birth)" /> <property name="cliniko.patientFirstName" expression="json-eval($.patients.first_name)" /> <property name="cliniko.patientPhoneNumber" expression="json-eval($.patients.patient_phone_numbers)" /> <!-- Verify the Patient Birth date match with current date and Get the patient 'Mobile' Number. --> <script language="js"> <![CDATA[ var birthdate = mc.getProperty('cliniko.patientBirthDay'); var currentdate = ''+new java.text.SimpleDateFormat('yyyy-MM-dd').format(new java.util.Date()); var spiltbirthdate = birthdate.split('-')[2]+birthdate.split('-')[1]; var newbirthday = spiltbirthdate.toString(); var spiltcurrntdate = currentdate.split('-')[2]+currentdate.split('-')[1]; if(spiltcurrntdate == newbirthday) { var phoneNumberString =mc.getProperty('cliniko.patientPhoneNumber'); if(phoneNumberString != "") { var phoneNumbers = eval("(" + mc.getProperty('cliniko.patientPhoneNumber') + ")"); var mobile=''; var type; if(phoneNumberString.charCodeAt(0) != '91' && phoneNumberString.charCodeAt(phoneNumberString.length-1) != '93') { type = phoneNumbers.phone_type; if(type == 'Mobile'){ mobile =''+phoneNumbers.number; mc.setProperty('nexmo.toMobile', mobile); } } else{ for(var i=0;i<phoneNumbers.length;i++) { type = phoneNumbers[i].phone_type; if(type == 'Mobile') { mobile =''+phoneNumbers[i].number; mc.setProperty('nexmo.toMobile', mobile); break; } } } } var patientFirstName = mc.getProperty('cliniko.patientFirstName'); var accountName = mc.getProperty('cliniko.accountName'); var text ='Hi ' + patientFirstName + ', Many Happy Returns of the day!!'+'May you be blessed with Health,Wealth and Prosperity in your life. '+'*'+accountName +'*'; mc.setProperty('nexmo.text', text); mc.setProperty('nexmo.from', accountName); mc.setProperty('nexmo.to', mobile); } ]]> </script> <sequence key="removeResponseHeaders" /> <!-- START:Proceed only if the mobile Numbers are retrieved successfully.--> <filter source="boolean(get-property('nexmo.toMobile'))" regex="true"> <then> <!--Call nexmo connector sendMessage method. --> <nexmo.init> <responseType>json</responseType> <apiUrl>{$ctx:nexmo.apiUrl}</apiUrl> <apiSecret>{$ctx:nexmo.apiSecret}</apiSecret> <apiKey>{$ctx:nexmo.apiKey}</apiKey> </nexmo.init> <nexmo.sendMessage> <to>{$ctx:nexmo.to}</to> <text>{$ctx:nexmo.text}</text> <from>{$ctx:nexmo.from}</from> <type>text</type> </nexmo.sendMessage> <property name="sendMessage.messageId" expression="json-eval($.messages[0].error-text)" /> <!-- START: Append a message to be sent to the user regarding the status of the send Message operation. --> <filter source="boolean(get-property('sendMessage.messageId'))" regex="true"> <then> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.)" /> </then> <else> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'))" /> <property name="status" value="success" /> <property name="message" value="A birthday wish has been successfully sent." /> </else> </filter> <!-- END: Append a message to be sent to the user regarding the status of the send Message operation. --> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <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 only if the mobile Numbers are retrieved successfully.--> <property name="patientIndex" expression="get-property('operation','patientIndex') + 1" scope="operation" /> <property name="index" expression="get-property('operation','patientIndex')" /> <filter xpath="get-property('operation','patientIndex') = get-property('patientCount')"> <then> <loopback /> </then> </filter> </sequence> </target> </iterate> <!--FOR EACH Patient end : END--> </else> </filter> <!-- END: Proceed only if there is at least one patient --> </inSequence> <outSequence> <!-- Send the constructed response to the user. --> <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_sendBirthdayWishes", "activityResponse":"There are no Birthday Wishes for Today" } }</format> </payloadFactory> </then> <else> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"cliniko_sendBirthdayWishes", "activityResponse":[$1] } }</format> <args> <arg expression="get-property('operation', 'responseString')" /> </args> </payloadFactory> </else> </filter> <send /> </outSequence> </target> </proxy>
 {}
Notifying appointment cancellations and creating medical alertsÂ
- Retrieve daily cancelled appointments from the Cliniko API using the listCancelledAppointments operation.
- Retrieve patient details from the Cliniko API using the getPatient operation.
- Notify patient about the cancelled appointments using the sendMessage operation in the Nexmo API.
- Create medical alert in the Cliniko API using the createMedicalAlert operation.
Cliniko operations
Nexmo operations
Prerequisites
 The mobile number of the patient should be provided with the country code. (e.g. 94710425557)  Â
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 proxy will list the patient and their cancelled Appointments.Then notify to the Patient about appointment cancellation . --> <proxy xmlns="http://ws.apache.org/ns/synapse" name="cliniko_notifyAppointmentCancellation" transports="https,http" startOnLoad="true" trace="disable"> <target> <inSequence> <!-- Cliniko Properties --> <property name="cliniko.apiUrl" expression="get-property('registry', 'connectors/Cliniko/apiUrl')" /> <property name="cliniko.apiKey" expression="get-property('registry', 'connectors/Cliniko/apiKey')" /> <!-- Nexmo Properties --> <property name="nexmo.apiUrl" expression="get-property('registry', 'connectors/Nexmo/apiUrl')" /> <property name="nexmo.apiKey" expression="get-property('registry', 'connectors/Nexmo/apiKey')" /> <property name="nexmo.apiSecret" expression="get-property('registry', 'connectors/Nexmo/apiSecret')" /> <!-- Common properties --> <property name="responseString" value="" scope="operation" /> <!--Call cliniko_getSettingsSeq sequence to get Account Name. --> <sequence key="cliniko_getSettingsSeq" /> <!--Call cliniko connector listCancelledAppointments method to List cancelled Appointments. --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listCancelledAppointments> <practitionerId>{$ctx:practitionerId}</practitionerId> <businessId>{$ctx:businessId}</businessId> <patientId>{$ctx:patientId}</patientId> </cliniko.listCancelledAppointments> <property name="cancelledAppointmentsCount" expression="count(//appointments)" /> <property name="cancelledAppointmentsIndex" value="0" scope="operation" /> <!-- START :Proceed only if there is at least one cancelled Appointment. --> <filter xpath="get-property('cancelledAppointmentsCount') = 0"> <then> <property name="id" value="{}" /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="cliniko_listCancelledAppointments" /> <with-param name="status" value="skipped" /> <with-param name="message" value="No cancelledAppointments to process." /> </call-template> <loopback /> </then> <else> <!--FOR EACH Cancelled Appointments : BEGIN --> <iterate continueParent="false" id="appointments" expression="//appointments" sequential="true"> <target> <sequence> <property name="cliniko.appointmentId" expression="json-eval($.appointments.id)" /> <property name="cliniko.cancellationNote" expression="json-eval($.appointments.cancellation_note)" /> <property name="cliniko.appointmentStart" expression="json-eval($.appointments.appointment_start)" /> <property name="cliniko.cancellationTime" expression="json-eval($.appointments.cancellation_time)" /> <property name="cliniko.patient" expression="json-eval($.appointments.patient)" /> <!-- Verify the appointment start date greater than with current date and Get the patient_Id. --> <script language="js"> <![CDATA[ var patientUrl =mc.getProperty('cliniko.patient'); var patientId=patientUrl.substring(patientUrl.lastIndexOf('/') + 1); mc.setProperty('cliniko.patientId', patientId); var appointmentStart =mc.getProperty('cliniko.appointmentStart'); var newStartDate = ''+appointmentStart.split('T')[0]; var cancellationDate =mc.getProperty('cliniko.cancellationTime'); var newCancellDate = ''+cancellationDate.split('T')[0]; var currentdate =''+new java.text.SimpleDateFormat('yyyy-MM-dd').format(new java.util.Date()); if(newCancellDate == currentdate){ if(newStartDate > currentdate) { mc.setProperty('cliniko.notify',newStartDate); } } ]]> </script> <sequence key="removeResponseHeaders" /> <!-- START: Proceed only if the cliniko.notify Property is retrieved successfully. --> <filter source="boolean(get-property('cliniko.notify'))" regex="true"> <!-- Call cliniko connector getPatient method to Get Patient Details. --> <then> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.getPatient> <patientId>{$ctx:cliniko.patientId}</patientId> </cliniko.getPatient> <property name="cliniko.patientId" expression="json-eval($.id)" /> <property name="cliniko.patientFirstName" expression="json-eval($.first_name)" /> <property name="cliniko.patientPhoneNumber" expression="json-eval($.patient_phone_numbers)" /> <!-- Get the Patient 'Mobile' Number. --> <script language="js"> <![CDATA[ var appDate =mc.getProperty('cliniko.notify'); var phoneNumberString =mc.getProperty('cliniko.patientPhoneNumber'); if(phoneNumberString != "") { var phoneNumbers = eval("(" + mc.getProperty('cliniko.patientPhoneNumber') + ")"); var mobile=''; var type=''; if(phoneNumberString.charCodeAt(0) != '91' && phoneNumberString.charCodeAt(phoneNumberString.length-1) != '93') { type = phoneNumbers.phone_type; if(type == 'Mobile'){ mobile =''+phoneNumbers.number; mc.setProperty('nexmo.toMobile', mobile); } } else{ for(var i=0;i<phoneNumbers.length;i++) { type = phoneNumbers[i].phone_type; if(type == 'Mobile') { mobile = '' + phoneNumbers[i].number; mc.setProperty('nexmo.toMobile', mobile); break; } } } } var patientFirstName =mc.getProperty('cliniko.patientFirstName'); var accountName =mc.getProperty('cliniko.accountName'); var text ='Hi ' + patientFirstName + ', Your appointment which is sheduled for '+appDate+ ' has been cancelled. Sorry for the inconvenience caused. Thank you - '+accountName; mc.setProperty('nexmo.text', text); ]]> </script> <!-- START:Proceed only if the mobile Numbers are retrieved successfully.--> <filter source="boolean(get-property('nexmo.toMobile'))" regex="true"> <then> <!--Call nexmo connector sendMessage method. --> <nexmo.init> <responseType>json</responseType> <apiUrl>{$ctx:nexmo.apiUrl}</apiUrl> <apiSecret>{$ctx:nexmo.apiSecret}</apiSecret> <apiKey>{$ctx:nexmo.apiKey}</apiKey> </nexmo.init> <nexmo.sendMessage> <to>{$ctx:nexmo.toMobile}</to> <text>{$ctx:nexmo.text}</text> <from>{$ctx:cliniko.accountName}</from> <type>text</type> </nexmo.sendMessage> <property name="sendMessage.messageId" expression="json-eval($.messages[0].error-text)" /> <!-- START: Append a message to be sent to the user regarding the status of the send Message operation. --> <filter source="boolean(get-property('sendMessage.messageId'))" regex="true"> <then> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <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('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" /> <property name="status" value="success" /> <property name="message" value="The appointment cancellation has been successfully notified." /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </else> </filter> <!-- END: Append a message to be sent to the user regarding the status of the send Message operation. --> <script language="js"> <![CDATA[ var cancellationNote =mc.getProperty('cliniko.cancellationNote'); var medicalAlert = 'Cancelled Appointment :' + cancellationNote; mc.setProperty('cliniko.name', medicalAlert); ]]> </script> <!--Call cliniko connector createMedicalAlert method to create medical alert. --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.createMedicalAlert> <name>{$ctx:cliniko.name}</name> <patientId>{$ctx:cliniko.patientId}</patientId> </cliniko.createMedicalAlert> <property name="createMedicalAlert.medicalAlertId" expression="json-eval($.id)" /> <property name="cliniko.medicalAlertId" expression="json-eval($.id)" /> <!-- START: Proceed only if medicalAlerts are created successfully --> <filter source="boolean(get-property('createMedicalAlert.medicalAlertId'))" regex="false"> <then> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'),',cliniko_medicalAlertId:',get-property('cliniko.medicalAlertId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_createMedicalAlert" /> <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('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'),',cliniko_medicalAlertId:',get-property('cliniko.medicalAlertId'))" /> <property name="status" value="success" /> <property name="message" value="The medical alert has been successfully created." /> <!--Call the responseHandler template--> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_createMedicalAlert" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </else> </filter> </then> <else> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" /> <property name="status" value="skipped" /> <property name="message" value="The patient, phone number has been not found " /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </else> </filter> <!-- END:Proceed only if the mobile Numbers are retrieved successfully.--> </then> </filter> <!-- END: Proceed only if the cliniko.notify Property is retrieved successfully. --> <property name="cancelledAppointmentsIndex" expression="get-property('operation','cancelledAppointmentsIndex') + 1" scope="operation" /> <property name="index" expression="get-property('operation','cancelledAppointmentsIndex')" /> <filter xpath="get-property('operation','cancelledAppointmentsIndex') = get-property('cancelledAppointmentsCount')"> <then> <loopback /> </then> </filter> </sequence> </target> </iterate> <!--FOR EACH Cancelled Appointments : END --> </else> </filter> <!-- END :Proceed only if there is at least one cancelled Appointment. --> </inSequence> <outSequence> <!-- Send the constructed response to the user. --> <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_cancelledAppointment", "activityResponse":"There are no cancelled Appointments for Today" } } </format> </payloadFactory> </then> <else> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"cliniko_cancelledAppointment", "activityResponse":[$1] } } </format> <args> <arg expression="get-property('operation', 'responseString')" /> </args> </payloadFactory> </else> </filter> <send /> </outSequence> </target> </proxy>
 {}
Retrieving medical alerts and notifying patientsÂ
- Retrieve medical alerts from the Cliniko API using the listMedicalAlerts operation and filter the medical alerts tagged as 'Notify to patient'.
- Retrieve patient details from the Cliniko API using the getPatient operation.
- Notify the patient by SMS using the sendMessage operation in the Nexmo API.
- Update the medical alert in the Cliniko API using the updateMedicalAlert operation.
Cliniko operations
Nexmo operations
Special Notes
The medical alerts in the following format are considered to be notified to the patients:
- 'Notify to patient:Collect the medicine'
Prerequisites
The mobile number of the patient should be provided with the country code. (e.g. 94710425557)Â
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 scenario notify the medical alerts to the patients --> <proxy xmlns="http://ws.apache.org/ns/synapse" name="cliniko_retrieveMedicalAlertsAndNotifyPatients" transports="https http" startOnLoad="true" trace="disable"> <target> <inSequence> <!-- Cliniko Properties --> <property name="cliniko.apiUrl" expression="get-property('registry', 'connectors/Cliniko/apiUrl')" /> <property name="cliniko.apiKey" expression="get-property('registry', 'connectors/Cliniko/apiKey')" /> <!-- Nexmo Properties --> <property name="nexmo.apiUrl" expression="get-property('registry', 'connectors/Nexmo/apiUrl')" /> <property name="nexmo.apiSecret" expression="get-property('registry', 'connectors/Nexmo/apiSecret')" /> <property name="nexmo.apiKey" expression="get-property('registry', 'connectors/Nexmo/apiKey')" /> <property name="responseString" value="" scope="operation" /> <!--Extract cliniko_getSettingsSeq to get details of cliniko --> <sequence key="cliniko_getSettingsSeq" /> <!--Call cliniko connector listMedicalAlerts method to list all the medical alerts. --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listMedicalAlerts /> <!-- START: Proceed only if the listMedicalAlerts method is successful. --> <filter source="$axis2:HTTP_SC" regex="200"> <then> <property name="alertIndex" expression="0" scope="operation" /> <property name="alertsCount" expression="count(//medical_alerts)" /> <!-- START: Proceed only if there is at least one medical alert. --> <filter xpath="get-property('alertsCount') = 0.0"> <then> <property name="id" value="{}" /> <property name="status" value="skipped" /> <property name="message" value="There are no medical alerts to proceed." /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="cliniko_retrieveMedicalAlerts" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </then> <else> <!--BEGIN : FOR EACH alert --> <iterate continueParent="false" id="alert" expression="//medical_alerts" sequential="true"> <target> <sequence> <property name="cliniko.alertId" expression="json-eval($.medical_alerts.id)" /> <property name="cliniko.alertName" expression="json-eval($.medical_alerts.name)" /> <property name="cliniko.patient" expression="json-eval($.medical_alerts.patient.links.self)" /> <!-- Extract the alert name and check whether it is to be notified to the patient .--> <script language="js"> <![CDATA[ var alertName = ''+mc.getProperty('cliniko.alertName'); var patientUrl = ''+mc.getProperty('cliniko.patient'); if(new java.lang.String(alertName).toLowerCase().startsWith('notify to patient')) { var alert = alertName.split(':')[1]; mc.setProperty("cliniko.alert",alert); var patient=patientUrl.substring(patientUrl.lastIndexOf('/') + 1); mc.setProperty('cliniko.patientId',patient); } ]]> </script> <!-- START: Proceed only if the alert to be notified --> <filter source="boolean(get-property('cliniko.alert'))" regex="true"> <then> <!--Call cliniko connector getPatient method to get details of a patient .--> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.getPatient> <patientId>{$ctx:cliniko.patientId}</patientId> </cliniko.getPatient> <property name="cliniko.patientFirstName" expression="json-eval($.first_name)" /> <property name="cliniko.patientId" expression="json-eval($.id)" /> <property name="cliniko.patientPhoneNumber" expression="json-eval($.patient_phone_numbers)" /> <!--Get the patient Mobile Number--> <script language="js"> <![CDATA[ var patientName = mc.getProperty('cliniko.patientFirstName'); var alert = mc.getProperty('cliniko.alert'); var phoneNumbers = eval("(" + mc.getProperty('cliniko.patientPhoneNumber') + ")"); var accountName = mc.getProperty('cliniko.accountName'); var phoneNumberString =mc.getProperty('cliniko.patientPhoneNumber'); if(phoneNumberString != "") { var mobile=''; var type; if(phoneNumberString.charCodeAt(0) != '91' && phoneNumberString.charCodeAt(phoneNumberString.length-1) != '93') { type = phoneNumbers.type; if(type == 'Mobile'){ mobile =''+phoneNumbers.number; mc.setProperty('nexmo.toMobile', mobile); } } else{ for(var i=0;i<phoneNumbers.length;i++) { type = phoneNumbers[i].phone_type; if(type == 'Mobile') { mobile =''+phoneNumbers[i].number; mc.setProperty('nexmo.toMobile', mobile); break; } } } } var message = 'Hi ' + patientName + ', This is a reminder for you - '+alert+'. Thank you - ' + accountName + '.'; mc.setProperty('nexmo.message', message); ]]> </script> <!-- START:Proceed only if the mobile Numbers are retrieved successfully.--> <filter source="boolean(get-property('nexmo.toMobile'))" regex="true"> <then> <!--Call nexmo connector sendMessage method to send a sms to the patient --> <nexmo.init> <responseType>json</responseType> <apiUrl>{$ctx:nexmo.apiUrl}</apiUrl> <apiSecret>{$ctx:nexmo.apiSecret}</apiSecret> <apiKey>{$ctx:nexmo.apiKey}</apiKey> </nexmo.init> <nexmo.sendMessage> <to>{$ctx:nexmo.toMobile}</to> <text>{$ctx:nexmo.message}</text> <from>{$ctx:cliniko.accountName}</from> <type>text</type> </nexmo.sendMessage> <sequence key="removeResponseHeaders" /> <property name="sendMessage.messageId" expression="json-eval($.messages[0].error-text)" /> <!-- START: Append the response according to the status of the sendMessage call--> <filter source="boolean(get-property('sendMessage.messageId'))" regex="true"> <then> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <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('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_medicalAlertId:',get-property('cliniko.alertId'))" /> <property name="status" value="success" /> <property name="message" value="The alert has been successfully notified to the patient." /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <!--Call cliniko connector updateMedicalAlert method to update the medical alert --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.updateMedicalAlert> <medicalAlertId>{$ctx:cliniko.alertId}</medicalAlertId> <name>{$ctx:cliniko.alert}</name> </cliniko.updateMedicalAlert> <property name="cliniko.updateAlertId" expression="json-eval($.id)" /> <!-- START: Append the response according to the status of the updateMedicalAlert call--> <filter source="boolean(get-property('cliniko.updateAlertId'))" regex="false"> <then> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_medicalAlertId:',get-property('cliniko.alertId'))" /> <property name="status" value="error" /> <property name="message" expression="json-eval($)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="Cliniko_updateMedicalAlert" /> <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: Append the response according to the status of the updateMedicalAlert call--> </else> </filter> <!-- END: Append the response according to the status of the sendMessage call--> </then> <else> <property name="id" expression="fn:concat('cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_medicalAlertId:',get-property('cliniko.alertId'))" /> <property name="status" value="skipped" /> <property name="message" value="The mobile number of the patient is not found." /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="nexmo_notifyPatient" /> <with-param name="id" value="{$ctx:id}" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> </else> </filter> <!-- END:Proceed only if the mobile Numbers are retrieved successfully.--> </then> </filter> <!-- END: Proceed only if the alert to be notified --> <property name="alertIndex" expression="get-property('operation','alertIndex') + 1" scope="operation" /> <filter xpath="get-property('operation','alertIndex') = get-property('alertsCount')"> <then> <loopback /> </then> </filter> </sequence> </target> </iterate> <!--END : FOR EACH alert --> </else> </filter> <!-- END: Proceed only if there is at least one medical alert --> </then> <else> <property name="id" value="{}" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.)" /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="cliniko_retrieveMedicalAlerts" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback /> </else> </filter> <!-- END: Proceed only if the listMedicalAlerts method 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_retrieveMedicalAlertsAndNotifyPatients", "activityResponse":"There are not medical alerts to be notified to the patient." } }</format> </payloadFactory> </then> <else> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"cliniko_retrieveMedicalAlertsAndNotifyPatients", "activityResponse":[$1] } }</format> <args> <arg expression="get-property('operation', 'responseString')" /> </args> </payloadFactory> </else> </filter> <send /> </outSequence> </target> <description /> </proxy>
 {}
Retrieving products and sending reports
- Retrieve all products from the Cliniko API using the listProducts operation.
- Notify customer regarding the stock level through the Mandrill API using the sendMessage operation only if the stock level is low.
Cliniko operations
Mandrill operations
Special Notes
 Make sure to give supplier's details along with the reorder level when creating the products and it should be in the following format:
- 'AWS (Pvt) Ltd-yasasitest@gmail.com (Reorder Level:200)'
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. --> <!--Send the details of the product with lower stock levels to the cliniko administrator.--> <proxy xmlns="http://ws.apache.org/ns/synapse" name="cliniko_notifyStockLevels" transports="https http" startOnLoad="true" trace="disable"> <description /> <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')" /> <!-- Madnrill Properties --> <property name="mandrill.apiUrl" expression="get-property('registry', 'connectors/Mandrill/apiUrl')" /> <property name="mandrill.apiKey" expression="get-property('registry', 'connectors/Mandrill/apiKey')" /> <property name="mandrill.fromName" expression="json-eval($.mandrill.fromName)" /> <property name="mandrill.fromEmail" expression="json-eval($.mandrill.fromEmail)" /> <!--Extract cliniko_getSettingsSeq to get details of cliniko.--> <sequence key="cliniko_getSettingsSeq" /> <!--Call cliniko connector listProducts method to list all the products. --> <cliniko.init> <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl> <apiKey>{$ctx:cliniko.apiKey}</apiKey> </cliniko.init> <cliniko.listProducts/> <!-- START: Proceed only if the Products are retrieved successfully. --> <filter source="$axis2:HTTP_SC" regex="200"> <then> <property name="cliniko.productCount" expression="count(//products)" /> <!-- START: Proceed only if there is at least one product. --> <filter xpath="get-property('cliniko.productCount') = 0.0"> <then> <property name="id" value="{}" /> <property name="status" value="skipped" /> <property name="message" value="There are no products to process." /> <call-template target="responseHandlerTemplate"> <with-param name="id" value="{$ctx:id}" /> <with-param name="activity" value="cliniko_listProducts" /> <with-param name="status" value="{$ctx:status}" /> <with-param name="message" value="{$ctx:message}" /> </call-template> <loopback/> </then> <else> <!-- Extract the re-order point for the product --> <script language="js"> <![CDATA[ var payload = mc.getPayloadJSON(); var products = payload.products; var prodString=''; var requesterName = mc.getProperty('cliniko.adminFirstName'); var requesterEmail = mc.getProperty('cliniko.adminEmail'); var mailHTML = "<h3>Dear " + requesterName + ",</h3><p>Please be informed that the following products are running out of the stock.</p><br/><div><style>table, th, td {border-style: solid; border-width: 1px;}</style><table><tr><th>Name</th><th>Stock Level</th><th>Re-Order Level</th></tr>"; for(var i=0;i<products.length;i++) { var id = products[i].id; var name = products[i].name; var supplier = ''+products[i].product_supplier_name; supplier = supplier.split('-')[1]; var stockLevel = products[i].stock_level; var reOrderPoint = supplier.match(/\(([^)]+)\)/)[1].split(':')[1]; if(reOrderPoint != undefined || reOrderPoint !=null ) { if(stockLevel<=reOrderPoint) { var stock = id+'-'+stockLevel+','; mailHTML = mailHTML + "<tr><td> "+name+ "</td><td>"+stockLevel+"</td><td>"+reOrderPoint+"</td></tr>"; prodString = prodString + stock; } } } mailHTML = mailHTML + "</table></div><br/><p>This is an auto-generated email. Please do not reply.</p><p>Thank you</p>"; mc.setProperty('mandrill.html', mailHTML); mc.setProperty('mandrill.subject', 'Stock Report'); var mailTo = '[{"email": "' + requesterEmail + '", "name": "' + requesterName + '", "type": "to"}]'; mc.setProperty('mandrill.to', mailTo); ]]> </script> <property name="mandrill.html" expression="fn:concat('<html>', get-property('mandrill.html'), '</html>')" /> <!-- Call mandril sendMessage method to Send stock level to the customer. --> <mandrill.init> <apiKey>{$ctx:mandrill.apiKey}</apiKey> <apiUrl>{$ctx:mandrill.apiUrl}</apiUrl> <format>json</format> </mandrill.init> <mandrill.sendMessage> <html>{$ctx:mandrill.html}</html> <subject>{$ctx:mandrill.subject}</subject> <fromEmail>{$ctx:mandrill.fromEmail}</fromEmail> <fromName>{$ctx:mandrill.fromName}</fromName> <important>false</important> <autoHtml>true</autoHtml> <urlStripQs>false</urlStripQs> <preserveRecipients>true</preserveRecipients> <viewContentLink>true</viewContentLink> <to>{$ctx:mandrill.to}</to> </mandrill.sendMessage> <property name="mandrill.mailId" expression="json-eval($[0]._id)" /> <!-- START: Append a message to be sent to the user regarding the status of the send email operation. --> <filter source="boolean(get-property('mandrill.mailId'))" regex="true"> <then> <property name="id" value="{}" /> <property name="status" value="success" /> <property name="message" value="Insufficient stock levels of the products have been successfully notified to the administrator." /> </then> <else> <property name="id" value="{}" /> <property name="status" value="error" /> <property name="message" expression="json-eval($)" /> </else> </filter> <!-- END: Append a message to be sent to the user regarding the status of the send email operation. --> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="mandrill_sendStockDetails" /> <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 there is at least one product --> </then> <else> <property name="id" value="{}" /> <property name="status" value="error" /> <property name="message" expression="json-eval($.)" /> <call-template target="responseHandlerTemplate"> <with-param name="activity" value="cliniko_listProducts" /> <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 product are retrieved successfully. --> </inSequence> <outSequence> <property name="messageType" value="application/json" scope="axis2" /> <payloadFactory media-type="json"> <format>{ "Response":{ "process":"cliniko_notifyStockLevels", "activityResponse":[$1] } }</format> <args> <arg expression="get-property('operation', 'responseString')" /> </args> </payloadFactory> <send /> </outSequence> </target> </proxy>
{ "mandrill": { "fromEmail": "etriggerit@gmail.com", "fromName": "ETrigger Admin" } }
Note
 The following are the parameter descriptions:
The name of the company/person to be used as the sender name when sending the stock report.mandrill.fromName :
E-mail of the company/person to be used as the sender e-mail when sending the report.mandrill.fromEmail :