scanning laptop serial to look up user information and creating interaction ticket - peform check in

chercm
Mega Sage

created a service portal widget but after entering the serial number nothing happens. 

 

chercm_0-1702566186390.png

 

 

Client :

// Widget Script

function handleCheckIn() {

    // Get the scanned barcode from the input field

    var scannedBarcode = document.getElementById('barcodeInput').value;

 

    // Call a function to process the scanned barcode (e.g., initiateCheckInProcess)

    initiateCheckInProcess(scannedBarcode);

 

    // Clear the input field for the next scan

    document.getElementById('barcodeInput').value = '';

}

 

function initiateCheckInProcess(scannedBarcode) {

    // Example: Query the alm_hardware table to find the hardware record based on the scanned barcode

    var hardwareRecord = new GlideRecord('alm_hardware');

    hardwareRecord.addQuery('serial_number', scannedBarcode);

    hardwareRecord.query();

 

    if (hardwareRecord.next()) {

        // Hardware record found, get the assigned user

        var assignedUser = hardwareRecord.assigned_to;

        

        // Check if the assigned user is valid

        if (assignedUser) {

            // Create an interaction ticket

            var interaction = new GlideRecord('interaction');

            interaction.initialize();

            interaction.caller_id = assignedUser;

            interaction.location = hardwareRecord.location; // Assuming 'location' is a field on the hardware table

            interaction.reason = "Laptop refresh";

            interaction.insert();

 

            // Log success or perform additional actions

            gs.info('Check-in process initiated for user: ' + assignedUser.getDisplayValue());

        } else {

            // Assigned user not found, log an error or handle as needed

            gs.error('Assigned user not found for hardware with serial number: ' + scannedBarcode);

        }

    } else {

        // Hardware record not found, log an error or handle as needed

        gs.error('Hardware record not found for serial number: ' + scannedBarcode);

    }

}

 

 

html template. :

 

<!-- Barcode Check-In Widget Template -->

<div class="barcode-checkin-widget">

    <label for="barcodeInput">Scan Barcode:</label>

    <input type="text" id="barcodeInput" placeholder="Scan barcode..." autofocus>

    <button onclick="handleCheckIn()">Check-In</button>

</div>

4 ACCEPTED SOLUTIONS

Well, your code is faulty: 1st you load the asset's user (assigned to) only after that you check whether the asset's user (assigned to) is actually filled in or not.

And that assuming that you have an actual user id in the actual code in line:

alm_hardware.addQuery('serial_number', 'your_serial_number');

Otherwise the Opened for always ends up empty.

 

Also why would you look up and load the same thing twice?

I mean you 1st load the asset to get the assigned to user than you load the asset once more to check whether the assigned to user is filled in or not and do the rest of the stuff.

Try formatting your code, maybe it will make such things more obvious.

 

Also you are not calling createInteraction function with the expected data type: parameter userId - it seems - must be a string.

 

A functioning code should at minimum look something like:

	function lookUpAssetAndCreateInteraction (barCode) {
		var alm_hardware = new GlideRecord('alm_hardware');

		alm_hardware.setLimit(1);

		if (alm_hardware.get('serial_number', barCode)) {
			if (!alm_hardware.assigned_to.nil()) {
				var facade = new sn_walkup.ExtPointUtil().loadExtension('InteractionFacade');
				var queueId = '775bd4f62fd5b110207170682799b6c6';
				var reasonId = '837468135b8b3300f6bc098b41f91ab8';
				var reasonDescription = 'Something not working';
				var badgeId = true;

				return facade.createInteraction(
					// Here a string is needed, not an object -
					// alm_hardware.assigned_to is an object, a GlideRecord,
					// '' + alm_hardware.assigned_to on the other hand is a string
					'' + alm_hardware.assigned_to,
					queueId,
					reasonId, // reasonID
					reasonDescription, // reason description
					false, // is_guest
					'', // guest_name
					'', // guest_email
					false, // is_online_checkin
					false, // is_appointment
					badgeId ? true : false // is_badge_checkin
				);
			}
			else {
				data.error = gs.getMessage('Assigned user not found for hardware with serial number: {0}', barCode);
			}
		}
		else {
			data.error = gs.getMessage('Hardware record not found for serial number: {0}', barCode);
		}
	}

 

Pasting only function lookUpAssetAndCreateInteraction here.

I am assuming that the rest is correct, like the queue id and that if there is an extension point defined, it is working - I have tested with OOB.

View solution in original post

That means you have not updated your Script Include code as suggested previously.

You should have in it

