Converting a business rule to a script include

Ian Mildon
Tera Guru

I have a fairly simple before business rule that adds a message if the CI entered on an Incident record has active Change Requests against it. My issue is that I have been tasked with making this functionality work more "real time", as an "onChange" of the Incident cmdb_ci field.

And this is where my lack of knowledge on script includes comes in. I've spent quite a bit of time trying to figure this out but Script Includes just seem to confuse me.

Here is the business rule that I'm wanting to convert, it  runs before insert and update on the Incident table. I would appreciate any help on this.

var gr = new GlideRecord('change_request');
gr.addQuery('cmdb_ci', current.cmdb_ci);
gr.addQuery('active', true);
gr.query();
if (gr.next()) {
	var rc = gr.getRowCount();
	gs.addErrorMessage("This CI has " + rc + " open Changes against it");
}

 

1 ACCEPTED SOLUTION

Ian Mildon
Tera Guru

Things are a little clearer now (still pretty cloudy though!) but the main thing is that I do have a working script include and a working GlideAjax call. Plus the gr.getRowCount() does still work, so I can provide a "live" count in the alert box.

Here is the modified Script Include based off Shane J's example:

var ChangeCheck = Class.create();
ChangeCheck.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	
	getChangeRequests : function(){
		
		var ciVal = this.getParameter('sysparm_ciVal');		
		
		var gr = new GlideRecord('change_request');
		gr.addQuery('cmdb_ci', ciVal);
		gr.addQuery('active', true);
		gr.query();
		if (gr.hasNext()) {
			var rc = gr.getRowCount();
			return "This CI has " + rc + " open Changes against it";
		}
		else {
			return "This CI has no open Changes against it.";
		}
	},
	
	type: 'ChangeCheck'
});

And here is the modified onChange Client Script (also based off Shane J's example):

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
	if (isLoading || newValue === '') {
		return;
	}
	
	var ciVal = g_form.getValue('cmdb_ci');
	
	var ga = new GlideAjax('ChangeCheck');
	ga.addParam('sysparm_name', 'getChangeRequests');
	ga.addParam('sysparm_ciVal', ciVal);
	ga.getXML(chgCallback);
	
	function chgCallback(response){
		var answer = response.responseXML.documentElement.getAttribute("answer");
		
		alert(answer);
	}

Currently this is working and I have only found 1 issue so far. I found that I had to provide an alert message for the "else" part of the Script Include, otherwise I was getting an alert popup with "null" as the value.

View solution in original post

9 REPLIES 9

Could you have the answer from the Script Includes provide a less robust response if the answer is 'None' (or null) and then do an IF in your Client Script, to just "return;" instead of forcing an "alert(answer)"?

If you wanted to simplify a bit and squeeze the most out of performance (as we all should), here's an updated Script Include:

var ChangeCheck = Class.create();
ChangeCheck.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	
	getChangeRequestCount : function(){
		var count = 0;  //default to none
		var ci = this.getParameter("sysparm_ci");
		var ga = new GlideAggregate("change_request");  //faster than GlideRecord when we just need a count
		ga.addAggregate("COUNT");
		ga.addEncodedQuery("active=true^cmdb_ci=" + ci);
		ga.query();
		if (ga.next()) {
			count = ga.getAggregate("COUNT");
		}
		return count;
	},
	
	type: 'ChangeCheck'
});

It will just return the number of records found.  No message, just the number.  That way we could possibly reuse the function elsewhere.

Then, the Client Script can be simplified as well:

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
	if (isLoading || newValue === '') {
		return;
	}
	
	var ga = new GlideAjax("ChangeCheck");
	ga.addParam("sysparm_name", "getChangeRequestCount");
	ga.addParam("sysparm_ci", newValue);  //no need to g_form.getValue(), we already have the value in "newValue"
	ga.getXMLAnswer(chgCallback);
	
	function chgCallback(answer){  //the response from getXMLAnswer already just contains the value we want, no need to traverse an XML document
		alert(answer);
	}
}

You can then actually add some logic to the Client Script to do different things based on the number returned:

function chgCallback(answer){
	var count = parseInt(answer);
	var type = "info";
	var msg = "No Change Requests were found for the selected CI.";  //default
	if (count == 1) {
		msg = "1 Change Request was found for the selected CI.";
	} else if (count >= 10) {
		msg = "Whoa! " + count + " Change Requests were found for the selected CI.";
		type = "error";
	} else {
		msg = count + " Change Requests were found for the selected CI.";
	}
	g_form.showFieldMsg("cmdb_ci", msg, type);		
}

 

find_real_file.png

find_real_file.png

find_real_file.png

find_real_file.png

That way the logic to grab the number of records and whatever we may want to do with that info is kept in the appropriate places.

 

Kwabena
Tera Contributor

Utilising GlideAjax is, of course, best practice. However, for extremely simple tasks it would be feasible to simply define a function in the script include that was later executed in a call in an onChange script. Again, I would by no means suggest this, but for simple logging to avoid synchronisation errors.

Jim Coyne
Kilo Patron

Were you able to find a solution?

Yes I did. The second set of example scripts above worked. And I've since used them as a base for further script includes.