Showing posts with label Script Include. Show all posts
Showing posts with label Script Include. Show all posts

Thursday, September 10, 2020

Make a call to the Incident Caller - How to read the Docs - Twilio Part 6

 Hi Developers,

In the last article, we have seen, how to make use of the out of the box related links on task records to make a conference call or send a message. In this article we will be creating a custom icon using UI Macro on incident form that will allow an Resolver to directly make a conference call with the Incident Caller. Seems interesting? it is!

UI macros are discrete scripted components administrators can add to the user interface. Wonder what does it mean? You might have seen little action icons next to fields on forms, for example :

This little user (Add me) icon next to the 'Assigned to' field, when clicked, adds currently logged in user to the Assigned to field.

You can visit SNGuru or check out TechNow Episode 3 video on ServiceNow Jelly Scripting by none other than @Chuck Tomasi to check the scripting logic behind this.

UI macros are typically controls that provide inputs or information not provided by existing field types. Let us understand this by means of an example :

The Show Related Incidents icon is a reference icon that appears beside the Caller field on the default incident form, when the field is populated. When clicked, it opens a browser window displaying a list of other incidents for same caller.

Now if you have got an idea about what UI Macros are and what it does, let us proceed with the development of our business requirement. Here, we will be making use of some Jelly, do not worry if you are not familiar with Jelly yet.

Step 1) Navigate to System UI > UI Macros and click 'New'

Step 2) Give it a unique name

Step 3) Replace the existing code of XML field by the following snippet :

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<style>
		.hide_icon {
			visibility: hidden;
		}
		.show_icon {
			visibility: visible;
		}
	</style>
	<g2:evaluate var="jvar_show_hide_icon" object="true" jelly="true">
		var r=new myNotifyHandler().macroVisibility();
		r;
   </g2:evaluate>
	<j:set var="jvar_n" value="Make a Call ${ref}" />
	<a id="${jvar_n}" onclick="makeCall('${ref}')" class="$[jvar_show_hide_icon]">
		<span class="glyphicon glyphicon-headphones" style="font-size:25px;color:black;text-shadow:2px 2px 4px #000000;"></span>
	</a>
	
	<script>
	function makeCall(reference){
		var a=reference.split('.');
		var referenceField=a[1];
		var c=g_form.getValue(referenceField);
		 var createRes = new GlideAjax('myNotifyHandler');
                createRes.addParam('sysparm_name', 'callCaller');
                createRes.addParam('sysparm_c', c);
                createRes.getXML();
		}
	</script>
</j:jelly>

Now let us understand the above code.

<j:set var="jvar_n" value="Make a Call ${ref}" />

In the above code Jelly tag 'set' sets a variable 'jvar_n' to the value returned from value attribute. in this particular case it will be 'Make a Call ${ref}' where '${ref}' will be replaced by the referenced field as 'incident.caller_id' and the final value will become 'Make a Call incident.caller_id'.

<a id="${jvar_n}" onclick="makeCall('${ref}')" class="$[jvar_show_hide_icon]">
		<span class="glyphicon glyphicon-headphones" style="font-size:25px;color:black;text-shadow:2px 2px 4px #000000;"></span>
	</a>

In the above code 'a' tag will create a link to our bootstrap icon specified in 'span' tag. The onclick attribute onclick="makeCall('${ref}')" fires on a mouse click on the element and Execute a JavaScript code written in 'makeCall' function when an icon is clicked.

<g2:evaluate var="jvar_show_hide_icon" object="true" jelly="true">
		var r=new myNotifyHandler().macroVisibility();
		r;
   </g2:evaluate>

The evaluate tag evaluates JavaScript code (server side), and makes variables visible to future code. Unlike other tags, the evaluate tag evaluates the content that is inside the tag as server side JavaScript. In the above code we will be calling a script include named 'myNotifyHandler' and it's function 'macroVisibility' to check whether macro should be visible to the currently logged in user or not. We will see how to write this Script Include in later steps. This function will return a class value to be set in our anchor tag later.

<style>
		.hide_icon {
			visibility: hidden;
		}
		.show_icon {
			visibility: visible;
		}
	</style>

The 'style' tag specifies styles to be applied to an element for a specified class. In our case. it will hide the icon if class is be hide_icon or will display the icon if it is show_icon.

<script>
	function makeCall(reference){
		var a=reference.split('.');
		var referenceField=a[1];
		var c=g_form.getValue(referenceField);
		 var createRes = new GlideAjax('myNotifyHandler');
                createRes.addParam('sysparm_name', 'callCaller');
                createRes.addParam('sysparm_c', c);
                createRes.getXML();
		}
	</script>

The 'script' tag is used to embed a client-side script (JavaScript). Whenever the icon is clicked this script will be executed. The parameter 'reference', in this case, will have field name as 'incident.caller_id'. Our code will retrieve the field name 'caller_id' by splitting the value and then it will call g_form method to retrieve field Caller's sys_id. Then we are calling 'callCaller' function and passing the caller sys_id to it for further processing.

