- 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
03-26-2022 09:58 AM
You are Amazin man, 100% helpful.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
01-13-2024 10:35 PM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-17-2019 10:30 AM
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 !!