Prevent the user to fill serial number that is already present in pc_hardware table for another asset.

PriyaRaj
Tera Contributor

Hi All,

I am having a requirement on catalog task form. On the form there is two editable field hostname and serial number. Serial Number auto populates when hostname is filled but if the hostname is of a new asset which is not present in pc_hardware table then the user needs to manually enter the serial number.

In manual case, we need to validate if the serial number is already present in pc_hardware table or not. If yes, we need to show the error msg with the name of asset to which the serial number is assigned and prevent saving the form.

find_real_file.png

As I am new and learning, kindly help me with the script to validate serial number and display error message.

1 ACCEPTED SOLUTION

SumanthDosapati
Mega Sage
Mega Sage

Can you try below scripts :

 Yup! You can update scripts as below

Client script : 

function onChange(control, oldValue, newValue, isLoading) {

    if (isLoading || newValue == '') {

        return;

    }

    var ga = new GlideAjax('global.CMDBClientUtils'); //update script include name as needed

    ga.addParam('sysparm_name', 'checkForSerialNumber');

    ga.addParam('sysparm_serialnumber', g_form.getValue("serial_number"));

    ga.addParam('sysparm_hostname', g_form.getValue('host_name')); //check the backend value of hostname variable

    ga.getXML(checkSerialNumber);

}




function checkSerialNumber(response) {

    var answer = response.responseXML.documentElement.getAttribute("answer");

    if (answer != 'no') {

        g_form.clearValue('serial_number');

        g_form.addErrorMessage(answer);

    }

}

 

Script Include

var CMDBClientUtils = Class.create();

CMDBClientUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {

       

        checkForSerialNumber: function () {

               try {

                var answer;

                       var serialNumber = this.getParameter('sysparm_serialnumber');

                       var hostName = this.getParameter('sysparm_hostname');

                       var grHardware = new GlideRecord('cmdb_ci_pc_hardware');

                       grHardware.addQuery('serial_number', serialNumber);

                grHardware.addQuery('name', '!=', hostName);

                       grHardware.query();

                       if (grHardware.next()) {

                                answer = 'Serial Number already exists, found in asset: ' + grHardware.getValue('name');

                       }

                else {

                       answer = 'no';

                }

                return answer;

               } catch (ex) {

                       gs.error(ex);

               }

        },




    type: 'CMDBClientUtils'

});

If the above is not working, just share the screenshot of your form which shows the hostname field and serial number field.

 

Mark as correct and helpful if it solved your query.

Regards,
Sumanth

View solution in original post

18 REPLIES 18

Ethan Davies
Mega Sage
Mega Sage

Hi Priya,

This is possible, but will require a couple of components to make it work. Before we begin, we need to design / consider / need the following:

  • A Client Callable Script Include to host a function that will perform a check to determine IF the Serial Number entered is already in the pc_hardware table or not.
  • An onChange Catalog Client Script that 'does' the check for a Serial Number every time the Serial Number field changes. This Client Script should on be set to run on 'Desktop' since we don't want it on the portal, only after it is logged. We will utilise GlideAjax for this.
  • (Optional) A step in a Flow / Workflow that sits behind your item to automatically create the new Serial Number / Hostname in the relevant table. This is optional, you may be happy with the manual process as is.

Some of the concepts here in terms of ServiceNow / Scripting aren't necessarily beginner concepts, so if anything doesn't make a lot of sense, please take the time to research and improve understanding as it will benefit you greatly in the long run.

Client Callable Script Include

find_real_file.png

Code Snippet:

var CMDBClientUtils = Class.create();
CMDBClientUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {
	
	checkForSerialNumber: function () {
		try {
			var isError = false;
			var serialNumber = this.getParameter('sysparm_serialnumber');
			var grHardware = new GlideRecord('cmdb_ci_pc_hardware');
			grHardware.addQuery('serial_number', serialNumber);
			grHardware.setLimit(1);
			grHardware.query();
			// We are just going to return a simple error message if we do / dont find the 
			if (grHardware.next()) {
				// Setting isError to TRUE to indicate that WE HAVE found a matching Serial Number.
				isError = true;
				return isError;
			} else {
				// we didn't find the serial number. You can decide what to do here, maybe you create the new pc_hardware record here instead of in the workflow / flow.
				// Is error will be false here, indicating we havent found any matching serial number.
				return isError;
			}
		} catch (ex) {
			gs.error(ex);
		}
	},

    type: 'CMDBClientUtils'
});