I would suggest you to go through ServiceNow documentation for learning more about Jelly Tags and https://www.w3schools.com/ for HTML, CSS, Bootstrap or XML.

Step 4) Click 'Submit'

Step 5) Navigate to System UI > Script Includes and click 'New'

Step 6) Give it a (unique) name as 'myNotifyHandler' (Since, we have used the same script include name to be called in our macro).

Step 7) Make it accessible from 'All application scopes'

Step 8) Make it 'Client callable'

Step 9) Replace the existing 'Script' by the following code snippet :

var myNotifyHandler = Class.create();
myNotifyHandler.prototype = Object.extendsObject(AbstractAjaxProcessor, {
    callCaller: function() {
        var c = this.getParameter('sysparm_c');
        var gc = new GlideRecord('sys_user');
        gc.get(c);
        var cm = gc.getValue('mobile_phone');

        var r = gs.getUserID();
        var gr = new GlideRecord('sys_user');
        gr.get(r);
        var rm = gr.getValue('mobile_phone');

        var notify = new SNC.Notify();
        var from = gs.getProperty('glide.notify.task.phone_number');
        var participants = [cm.toString(), rm.toString()];

        // set up a conference call
        var conferenceCall = notify.conferenceCall();

        // set up the outbound calls for all conference call participants
        for (var i in participants) {
            var to = participants[i];
            notify.call(from, to, conferenceCall);
        }

    },
	macroVisibility: function() {
		if(gs.hasRole('itil')){
			return 'show_icon';
		}else{
			return 'hide_icon';
		}
    },
    type: 'myNotifyHandler'
});

Let us understand what this script does. let us first look at the function 'macroVisibility' :

macroVisibility: function() {
		if(gs.hasRole('itil')){
			return 'show_icon';
		}else{
			return 'hide_icon';
		}
    },

here, gs.hasRole('itil') will return true only if currently logged in user will have an role 'itil', in which case it will return 'show_icon' and tell our macro to be visible. If user doesn't have the role we will be returning 'hide_icon' and will hide the macro. Thereby we will be controlling the icon to be visible to only Resolvers or users having ITIL role in other words. 

The GlideSystem (referred to by the variable name 'gs' in any server-side JavaScript) API provides a number of convenient methods to get information about the system, the current logged in user, etc. hasRole(String roleName) method determines if the current user has at least one of the passed-in roles.  You can read more about it here.

Now let us take a look at our other function 'callCaller' :

callCaller: function() {
        var c = this.getParameter('sysparm_c');
        var gc = new GlideRecord('sys_user');
        gc.get(c);
        var cm = gc.getValue('mobile_phone');

        var r = gs.getUserID();
        var gr = new GlideRecord('sys_user');
        gr.get(r);
        var rm = gr.getValue('mobile_phone');

        var notify = new SNC.Notify();
        var from = gs.getProperty('glide.notify.task.phone_number');
        var participants = [cm.toString(), rm.toString()];

        // set up a conference call
        var conferenceCall = notify.conferenceCall();

        // set up the outbound calls for all conference call participants
        for (var i in participants) {
            var to = participants[i];
            notify.call(from, to, conferenceCall);
        }

    },

here, In the following lines of code we will be getting mobile numbers of caller of the incident and the resolver who clicked the icon :

var c = this.getParameter('sysparm_c');
        var gc = new GlideRecord('sys_user');
        gc.get(c);
        var cm = gc.getValue('mobile_phone');

        var r = gs.getUserID();
        var gr = new GlideRecord('sys_user');
        gr.get(r);
        var rm = gr.getValue('mobile_phone');

In the ServiceNow documentation here, you will find all the scripts that you can use with Notify to interact with calls and SMS messages, or to provide a custom client interface.

Notify - conferenceCall() Creates a new conference call. We have copied the code snippet available here and modified it for our purpose :

If you compare both the codes, you will realize,

var from = '+14041234567';
var participants = ['+31612345678', '+31623456789', '+31687654321'];

the above code from example snippet has been changed in our code to :

var from = gs.getProperty('glide.notify.task.phone_number');
        var participants = [cm.toString(), rm.toString()];

The system property 'glide.notify.task.phone_number' stores Notify phone number used for sending SMS-s and starting conference calls from any record that belongs to the task table (or table that extends task table).

Step 10) Click 'Submit'

Step 11) Navigate to Incident > All and open any incident record

Step 12) Right click the 'Caller' field and select 'Configure Dictionary'

Step 13) Add the attribute ref_contributions=ui_macro_name to the Attributes field and click 'Update'

Dictionary attributes alter the behavior of the table or element that the dictionary record describes.

