- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-18-2019 11:13 AM
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.
Solved! Go to Solution.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-20-2019 07:28 AM
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"
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)
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-21-2019 06:58 AM
This was awesome. I was able to get this solution working.
And of course as soon as I got it working the requirements changed and now I need to go back to redirecting without the checkout widget haha.
This info is all really helpful I appreciate it so much. This should be super helpful for others too.
I will update when I get the new sc_catalog_item redirect working without the checkout enabled. 🙂
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-24-2019 01:21 PM
This is exactly what we're looking for, except the one thing is we want to disable glide.sc.sp.twostep because we don't like the two-step checkout process (we want the portal to just be a simple form with a submit that instantly creates the RITM and redirects).
If we disable the twostep though this process doesn't work.
Do you have any recommendation on what we should do?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-02-2019 06:43 AM
I actually went back through and set our portal up to not have the two step check out as well. So basically instead of making these changes in the checkout widget, you make them in the cloned version of the catalog widget.
There is only one update to the server script. Do a ctrl + f to find "data._generatedItemGUID = cart_item_id;
data.quantity = '' + gr.quantity;
} else {" and that is where this script starts
if (input){
data.sys_id = input.sys_id;
//Input REQ sys id from the Client Controller
if(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();
}
}
}else if (options.sys_id)
data.sys_id = options.sys_id;
else
data.sys_id = $sp.getParameter("sys_id") || $sp.getParameter('sl_sys_id');
if (!data.sys_id) {
data.recordFound = false;
return;
}
In the client controller script update the two following spScUtil functions like this:
spScUtil.orderWishlistedItem($scope.data.sc_cat_item.sys_id, $scope.data.sc_cat_item.quantity, getVarData($scope.data.sc_cat_item._fields), $scope.data._generatedItemGUID, additionalParms).then(function(response) {
var a = response.data.result;
$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') {
$scope.submitting = false;
$scope.submitted = true;
$rootScope.$broadcast("$sp.service_catalog.cart.submitted", true);
spUtil.addInfoMessage($scope.m.requestSubmitted);
return;
}
else{
//Update the server and see if exactly one RITM is returned,
c.data.requestId = a.sys_id;
c.server.update().then(function(){
if(c.data.ritmId){
var redirectSysId = c.data.requestId;
//if one RITM is returned, redirect to page for that RITM. Otherwise redirect to sc_request
page = ''; // your page
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{
$location.search('id=sc_request&is_new_order=true&table=sc_request&sys_id=' + a.sys_id);
}
});
}
});
}
else {
spScUtil.orderNow($scope.data.sc_cat_item.sys_id, $scope.data.sc_cat_item.quantity, getVarData($scope.data.sc_cat_item._fields), $scope.data._generatedItemGUID, additionalParms).then(function(response) {
var a = response.data.result;
$scope.$emit("$$uiNotification", a.$$uiNotification);
$scope.$emit("$sp.sc_cat_item.submitted", a);
if (c.options.auto_redirect == 'false') {
$scope.submitting = false;
$scope.submitted = true;
$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(){
if(c.data.ritmId){
var redirectSysId = c.data.requestId;
//if one RITM is returned, redirect to page for that RITM. Otherwise redirect to sc_request
page = ''; // your page
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{
$location.search('id=sc_request&is_new_order=true&table=sc_request&sys_id=' + a.sys_id);
}
});
}
});
}
}

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-09-2021 11:00 AM
Have you had to make changes to this for the newer versions? I can't seem to get this to work. I'm on Paris. When I load the catalog page, I have no buttons to be able to submit/order.
Thanks,
Shannon Burns
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-05-2020 12:44 AM
I don't know what I am doing wrong here but it just doesn't seem to be working for me.
Regards,
Monika