RITM Group Approval – How to Send Approval Requests Only to Selected Members from a Custom 'Approver

ArupR
Tera Contributor

I'm working on RITM approvals and need to modify the default group approval behavior. I have a custom field 'approvers' (List of Users type) on the Group table that contains specific users who should receive approval requests.
approver_column_name.pnggroup record.png

My requirements:

  1. Use Group Approval (not User Approval) to preserve which groups were requested
  2. Only users in the custom 'approvers' field should get approval requests, not all group members
  3. Don't want to manually extract user sys_ids and use individual user approvals

Current challenge:
When I use standard group approval, it sends requests to ALL active group members, but I only want the subset defined in my custom 'approvers' field.

I've considered scripted group approvals but want to ensure:

· It still shows as a group approval in the system
· The group relationship is maintained for reporting
· Only my specified approvers receive the request

Has anyone implemented something similar? What's the best approach - workflow script, business rule, or some other method that maintains the group approval context while filtering the actual approvers?

1 ACCEPTED SOLUTION

@ArupR 

got it.

then do this

-> let the approval go to that group using OOTB Ask for Approval

-> use before insert business rule on sysapproval_approver table and see if this is generated due to Group approval i.e. Group field not empty

-> then grab the custom list field and see if the current approver is allowed or not

-> if not then use setAbortAction(true) and record won't be inserted

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

21 REPLIES 21

@Ankur Bawiskar 
Sure, check the below screenshot.

ArupR_0-1761202062086.png

 

@ArupR 

it worked for me when I used single group

I believe it doesn't work when multiple groups are selected for approval

I used this in "Ask for Approval" flow action and it populate the Group field in sysapproval_approver

 

AnkurBawiskar_3-1761203398666.png

 

AnkurBawiskar_2-1761203380750.png

 

 

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

@Ankur Bawiskar 

Oh, I see — it doesn’t work when more than one group is present.

I managed to write a Business Rule, and it seems to be working correctly as I can see the expected logs. However, even when I use current.setAbortAction(true);, the record is still not being skipped from insertion.

@ArupR 

Glad to know that it's working.

Share the business rule config screenshots and the actual script.

it should be before insert

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

@Ankur Bawiskar 

ArupR_0-1761205585924.png


This is the business rule, changing the table names for security purpose.

(function executeRule(current, previous /*null when async*/) {

    gs.info("Business Rule triggered for document_id: " + current.document_id);

    // 1️⃣ Get the RITM record using document_id
    var ritm = new GlideRecord('sc_req_item');
    if (!ritm.get(current.document_id)) {
        gs.warn("No RITM found for document_id: " + current.document_id);
        return;
    }

    var ritmNumber = ritm.getValue('number');
    gs.info("Found RITM Number: " + ritmNumber);

    // 2️⃣ Find matching records in ritm_deployment table
    var depGR = new GlideRecord('ritm_deployment');
    depGR.addQuery('ritm_number', ritmNumber);
    depGR.query();

    var currentUser = current.getValue('approver'); // sys_user.sys_id of approver
    var foundMatch = false;

    while (depGR.next()) {

        var mac = depGR.getValue('mac_address');
        var port = depGR.getValue('port');
        var server = depGR.getValue('server_name');
        var vendor = depGR.getValue('vendor_name');

        gs.info("Checking System Info for: MAC=" + mac + ", PORT=" + port + ", SERVER=" + server + ", VENDOR=" + vendor);

        // 3️⃣ Search matching entry in Systems Information table
        var sysInfo = new GlideRecord('system_information');
        sysInfo.addQuery('mac_address', mac);
        sysInfo.addQuery('port', port);
        sysInfo.addQuery('server_name', server);
        sysInfo.addQuery('vendor_name', vendor);
        sysInfo.query();

        while (sysInfo.next()) {
            var groupList = sysInfo.getValue('group_name');
            if (!groupList) {
                gs.warn("No groups found for system: " + sysInfo.getDisplayValue());
                continue;
            }

            var groupArray = groupList.split(',');

            // 4️⃣ For each group, check if the current user is in its Approver field
            for (var i = 0; i < groupArray.length; i++) {
                var grpSysId = groupArray[i].trim();
                if (!grpSysId)
                    continue;

                var grp = new GlideRecord('sys_user_group');
                if (!grp.get(grpSysId)) {
                    gs.warn("Group not found: " + grpSysId);
                    continue;
                }

                var approverField = grp.getValue('u_approvers');
                if (!approverField)
                    continue;

                var approvers = approverField.split(',');
                if (approvers.indexOf(currentUser) !== -1) {
                    gs.info("User " + currentUser + " found in approvers of group: " + grp.name);
                    foundMatch = true;
                    break; // Found match → no need to check more groups
                }
            }

            if (foundMatch)
                break; // Break out of sysInfo loop as well
        }

        if (foundMatch)
            break; // Break out of depGR loop
    }

    // 5️⃣ If no match found → Abort the insert/update
    if (!foundMatch) {
        gs.warn("User " + currentUser + " not present in any group approver list. Skipping this record.");
        current.setAbortAction(true);
    }

})(current, previous);