Send user to RITM instead of REQ when submitting a catalog item

j3ssicav
Kilo Expert

We are running Madrid and have the OOB widgets for sc-checkout and widget-sc-cat-item-v2.

We are about to go live with Service Portal for our IT catalog for the first time (have been using CMS).  We would like a catalog item submit to redirect to the RITM instead of REQ. REQs only seem relevant to us when they are using Order Guides and we have not gone live with any yet- just single submit catalog items. Also there are no notifications sent for REQ comments so we don't want to confuse customers.

I have cloned both widgets and have attempted to follow the instructions for https://community.servicenow.com/community?id=community_question&sys_id=5052e878db679bc0fff8a345ca96... 

It is slightly outdated though and I feel like I might be missing a piece of the puzzle. It redirects to the correct page now but shows the request instead of the RITM. The function they mention looks different on my version so I updated to the best of my ability. I was unclear about what to update on the checkout widget as well.

1 ACCEPTED SOLUTION

Josh Virelli
Tera Guru

Okay I have it figured out, it is very similar to my other post.

First, make sure your clone of the Catalog Checkout widget has a unique ID. We'll need this is in our other widget. I've named mine "jessicas-checkout"

find_real_file.png

Whatever the ID is, copy it and we'll put it in line 21 of the server script of the other widget (the clone of SC Catalog Item)

find_real_file.png

This will associate the two widgets so that when you click "Order Now" our custom Catalog Checkout widget will display.

Then it's time to edit the Checkout widget to insert a check for one RITM before the redirect, and if it finds one, redirect to the ticket page with the RITM, instead of the sc_request.

We do this by updating the data object in the server synchronously, so we have to wait until the server returns a value before we redirect with the $location service. You can simply copy and paste these into your Server script and Client controller respectively, I just wanted to explain a bit of what's happening here since you will have to support it going forward 🙂  It also looks like there is a redirect handled on the SC Catalog Item widget, but I believe that only applies if you are not using the modal Checkout widget. In any case, make sure to test this with Order guides, record producers, and any type of catalog item you can think of before moving it to production.

 

Server script

