restrict a catalog item to just one time request per user

levino
Giga Guru

Hi there

i have a requirement to restrict a catalog item to just one time request per user, that is once its requested and state pending or completed it cannot be requested again.

This is requested via the servicenow portal.

the attached script does not seem to work it always comes up with the message  when i change user  'duplicate request cannot be submitted'

Thanks

Levino

 

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }
  
    var ga = new GlideAjax('restrictduplicateitem');
    ga.addParam('sysparm_name', 'restrictduplication');
    ga.addParam('sysparm_reqfor', newValue);
    ga.getXML(alertUser);

    function alertUser(response) {
        var answer = response.responseXML.documentElement.getAttribute("answer");
        if (answer) {
            g_form.showFieldMsg('requested_for', 'Duplicate request can not be submitted', 'Error');
            g_form.setValue('hidden_variable', true);
        } else {
            g_form.hideFieldMsg('hidden_variable', true);
        }
    }

}


var restrictduplicateitem = Class.create();
restrictduplicateitem.prototype = Object.extendsObject(AbstractAjaxProcessor, {
restrictduplication: function() {
       var user = this.getParameter('sysparm_user');
		var cat_item_id = this.getParameter('sysparm_catitem');
        
        var gr = new GlideRecord('sc_req_item');
        gr.addEncodedQuery('cat_item=' + cat_item_id + '^stateNOT IN3,4,7^request.requested_for=' + req_for);
        gr.query();
        if (gr.next())
            return true;
        else
            return false;
    },
    type: 'restrictduplicateitem'
});


function onSubmit() {
    //Type appropriate comment here, and begin script below
    if (g_form.getValue('hidden_variable') == 'true') {
        return false;
    }
}

 

Thanks

Levino

1 ACCEPTED SOLUTION

Ankur Bawiskar
Tera Patron
Tera Patron

Hi,

you don't require onSubmit

if the validation fails then clear the requested for and show error so that unless user selects correct user form cannot be submitted

try this

var restrictduplicateitem = Class.create();
restrictduplicateitem.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	
	
	restrictduplication: function() {
		var user = this.getParameter('sysparm_user');
		var cat_item_id = this.getParameter('sysparm_catitem');

		var gr = new GlideRecord('sc_req_item');
		gr.addEncodedQuery('cat_item=' + cat_item_id + '^stateNOT IN3,4,7^request.requested_for=' + user);
		gr.query();
		return gr.hasNext();
	},
	type: 'restrictduplicateitem'
});
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
	if (isLoading || newValue === '') {
		return;
	}

	g_form.hideFieldMsg('requested_for', true);

	if(oldValue != newValue){
		var ga = new GlideAjax('restrictduplicateitem');
		ga.addParam('sysparm_name', 'restrictduplication');
		ga.addParam('sysparm_reqfor', newValue);
		ga.getXML(alertUser);
		function alertUser(response) {
			var answer = response.responseXML.documentElement.getAttribute("answer");
			if (answer.toString() == 'true') {
				g_form.clearValue('requested_for', true);
				g_form.showFieldMsg('requested_for', 'Duplicate request can not be submitted', 'Error');
			} 
		}
	}
}

Regards
Ankur

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

20 REPLIES 20

Hitoshi Ozawa
Giga Sage
Giga Sage

Hi Levino,

Variable "request_for" is a variable in Service Catalog set when the form is submitted. As such, it's not possible to set onChange() script on it.

It is also not possible to use GlideAjax in onSubmit() script.

Therefore, to prevent end-user from submitting a duplicate request, create a before business rule on sc_request and sc_req_item tables.

Business rule on sc_request table

(function executeRule(current, previous /*null when async*/ ) {
	var cat_item_name = 'Prevent duplicate request';  // replace with service catalog form to prevent duplicate
    var grReqItem = new GlideRecord('sc_req_item');
    grReqItem.addEncodedQuery('cat_item.name=' + cat_item_name + '^stateNOT IN3,4,7^request.requested_for=' + current.requested_for);
    grReqItem.query();
    if (grReqItem.hasNext()) {
        current.setAbortAction(true);
        gs.addErrorMessage('Request can only be submitted once.');
    }
})(current, previous);

Business rule on sc_req_item table

(function executeRule(current, previous /*null when async*/ ) {
	var cat_item_name = 'Prevent duplicate request';
    var grReqItem = new GlideRecord('sc_req_item');
    grReqItem.addEncodedQuery('cat_item.name=' + cat_item_name + '^stateNOT IN3,4,7^request.requested_for=' + current.requested_for);
    grReqItem.query();
    if (grReqItem.hasNext()) {
        current.setAbortAction(true);
    }
})(current, previous);