Dictionary attribute ref_contributions displays an icon for a reference field and when the field renders on a form, it invokes the named UI macro. If there are more than one macro like in this case, they are separated by semicolons (;).

Step 14) Navigate back to your incident form and you'll see an icon next to Caller field if you will have 'itil' role.

Step 15) Click the new icon we added and you'll be added to the conference call with the caller of the current incident.

So we have created an icon next to caller that, when clicked, will allow a user with ITIL role to connect with the incident caller directly in conference call.

In next article, we will solve another business requirement. Till the time, I would recommend you to visit the sources that I have mentioned in the article to have better idea about UI Macros :

Also there is an awesome and short similar community article 'Integrating ServiceNow with Twilio Services with the help of Notify API' written by @Abhishek Gardade that would help you to picture the scenerio in one shot and it will provide the ready-made update set that you can directly download and import.

If you have any queries regarding, UI Page, UI Macro, Jelly, or Twilio, Please mention in the comments or post a question to the ServiceNow Community. We would love to help.

Thank you.

Vishal Ingle

ServiceNow Certified System Administrator

DxSherpa Technologies Pvt. Ltd.

Pune, MH, IN.

 

Tuesday, July 14, 2020

Code Smart with Script Include - How to read the Docs - Scripting Part 1

Hi Developers,
Welcome to another article in the series and the first on the scripting. Today we will talk about how to code smarter with Script Includes.
Script Includes defines a function or class to be reusable server-side script logic that execute only when explicitly called by other scripts.
Let us talk about Script Includes later someday (You still can read about them at Docs or Here). Today we will be creating a Utilities Script Include to help you code smart.
I was inspired to find this capability of script include after reading @Kalaiarasan Pushpanathan's blog post 'Unlearn Series - Common Library Functions - Part1'
You might be thinking how can we code smart using Script Includes?
First of all, using Script Includes is itself a way of coding smarter. Wondering why?
  • Script Includes are only loaded on request
  • Script Includes are reusable server-side script logic
We will be using the same capability of it for our server side scripts to make it quick and smart. How?
Let me give you some examples,
If you have a requirement, let's say, to update the Incident state based on some query. The shortest GlideRecord query will look somewhat like this :
var gr = new GlideRecord("incident");
gr.addEncodedQuery("active=true^caller_id=77ad8176731313005754660c4cf6a7de");
gr.setValue('state',2);
gr.updateMultiple();
And if you have to update another set of records to different values for different query condition on different table, you have to write it again!
But if we use the capability of re-usability of Script Includes we don't need to re-write all of the code. And In fact, your code will be reduced to a single line :
MySI.updateList('incident','active=true^caller_id=77ad8176731313005754660c4cf6a7de','state',2);
You can change the parameters (table, query, field, value) to different values to use it as per your requirement.
How to achieve it? I will demonstrate you how to create a smart Script Includes with some simple examples, Feel free to create your own with your own piece of code, and don't forget to share your new findings here on ServiceNow Community.
Step 1 : Navigate to System Definitions > Script Includes and click 'New'
(Tip : Observe the way we filter the applications in navigator, the last two letters of first word and first two letters of second word. It is a shortcut to filter applications I learned from my lead @Mouli Praneeth in one of my projects. E.g. 'ss ru' for Business Rules)

Step 2: Give it a unique name

Step 3 : Change the '
Step 4 : Delete the 'initialize' function defined in line 3 & 4.
Step 5 : Paste the following piece of code after Line 1 and click 'Submit'.
//My Smart SI - Start

SmartSI.getRecCount = function(table, query) {
var gr = new GlideRecord(table);
gr.addEncodedQuery(query);
gr.query();

return gr.getRowCount();
};

SmartSI.getRecords = function(table, query) {
var gr = new GlideRecord(table);
gr.addEncodedQuery(query);
gr.query();

return gr;
};

SmartSI.getRecList = function(table, query) {
var recList = [];
var gr = new GlideRecord(table);
gr.addEncodedQuery(query);
gr.query();
while (gr.next()) {
recList.push(gr.getUniqueValue());
}

return recList.toString();
};

SmartSI.updateList = function(table, query, field, value) {

var gr = new GlideRecord(table);
gr.addEncodedQuery(query);
gr.setValue(field, value);
gr.updateMultiple();

return '';
};

SmartSI.deleteList = function(table, query) {

var gr = new GlideRecord(table);
gr.addEncodedQuery(query);
gr.deleteMultiple();

return '';
};

//My Smart SI - End
Hurray, You are now ready to test your Script Include. Check whether executing following script in Scripts - background deletes all inactive problem records? :
SmartSI.deleteList('problem', 'active=false');
Now you are all set to modify your working Script Include with your own reusable functions and code smarter.
Thank You.
Vishal Ingle
ServiceNow Certified System Administrator
DxSherpa Technologies Pvt. Ltd.
Maharashtra, IN.