sc_task Business rule to move non agent comments from pending to work in progress.

RBlor
Mega Guru

Hi,
I seem to be running into issues with trying to set up a business rule for sc_task. We want any non-agent replies to the sc_tasks to move the state from pending to work in progress. We only want this to work for 3 assignment groups. Another factor is to not work when moveworks updates. I have the below script but it seems to not work when I comment to a ticket it seems to move the state back to work in progress. Any tips on the script would be appreciated. thank you.

// Before Update on sc_task

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

    // --- Act only on comment-only updates while Pending (5) ---
    if (!current.comments.changes()) return;               // No Additional Comments change
    if (current.state.changes()) return;                   // State was manually changed in this update
    if (previous.state != 5 || current.state != 5) return; // Was and is Pending

    // --- Only for these assignment groups (by sys_id) ---
    var allowedGroups = [
        'ba0fd3c7db78e11053403978f4961920', // Service Delivery Optimization
        'd625dccec0a8016700a222a0f7900d06', // IT Service Desk
        'c75eb931dbab5700f4ee7b5b8c961971'  // Desktop Support
    ];
    if (allowedGroups.indexOf(String(current.assignment_group)) === -1) return;

    // --- Updater checks (use session user in Before rules) ---
    var userName = gs.getUserName() || '';

    // If updated by MoveWorks, do NOT flip
    if (userName === 'MoveWorks') return;

    // If updater is an agent, do NOT flip
    var isAgent = gs.hasRole('itil') || gs.hasRole('hr') || gs.hasRole('facilities_inc');
    if (isAgent) return;

    // --- Otherwise flip Pending -> Work in Progress (2) ---
    current.state = 2;

})(current, previous);

 

3 REPLIES 3

Rafael Batistot
Tera Sage

Hi @RBlor 

 

Analyzing your script I found some Problems with your script:

 

 

  1. current.comments.changes() →
    This will return true even if the update is done by a system account (like MoveWorks), so you need to filter earlier.
  2. gs.hasRole(...) →
    In a before business rule, gs.hasRole() evaluates the roles of the user executing the update (good), but if the user is a fulfiller/agent, they might still trigger comment-only updates that push the state back unexpectedly.
    → You’re already excluding them, but ensure that the MoveWorks account is excluded properly too.
  3. Checking Pending state →
    Your current condition if (previous.state != 5 || current.state != 5) prevents the script from working if the state was manually set to something else and then comments added. You want “was pending and still pending”.
  4. Assignment group check →
    You’re comparing String(current.assignment_group) which will return a GlideRecord object, not always the sys_id. Better to use .toString() or .getDisplayValue() correctly.

 

Chavan AP
Tera Guru

here is corrected version of script:

 

// Business Rule: SC Task - Pending to WIP on Non-Agent Comments
// Table: sc_task
// When: before
// Update: true
// Advanced: true

(function executeRule(current, previous) {

    // --- Only act when task is currently in Pending state ---
    if (current.state != 5) return; // Not in Pending state
    
    // --- Only act when comments were added (not other field changes) ---
    if (!current.comments.changes()) return; // No new comments
    
    // --- Don't interfere if state is being manually changed ---
    if (current.state.changesFrom(previous.state)) return; // State manually changed
    
    // --- Only for specified assignment groups ---
    var allowedGroups = [
        'ba0fd3c7db78e11053403978f4961920', // Service Delivery Optimization
        'd625dccec0a8016700a222a0f7900d06', // IT Service Desk
        'c75eb931dbab5700f4ee7b5b8c961971'  // Desktop Support
    ];
    
    var currentAssignmentGroup = current.getValue('assignment_group');
    if (allowedGroups.indexOf(currentAssignmentGroup) === -1) return;
    
    // --- Get the actual user making the update ---
    var updatingUser = gs.getUserName();
    
    // --- Skip if updated by MoveWorks ---
    if (updatingUser === 'moveworks' || updatingUser === 'MoveWorks') return;
    
    // --- Skip if updating user is an agent ---
    var userGR = new GlideRecord('sys_user');
    if (userGR.get('user_name', updatingUser)) {
        
        // Check if user has agent roles
        var isAgent = userGR.hasRole('itil') || 
                     userGR.hasRole('hr') || 
                     userGR.hasRole('facilities_inc') ||
                     userGR.hasRole('admin') ||
                     userGR.hasRole('sn_request_read'); // Add other agent roles as needed
        
        if (isAgent) {
            gs.debug('User ' + updatingUser + ' is an agent - not changing state');
            return;
        }
    }
    
    // --- Check if this is actually a new comment (not just a touch) ---
    var newComments = current.comments.getJournalEntry(1);
    if (!newComments || newComments.trim() === '') return;
    
    // --- All checks passed - move to Work in Progress ---
    current.state = 2; // Work in Progress
    current.work_notes = 'State automatically changed to Work in Progress due to customer comment';
    
    gs.info('SC Task ' + current.number + ' moved from Pending to Work in Progress due to non-agent comment by: ' + updatingUser);

})(current, previous);

 

Key Issues Fixed:

1. Role Check Problem:

Your original script used gs.hasRole() which checks the current session user, not necessarily the person who made the comment. Fixed with proper user lookup.

2. State Change Logic:

 
// WRONG - this condition was confusing
if (previous.state != 5 || current.state != 5) return;

// RIGHT - clearer logic
if (current.state != 5) return; // Only act when in Pending
if (current.state.changesFrom(previous.state)) return; // Don't interfere with manual changes

3. Comment Validation:

Added check for actual comment content to avoid "empty" comment updates.

Chavan AP
[ Architect | Certified Professional]

Was this response helpful? If so, please mark it as Helpful and Accept as Solution to help others find answers.

kaushal_snow
Mega Sage

Hi @RBlor ,

 

Try below code,  Before Update on sc_task....

 

Here, I am ensuring precise behavior by comparing the latest journal entry using current.comments.getJournalEntry( ) to its previous value, so the rule only fires for actual comment additions and not general record updates. ....

 

(function executeRule(current, previous /* null when async */) {
    // 1. Check for added Additional Comments ONLY
    var prevComment = previous.comments.getJournalEntry(1);
    var currComment = current.comments.getJournalEntry(1);
    if (!currComment || currComment === prevComment) return;

    // 2. Ensure status remains Pending (5)
    if (!(previous.state == 5 && current.state == 5)) return;

    // 3. Only specific assignment groups
    var allowed = new Set([
        'ba0fd3c7db78e11053403978f4961920',
        'd625dccec0a8016700a222a0f7900d06',
        'c75eb931dbab5700f4ee7b5b8c961971'
    ]);
    if (!allowed.has(String(current.assignment_group))) return;

    // 4. Exclude user if update made by MoveWorks
    if (current.sys_updated_by == 'MoveWorks') return;

    // 5. Exclude users with agent roles
    var agentRoles = ['itil', 'hr', 'facilities_inc'];
    for (var role of agentRoles) {
        if (gs.hasRole(role)) return;
    }

   
    current.state = 2;

})(current, previous);

 

If you found my response helpful, please mark it as ‘Accept as Solution’ and ‘Helpful’. This helps other community members find the right answer more easily and supports the community.

 

Thanks and Regards,
Kaushal Kumar Jha - ServiceNow Consultant - Lets connect on Linkedin: https://www.linkedin.com/in/kaushalkrjha/