(function() {
	data.action = options.action;
	if (data.action)
		data.item = options.item;
	else
		data.action = 'checkout';
	
	if (input && input.action == "from_attachment")
		return;

	var cartName = '';
	if (input)
		cartName = input.cart.name;
	else if (options.cart)
		cartName = options.cart.name;

	var m = data.msgs = {};
	m.dialogTitle = gs.getMessage("Delete Attachment");
	m.dialogMessage = gs.getMessage("Are you sure?");
	m.dialogOK = gs.getMessage("OK");
	m.dialogCancel = gs.getMessage("Cancel");
	m.renameSuccessMsg = gs.getMessage("Attachment renamed successfully");
	m.deleteSuccessMsg = gs.getMessage("Attachment deleted successfully");
	m.delete_attachment = gs.getMessage("Delete Attachment?");
	m.requestSubmitted = gs.getMessage("Thank you, your request has been submitted.");
	if (data.item.request_method == "request") {
		m.checkOutMsg = gs.getMessage("Request");
		m.checkoutPopupTitle = gs.getMessage("Request Confirmation");
	} else {
		m.checkOutMsg = gs.getMessage("Checkout");
		m.checkoutPopupTitle = gs.getMessage("Order Confirmation");
	}

	data.maxAttachmentSize = parseInt(gs.getProperty("com.glide.attachment.max_size", 1024));
	if (isNaN(data.maxAttachmentSize))
		data.maxAttachmentSize = 24;
	m.largeAttachmentMsg = gs.getMessage("Attached files must be smaller than {0} - please try again", "" + data.maxAttachmentSize + "MB");
	
	var cartJS;
	if (data.action !== 'order_now') {
		cartJS = new sn_sc.CartJS(cartName, '' + gs.getUser().getID());
		
		if (input && input.action === "change_shipping_info") {
			cartJS.setSpecialInstructions(input.special_instructions);
			cartJS.setRequestedFor(input.requestedFor);
			cartJS.setDeliveryAddress(input.deliverTo);
		}
	}
	
	if (input && input.action == 'order_guide') {
		var guideJS = new sn_sc.OrderGuide('' + cartName);
		cartJS = new sn_sc.CartJS('' + cartName);
		for(var i = 0; i < input.item.items.length; i++) {
			guideJS.navigateFromMap(input.item.items[i]);
		}
		cartJS.activateGuide();
		cartJS.setRequestedFor(input.requested_for);
		cartJS.setDeliveryAddress(input.delivery_address);
		cartJS.setSpecialInstructions(input.special_instructions);
		cartJS.setParentParams(input.parentParams);
		var request = cartJS.checkoutGuide();
		data.result = {sys_id: request.request_id, number: request.request_number, table: 'sc_request'};
		$sp.logStat('Checkout Request', 'sc_request', request.request_id);
		return;
	}
	
	if (input && input.action === 'checkout') {
		var request = cartJS.checkoutCart(true);
		data.result = {sys_id: request.request_id, number: request.request_number, table: 'sc_request'};
		$sp.logStat('Checkout Request', 'sc_request', request.request_id);
		return;
	}

//This is where we determine if there is one RITM associated and return something in data.ritmId if so for the client controller
		if(input && input.requestId){
			//Search for related RITMs
			var ritm = new GlideRecord('sc_req_item');
			ritm.addQuery('request',input.requestId);
			ritm.query();
			//If exactly one RITM is returned, pass to the Client Controller to redirect user
			if(ritm.next() && (ritm.getRowCount() == 1)){
				data.ritmId = ritm.getUniqueValue();
			}
		}
	
	if (data.action !== 'order_now')
		data.cart = cartJS.getCartDetails(false);
	else
		data.cart = {name: cartName, sys_id: gs.generateGUID(), requested_for: gs.getUser().getID(), requested_for_display_name: gs.getUser().getDisplayName(), delivery_address: sn_sc.CartJS.getRequestedForAddress(gs.getUser().getID())};

	if (options && options.parentParams && options.parentParams.sysparm_parent_table && options.parentParams.sysparm_parent_sys_id && options.parentParams.sysparm_parent_sys_id != -1) { //if parent is passed
			var gr = new GlideRecord('request_parent_mapping');
			gr.get('parent_table', options.parentParams.sysparm_parent_table);
			gr.query();
			if (gr.next()) {
				var parent = new GlideRecord(options.parentParams.sysparm_parent_table);
				parent.get(options.parentParams.sysparm_parent_sys_id);
				if (JSUtil.notNil(parent.getValue(gr.requested_for_field))) {
					data.cart.requested_for = parent.getValue(gr.requested_for_field);
					data.cart.requested_for_display_name = parent.getDisplayValue(gr.requested_for_field);
					data.cart.delivery_address = sn_sc.CartJS.getRequestedForAddress(data.cart.requested_for);
				}
				data.parentParams = options.parentParams;
			}
	}
	
	if (options && options.requested_for && options.requested_for.id) { //If Passed via options
			data.cart.requested_for = options.requested_for.id;
			data.cart.requested_for_display_name = options.requested_for.displayValue;
			data.cart.delivery_address = sn_sc.CartJS.getRequestedForAddress(options.requested_for.id);
	}

	if (data.request_for) { //if value is changed by user
		var user = GlideUser.getUserByID(data.request_for);
		if (user.exists()) {
			data.cart.requested_for = data.request_for;
			data.cart.requested_for_display_name = user.getDisplayName();
			data.cart.delivery_address = sn_sc.CartJS.getRequestedForAddress(data.request_for);
		}
	}

	data.disable_req_for = sn_sc.CartJS.canViewRF();
	var reqForDispCols = gs.getProperty("glide.sc.request_for.columns");
	if (reqForDispCols && reqForDispCols.length > 0) {
		 reqForDispCols = reqForDispCols.replace(/;/g, ",")
		 reqForDispCols = "name," + reqForDispCols;
	}
	data.reqForDispCols = reqForDispCols || "name";
	data.reqForQuery = gs.getProperty("glide.sc.request_for.query");
	
})();

 

Client Controller