MyScriptInclude.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {

not

MyScriptInclude.prototype = Object.extendsObject(AbstractAjaxProcessor, {

View solution in original post

I assume that is because the user has stuff assigned to him that has no serial number.

You could handle this in two ways - depending on the business requirements:

 

- eliminate assets without a serial number by adding one more condition to the GlideRecord in the server side script include:

 

gr.addQuery('assigned_to', openedForSysId); // Assuming 'opened_for' is a reference field to sys_user
gr.addNotNullQuery('serial_number') // Don't load assets with no serial number

 

 

- or add something else instead of the serial number - if it is missing - when loading the assets:

 

while (gr.next()) {
	serialNumbers.push(gr.serial_number.nil() ?
		'#N/A (' + gr.model.getDisplayValue() + ')' :
		gr.serial_number.toString());
}

 

View solution in original post

Well, sometimes I get the feeling you are not reading my posts :-).

To quote myself from above:

Which raises the issue that even my configuration is not correct as for this script the proper configuration is Mobile / Service Portal really as variable g_modal is not available in Core UI, so the script would fail in that UI.

For Core UI (what you call "classic workspace"*) the solution is totally different, one based on GlideModal and UI Pages.

 

If you want to support both UIs, you could write a Client Script something like below:

function onChange (control, oldValue, newValue, isLoading, isTemplate) {
	if (newValue != '')
		getMessage('Incidents of the Opened for user', showList(newValue));

	function showList (callerId) {
		return function (title) {
			if (typeof g_modal == 'undefined')
				showListInCoreUI(title, callerId);
			else
				showListInWorkspace(title, encodeURIComponent('caller_id=' + callerId + '^ORDERBYDESCsys_created_on'));
		};
	}

	function showListInCoreUI (title, callerId) {
		var $gm = new GlideModal('show_list');

		$gm.setTitle(title);
		$gm.setSize(768);
		$gm.setPreference('focusTrap', true);
		$gm.setPreference('table', 'incident_list');
		$gm.setPreference('sysparm_query', 'caller_id=' + callerId + '^ORDERBYDESCsys_created_on');
		$gm.setPreference('sysparm_view', 'sys_popup');

		$gm.render();
	}

	function showListInWorkspace (title, query) {
		g_modal.showFrame({
			'height': '64rem',
			'size': 'lg',
			'title': title,
			'url': '/incident_list.do?sysparm_query=' + query + '&sysparm_isWorkspace=true&sysparm_view=sys_popup',
		});
	}
}

As is this uses not GlideAjax, so the Script Include is not even needed anymore.

And pops up mostly the same dialog in both "places".

 

This could be enhanced so that the Script Include is repurposed to return the no. of incidents an Opened for user has and only do the popping if there is at least one incident - using GlideAjax, of course.

 

Also it would be possible to do a Workspace native solution where the dialog is defined in UI Builder, end responding to framework events triggers the dialog, but it would be far more complex.

And the difference would be maybe nicer visuals (in Service Operations Workspace).

 

*) In ServiceNow world classic and workspace are actually yin and yen - two different, opposing terms when talking about UI; workspace is what replaces classic UI, so anything but the same thing.

View solution in original post

68 REPLIES 68

That code does not translates to the logic - if it is a of the form xxx:xxx then do one thing otherwise do the other thing.

On the other hand it is much simpler to just add two buttons to the form: 1 that triggers the laptop lookup, another 1 that triggers badge lookup.

chercm
Mega Sage

@-O-  can i check for the widget that was created , how can i add it to the All menu for easy reference ?

 

chercm_1-1703510943965.png

 

 

chercm_0-1703510925953.png

 

Sure, just press the pencil-in-the-box icon (positioned before the star icon) and you can than add items (Modules) to the Self-Service Application.

However you could also give History a try, which - I believe - should be called "Recent Items", cause that is what it does, it offers easy access to recently opened Modules.

Also if you are editing the widget in Core UI form, you can pop up the hamburger menu (Additional actions) and mark the current form as favorite.

Than you can easily look it up through the Favorites menu (vs. All).

I would say History and Favorites are the preferred way to create - one way or another - temporary Modules.

Applications (e.g. Self-Service) and Modules (e.g. Business Applications) are record of type Application File, which are captured into Update Sets and are meant be moved between instances.

Favorite and History on the other hand are data records that are not captured into Update Sets and are not meant to be moved from development to production instance.

@-O- does this script look correct to load last 10 tickets when the interaction loads ?

 

/ Example client script

function displayLast10Tickets() {

    // Assuming you have a GlideRecord query to fetch the last 10 tickets

    var ga = new GlideAjax('YourAjaxScript'); // Replace with your actual script include or other server-side script

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

    ga.addParam('sysparm_opened_for', g_form.getValue('opened_for')); // Get the opened_for value from the form

 

    ga.getXML(function (response) {

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

        // Display the results in a modal/pop-up

        g_modal.show('Last 10 Tickets', answer);

    });

}

 

 

// Example server-side script include

var Last10TicketsUtil = Class.create();

 

Last10TicketsUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    getLast10Tickets: function () {

        var openedFor = this.getParameter('sysparm_opened_for');

        var gr = new GlideRecord('your_ticket_table');

        gr.addQuery('opened_for', openedFor);

        gr.orderByDesc('sys_created_on');

        gr.setLimit(10);

        gr.query();

 

        var result = '';

        while (gr.next()) {

            // Format the results as needed

            result += 'Ticket Number: ' + gr.getValue('number') + '<br>';

        }

 

        return result;

    }

});

 

onload 

 

// Example onchange client script on the interaction form g_form.addOnChange('opened_for', displayLast10Tickets);