Catalogue Client Script

find_real_file.png

Code Snippet:

function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }
	// GlideAjax, if you're not familiar with the concepts I suggest spending some time looking it up, its super useful.
    var ga = new GlideAjax('global.CMDBClientUtils');
    ga.addParam('sysparm_name', 'checkForSerialNumber');
    ga.addParam('sysparm_serialnumber', g_form.getValue("serial_number"));
    ga.getXML(checkSerialNumber);
}

function checkSerialNumber(response) {
    var answer = response.responseXML.documentElement.getAttribute("answer");
    // Remember we are returning a boolean. If TRUE then we found the Serial Number, if FALSE we didnt.
    if (answer) {
        // Add your own error behaviours, this just an example.
        g_form.addErrorMessage('We found the Serial Number, please enter another.');
        g_form.clearValue('serial_number');
    } else {
        // Add your own success behaviours, this is just an example.
        g_form.addInfoMessage('We didnt find the Serial Number, we are all good to go.');
    }
}

 

This should be enough to get you started and to get some validation working. There are some caveats to consider though:

  • You may want to modify the GlideRecord query in the Script Include, it is just there as an example. You may have some more specific search criteria for matching with a record.
  • This will not STOP someone from submitting if they have entered a Serial Number that already exists. New behaviour / client scripts are required for that.
  • Carefully consider the client behaviour you want once we determine if the Serial Number exists or not, the ones in the client script I have written are just examples.

 

Hope this helps, let us know how you get on.

Ethan

Please mark the answer as correct if this has solved your issue, or upvote the answer if it was helpful.

Hi @Ethan Davies ,

I tried what you have given, but still no error msg is coming.

Catalog client script:

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

    var ga = new GlideAjax('global.CheckSerialNumber');
    ga.addParam('sysparm_name', 'ValidateID');
    ga.addParam('sysparm_serialnumber', g_form.getValue("serial_number"));
    ga.getXML(checkNumber);
    if (answer == true) {
        var answer = response.responseXML.documentElement.getAttribute("answer");
        if (answer) {
            g_form.addErrorMessage('Serial Number is not unique, please modify it');
            g_form.clearValue('serial_number');
        } else {
            g_form.addInfoMessage('We didnt find the Serial Number, we are all good to go.');
        }

    }


//Type appropriate comment here, and begin script below

}

 

Script Include:

var CheckSerialNumber = Class.create();
CheckSerialNumber.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    ValidateID: function() {
        try{
            //var isError = false;
        var serialNumber = this.getParameter('sysparm_serialnumber');
        var gr = new GlideRecord('cmdb_ci_pc_hardware');
        gr.addQuery('serial_number',serialNumber);
        gr.query();
        if (gs.next()) {
           // isError = true;// setting true as we found the matching serial number
            return true;
        } else {
            return false;
        }
        }catch(ex){
            gs.error(ex);
        }
    },

    type: 'CheckSerialNumber'
});

Hi @PriyaRaj ,

It looks like from your reply that your Client Script Code is a little different from the one that I copied. There is no callback function for your GlideAjax code, this is required. I have posted how the Client Code should look again below.

The checkSerialNumber function is important to the function of this client script.

function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }
	// GlideAjax, if you're not familiar with the concepts I suggest spending some time looking it up, its super useful.
    var ga = new GlideAjax('global.CMDBClientUtils');
    ga.addParam('sysparm_name', 'checkForSerialNumber');
    ga.addParam('sysparm_serialnumber', g_form.getValue("serial_number"));
    ga.getXML(checkSerialNumber);
}

function checkSerialNumber(response) {
    var answer = response.responseXML.documentElement.getAttribute("answer");
    // Remember we are returning a boolean. If TRUE then we found the Serial Number, if FALSE we didnt.
    if (answer) {
        // Add your own error behaviours, this just an example.
        g_form.addErrorMessage('We found the Serial Number, please enter another.');
        g_form.clearValue('serial_number');
    } else {
        // Add your own success behaviours, this is just an example.
        g_form.addInfoMessage('We didnt find the Serial Number, we are all good to go.');
    }
}

@Ethan Davies , but how to return the asset name with info message to which the serial number got match?