function($scope, $http, $timeout, $location, spScUtil, nowAttachmentHandler, spUtil, $log, spAriaUtil, $q, spAtf, spModal, spAriaFocusManager) {
	var c = this;
	c.showSpecialInstructions = false;
	c.showDeliveryAddr = false;

	c.updateDetails = function() {
		c.deliverTo = c.data.cart.delivery_address;
		c.special_instructions = c.data.cart.special_instructions;
		c.requestedFor = {
			displayValue: c.data.cart.requested_for_display_name,
			value: c.data.cart.requested_for,
			name: 'requested_for'
		};
	}


	spAtf.init().then(function(atf) {
		$scope._atf = atf;
		atf.expose('checkout_util', checkoutUtil);
	});

	var checkoutUtil = {
		checkout: function() {
			var defer = $q.defer();
			$scope.c.triggerCheckout();
			var cleanUp;
			var isOrderGuide = c.data.action == 'order_guide';
			if(isOrderGuide)
				cleanUp = $scope.$on('$sp.sc_order_guide.submitted', function(o, result) {
					$timeout(function() {
						cleanUp();
						defer.resolve(result);
					}, 10);
				});
			else
				cleanUp = $scope.$on('$sp.sc_cat_item.submitted', function(o, result) {
					$timeout(function() {
						cleanUp();
						defer.resolve(result);
					}, 10);
				});
			return defer.promise;
		}
	}

	$scope.$on('dialog.upload_too_large.show', function(e){
		$log.error($scope.m.largeAttachmentMsg);
		spUtil.addErrorMessage($scope.m.largeAttachmentMsg);
	});

	$scope.m = $scope.data.msgs;
	$scope.checkOutMsg = $scope.m.checkOutMsg;
	$scope.checkoutPopupTitle = $scope.m.checkoutPopupTitle;
	var ah = $scope.attachmentHandler = new nowAttachmentHandler(function (attachments, action) {
		$scope.attachments = attachments;
		if (action === "added")
			$scope.setFocusToAttachment();
		if (action === "renamed")
			spAriaUtil.sendLiveMessage($scope.m.renameSuccessMsg);
		if (action === "deleted")
			spAriaUtil.sendLiveMessage($scope.m.deleteSuccessMsg);
		spUtil.get($scope, {action: "from_attachment"});
	}, function (error) {
		spUtil.addErrorMessage(error.msg + error.fileName);
	});

	ah.setParams('sc_cart', c.data.cart.sys_id, 1024 * 1024 * $scope.data.maxAttachmentSize);

	$scope.attachmentHandler.getAttachmentList();

	$scope.confirmDeleteAttachment = function(attachment) {
		spModal.confirm($scope.data.msgs.delete_attachment).then(function() {
			$scope.attachmentHandler.deleteAttachment(attachment);
			$scope.setFocusToAttachmentButton();
		});
	}

	c.changeShippingInfo = function() {
		if (c.data.action !== 'order_now')
			c.server.get({
				action: "change_shipping_info",
				requestedFor: c.requestedFor.value,
				special_instructions: c.special_instructions,
				deliverTo: c.deliverTo,
				cart: {name: c.data.cart.name}
			}).then(function(response) {
				c.data.cart = response.data.cart;
				c.updateDetails();
			});
	}

	c.triggerCheckout = function() {
		var newURL;
		var page = 'sc_request';
		var table = 'sc_request';

		c.checkoutInProgress = true;
		var additionalParms = {'sysparm_requested_for': c.requestedFor.value,
							   'special_instructions': c.special_instructions,
							   'delivery_address': c.deliverTo
							  };
		if (c.data.parentParams) {
			additionalParms.sysparm_parent_sys_id =  c.data.parentParams.sysparm_parent_sys_id;
			additionalParms.sysparm_parent_table = c.data.parentParams.sysparm_parent_table;
		}
		if (c.data.action == 'order_now') {
			spScUtil.orderNow(c.data.item.sys_id, c.data.item.quantity, c.data.item.fields, c.data.item.newRecordID, additionalParms).then(function(response) {
				var a = response.data.result;
				if (!$scope.data.parentParams)
					$scope.$emit("$$uiNotification", a.$$uiNotification);
				$scope.$emit("$sp.sc_cat_item.submitted", a);
				if (c.options.auto_redirect == 'false') {
					$rootScope.$broadcast("$sp.service_catalog.cart.submitted", true);
					spUtil.addInfoMessage($scope.m.requestSubmitted);
					return;
				} else if (!$scope._atf) {
					//Update the server and see if exactly one RITM is returned, 
					c.data.requestId = a.sys_id;
					c.server.update().then(function(){
						var redirectSysId = c.data.requestId;
						//if one RITM is returned, redirect to ticket page for that RITM. Otherwise redirect to sc_request
						if(c.data.ritmId){
							page = 'ticket';
							table = 'sc_req_item';
							redirectSysId = c.data.ritmId;
						}
						newURL = $location.search('&id=' + page + '&is_new_order=true&table='+ table + '&sys_id=' + redirectSysId);
						spAriaFocusManager.navigateToLink(newURL.url());
					});
				}
			});
		} else if (c.data.action == 'order_now_wishlisted_item') {
			spScUtil.orderWishlistedItem(c.data.item.sys_id, c.data.item.quantity, c.data.item.fields, c.data.item.newRecordID, additionalParms).then(function(response) {
				var a = response.data.result;
				if (!$scope.data.parentParams)
					$scope.$emit("$$uiNotification", a.$$uiNotification);
				$scope.$emit("$sp.sc_cat_item.submitted", a);
				$rootScope.$broadcast("$sp.service_catalog.wishlist.update");
				if (c.options.auto_redirect == 'false') {
					$rootScope.$broadcast("$sp.service_catalog.cart.submitted", true);
					spUtil.addInfoMessage($scope.m.requestSubmitted);
					return;
				} else {
					c.data.requestId = a.sys_id;
					c.server.update().then(function(){
						var redirectSysId = c.data.requestId;
						//if one RITM is returned, redirect to ticket page for that RITM. Otherwise redirect to sc_request
						if(c.data.ritmId){
							page = 'ticket';
							table = 'sc_req_item';
							redirectSysId = c.data.ritmId;
						}
						newURL = $location.search('&id=' + page + '&is_new_order=true&table='+ table + '&sys_id=' + redirectSysId);
						spAriaFocusManager.navigateToLink(newURL.url());
					});
				}
			});
		}
		else {
			c.data.delivery_address = c.deliverTo;
			c.data.special_instructions = c.special_instructions;
			c.data.requested_for = c.requestedFor.value;
			var isOrderGuide = c.data.action == 'order_guide';
			c.server.update().then(function(response) {
				c.data.action = null;
				if (isOrderGuide)
					$scope.$emit("$sp.sc_order_guide.submitted", $scope.data.result);
				else
					$scope.$emit("$sp.cart.submitted", $scope.data.result);
				if (c.options.auto_redirect == 'false') {
					$rootScope.$broadcast("$sp.service_catalog.cart.update");
					$rootScope.$broadcast("$sp.service_catalog.cart.submitted", true);
					spUtil.addInfoMessage($scope.m.requestSubmitted);
					return;
				}
				else {
					if ($scope.data.result.sys_id) 
						$location.search('id=sc_request&is_new_order=true&table=sc_request&sys_id=' + $scope.data.result.sys_id);
					else 
						$location.search('id=requests');

					$timeout(function(){
						$rootScope.$broadcast("$sp.service_catalog.cart.update");
						$rootScope.$broadcast("$sp.service_catalog.cart.submitted", true);						
					})

				}
			});
		}
	}

	$scope.$on("field.change", function(evt, parms) {
		if (parms.field.name == 'requested_for') {
			c.data.cart.requested_for = parms.newValue;
			var getShippingAddrURL = '/api/sn_sc/v1/servicecatalog/cart/delivery_address/' + parms.newValue;
			$http.get(getShippingAddrURL).then(function handleSuccess(response) {
				if (response.data.result) {
					c.deliverTo = response.data.result.trim();
				} else {
					c.deliverTo = '';
				}
				c.changeShippingInfo();
			});
		}
	});

	c.cancel = function() {
		$rootScope.$broadcast("$sp.service_catalog.cart.cancel_order", true);
	}

	c.allowDeliveryAddress = function () {
		if (c.data.item)
			return c.data.item.request_method != "request"
			return true;
	}

	c.updateDetails();
}

 

I was able to get this working, let me know if it works for you!

If my answer was helpful or answered your question, please mark it as 'Helpful' or 'Correct'

Thanks!

Josh

View solution in original post

12 REPLIES 12

You are Amazin man, 100% helpful. 

Hi Josh, 
This is the exact solution I'm looking for but I have a query, When clicked on Order Now, In checkout widget, I'm receving the sys id instead of the user name of the logged in user. Can you help me with this..!?
Thanks, In Advance

john_duchock
Kilo Guru

Just tried this out in Madrid P4 and as a result, my user was re-directed to the portal home page...

granted, that is better than redirection to the REQ record, but i am not sure why it did not redirect to RITM...

 

EDIT:  bah...i didn't see where you had page = '';

once i put page = 'ticket'; it all worked.

 

Thanks for the help on this !!