Execution result:

step 1. New submission by user

find_real_file.png

step 2: Order created

find_real_file.png

step 3: Re-create order with same request_for

find_real_file.png

levino
Giga Guru

Thanks Hitoshi

BR might be the way to go , will test and  come back to update post

Hitoshi Ozawa
Giga Sage
Giga Sage

Hi Levino,

As I've explained above, the problem is with the requested_for. If a new field "requested_for" is added to the form, onChange() client script can be used. However, this "requested_for" will be different from the "requested_for" variable in the sc_req_item table.

So, the script include .addEncodedQuery() filter condition has to be modified to use the newly created requested_for variable added to the form instead of the request_for variable in sc_req_item.request.

To get the sys_id of requested_for variable on the form, open up the variable definition page for the variable requested_for and right click on the header and select sys_id.

Script Include

var restrictduplicateitem = Class.create();
restrictduplicateitem.prototype = Object.extendsObject(AbstractAjaxProcessor, {
    restrictduplication: function() {
        var user = this.getParameter('sysparm_user');
        var cat_item_id = 'daa58f7d9717011086d3b4b3f153af47'; // sys_id of service catalog of the form
        var requested_for = '52e58f7d9717011086d3b4b3f153af52';  // sys_id of "requested_for" variable added to the form

        var gr = new GlideRecord('sc_req_item');
        gr.addEncodedQuery('cat_item=' + cat_item_id + '^stateNOT IN3,4,7^variables.' + requested_for + '=' + user);
        gr.query();
        return gr.hasNext().toString();
    },
    type: 'restrictduplicateitem'
});

Client Script

function onChange(control, oldValue, newValue, isLoading) {
   if (isLoading || newValue == '') {
      return;
   }

	if(oldValue != newValue){
		var ga = new GlideAjax('restrictduplicateitem');
		ga.addParam('sysparm_name', 'restrictduplication');
		ga.addParam('sysparm_user', newValue);
		ga.getXML(alertUser);
		
		function alertUser(response) {
			var answer = response.responseXML.documentElement.getAttribute("answer");
			if (answer == 'true') {
				g_form.clearValue('requested_for', true);
				g_form.showFieldMsg('requested_for', 'Duplicate request can not be submitted', 'error');
			} 
		}
	}
}

Execution

case 1:New requested_for user (no duplicate)

find_real_file.png

case 2: Duplicate requested_for user

find_real_file.png

Note that by default, when submitting the form from Service Portal, ServiceNow will show a dialog box to enter Requested For user. That's the reason I've recommended to use Business Rule instead of adding request_for on the form.

find_real_file.png

Almost forgot, Field "Requested For" must be made Mandatory or else end-user will be able to submit the form without requested_for field being entered.

Script Include

  1.  Change variable "req_for" in addEncodedQuery to "user"
  2.  Changed "request.requested_for" in addEncodedQuery to "variables.' + requested_for"
  3.  Changed variable "cat_item_id" value to be fixed instead of getting it from parameter because it's static
  4.  Added variable "requested_for"
  5.  Converted return value to String (i.e. added .toString())


Client Script

  1. Change "Error" to "error" in .showFieldMsg() because JavaScript is case sensitive
  2. Delete .hideFieldMsg() because it's not needed
  3. Change addParam parameter name from "sysparm_reqfor" to "sysparm_user" to match Script Include

Script Include can be written as below to eliminate using finding sys_id of service catalog and sys_id of variable name.

var restrictduplicateitem = Class.create();
restrictduplicateitem.prototype = Object.extendsObject(AbstractAjaxProcessor, {
    restrictduplication: function() {
        var user = this.getParameter('sysparm_user');

        var catName = 'Prevent duplicate request';  // name of service catalog
        var variableName = 'requested_for';  // name of variable

        var grCat = new GlideRecord('sc_cat_item');
        if (grCat.get('name', catName)) {
            var cat_item_id = grCat.getValue('sys_id');

            var grItemOption = new GlideRecord('item_option_new');
            grItemOption.addQuery('cat_item.name', catName);
            grItemOption.addQuery('name', variableName);
            grItemOption.query();
            if (grItemOption.next()) {
                var requested_for = grItemOption.getValue('sys_id');
				
                var gr = new GlideRecord('sc_req_item');
                gr.addEncodedQuery('cat_item=' + cat_item_id + '^stateNOT IN3,4,7^variables.' + requested_for + '=' + user);
                gr.query();
                return gr.hasNext().toString();
            }
        }
		return 'false';
    },