Exclude delegates from specific approval records.

eglazier
Mega Contributor

I have a requirement to restrict approvals on a specific catalog item.

They do not what User Delegates to be able to approve these requests.  Sounds easy enough.

I've found the "exclude delegates" on the email notification. 

I've also added a business rule to abort the approval should a delegate try to approve this item.

Now, I need to HIDE that approval from them.   

 

So  of the approvals the delegate will see currently:

Buy Software - Approver1 - delegate 1 - **Yes delegate can approve

Grant Access to Bank Records - Approver1 - delegate 1 - **NO  delegate my not approve this

Order Mobile phone - Approver1 - delegate 1 - **Yes delegate can approve

 

I'm not finding an easy way to only show two approvals for D1 and 3 for A1.

What is the best practice for this and are they any examples?

 

12 REPLIES 12

Michael Ritchie
ServiceNow Employee
ServiceNow Employee

This is definitely a tricky use case.  There are several things at play here that I want you to be aware of:

  • All the approval logic depends on functions called "getMyApprovals" and "isApprovalMine" which are defined in the getMyApprovals business rule.  It basically provides a list of users that the logged in user can approve for - querying the delegates table.
  • On top of the function is a query business rule on the approval table called "approval query" which is filtering the approvals for a user - query business rules are "the other ACL" where a filter can be applied behind the scenes without the user knowing about it.

But in order to solve your particular issue we need something that executes on each record provided by the query and modifying the getMyApprovals the approval query business rule isn't going to solve that since those execute once.  The only solution really is to modify the read ACL on the sysapproval_approver table to restrict access to approvals for your specific item.  This ACL provides read access to the approval records and scripted based ACLs are executed row by row to provide access.  This is the out of the box ACL doing that:

https://INSTANCENAME.service-now.com/nav_to.do?uri=sys_security_acl.do?sys_id=80d4a005c0a801661dde939536239b02

You will need to add an additional check to the script to compare the catalog item associated to the approval:

// Make sure the below query is only added for request items
var restrictedList = "COMMA-SEPERATED-LIST-OF-ITEM-SYSIDS";
if (current.source_table == "sc_req_item" && restrictedList.indexOf(sysapproval.ref_sc_req_item.cat_item) > -1) {
	answer = false
}

A better solution may be to create a system property with your comma separated list of catalog item SysIDs so you don't have to modify this ACL if this changes.

 Please mark this post as helpful or the correct answer to your question if applicable so others viewing may benefit.

 

 

Hmm.  that sounds very intriguing.  I'm sorta new to SN as an admin/developer.

Would you possibly have an example of this.

OK I tested this in my developer instance and it appears to work fine.  Things to keep in mind:

  • Any user with the following roles will see these approvals: approval_admin, itil, catalog
  • Assuming a user doesn't have one of the roles above, then the ACL calls the isApprovalMine() function which OOB will return true if a delegate is setup
  • I adjusted this OOB ACL to also call a new function that checks for "secure catalog item" and it will override the delegate for a particular record
  • If the user is approving from the standard platform browser UI (not service portal) they will see this message at the bottom since ACLs are executed on a row by row basis: "Number of rows removed from this list by Security constraints: 1"
  • Unfortunately it is difficult to get rid of this message based on your requirement and the need to evaluate every approval row by row.  This message shouldn't appear in the service portal.

Here is the ACL script:

if (gs.getProperty("glide.approvals.restrict_by_record", "false") == "true")
	answer = gs.hasRole('approval_admin') || gs.hasRole('itil') || gs.hasRole('catalog') || ((isApprovalMine(current) && checkSecureCatalogItem()) && hasAccessToDocument(current));
else
	answer = gs.hasRole('approval_admin') || gs.hasRole('itil') || gs.hasRole('catalog') || (isApprovalMine(current) && checkSecureCatalogItem()) || hasAccessToDocument(current);

function checkSecureCatalogItem() {
	var allowDelegate = true;
	// Make sure the below query is only added for request items
	var restrictedList = "SYS-ID-OF-CATALOG-ITEM";
	if (current.source_table == "sc_req_item" && restrictedList.indexOf(current.sysapproval.ref_sc_req_item.cat_item) > -1) {
		allowDelegate = false;
	}
	return allowDelegate;
}

Please mark this post as helpful or the correct answer to your question if applicable so others viewing may benefit.

it will be the Great pleasure if you help me in my same sinario

i used Your script , but still Delegate can able to Approving this catalog item approvals

 i want to restrict Active Check Box item approvals. this item does not be approved by Marisa,

it should approve only by Natasha,

 

delegate had : approver_admin, itil, catalog roles

i want to exclude "Active Checking" catalog item of approvals 

i used your script as suggest, but it is not working.. please help me........ 

READ - ACL's script : table : sysapproval_approver

 

if (gs.getProperty("glide.approvals.restrict_by_record", "false") == "true")
answer = gs.hasRole('approval_admin') || (gs.hasRole('itil') && checkSecureCatalogItem(current))||(gs.hasRole('catalog') && checkSecureCatalogItem(current)) || (isApprovalMine(current) && checkSecureCatalogItem(current)) && hasAccessToDocument(current);
else
answer = gs.hasRole('approval_admin') || (gs.hasRole('itil') && checkSecureOrderGuide(current)) || (gs.hasRole('catalog') && checkSecureCatalogItem(current)) || (isApprovalMine(current) && checkSecureCatalogItem(current)) || (hasAccessToDocument(current) && checkSecureCatalogItem(current));

function checkSecureCatalogItem(current) {
var allowDelegate = true;
// Make sure the below query is for retricted items//

var restrictList = gs.getProperty('active.checking.box.restrict.delegates'); // Active check -catalog item sys_id

 

if (current.sysapproval.sys_class_name == "sc_req_item" && restrictedList.indexOf(current.sysapproval.ref_sc_req_item.cat_item) > -1 && current.approver!=gs.getUserID()) {
allowDelegate = false;

}
else if (current.sysapproval.sys_class_name == "sc_request" && restrictedList.indexOf(current.sysapproval.ref_sc_req_item.cat_item) > -1 && current.approver!=gs.getUserID()) {

allowDelegate = false;
}

return allowDelegate;
}