Business rule

Pratiksha KC
Tera Guru

Write a BR - If there are four RITM attached to one Request, then state of request should set as following combinations-
1. If any RITM is in closed incomplete state and Incomplete reason is withdrawn by requester then state should set as - "Closed Cancelled"
2. If any RITM is in Closed Incomplete state than state of request should state as "Closed Incomplete"
3. If any RITM is in closed Complete state than state of request should set as "Closed Complete"
4. Else If RITM is in closed skipped state than state of request should set as "Closed Skipped"

Request state should not set to closed incomplete, complete or skipped or cancelled, If their are any RITM active. For example. If there are two RITM and one of them is in closed complete but other is still active than state of request should not change till both RITM's get active false or closed.

 

 

  • If any RITM is Closed Incomplete and incomplete_reason == withdrawn_by_requester, set Request to Closed Cancelled.

  • If any RITM is Closed Incomplete, set Request to Closed Incomplete.

  • If any RITM is Closed Complete, set Request to Closed Complete.

  • If any RITM is Closed Skipped, set Request to Closed Skipped.

  • Do not update the Request state if any RITM is still active.

 

 

For that I have wrote below  business rule on sc_req_item table with below conditions but not working.

PratikshaKC_0-1753334085122.png

 

 

(function executeRule(current, previous /*null when async*/ ) { 
var ritmGR = new GlideRecord('sc_req_item');
   
   ritmGR.addQuery('request', current.request);  
   ritmGR.query();

    var hasActive = false;
    var hasWithdrawn = false;
    var hasClosedIncomplete = false;
    var hasClosedComplete = false;
    var hasClosedSkipped = false;

    while (ritmGR.next()) {
        var state = ritmGR.getValue('state');
        var isActive = ritmGR.getValue('active') == 'true';

        if (isActive) {
            hasActive = true;
        } else {
            if (state === 'closed_incomplete') {
                var reason = ritmGR.getValue('incomplete_reason');
                if (reason == '3') {
                    hasWithdrawn = true;
                } else {
                    hasClosedIncomplete = true;
                }
            } else if (state === 'closed_complete') {
                hasClosedComplete = true;
            } else if (state === 'closed_skipped') {
                hasClosedSkipped = true;
            }
        }
    }

    if (!hasActive) {
        var reqGR = new GlideRecord('sc_request');
        if (reqGR.get(current.request)) {
            if (hasWithdrawn) {
                reqGR.request_state = 'closed_cancelled';
            } else if (hasClosedIncomplete) {
                reqGR.request_state = 'closed_incomplete';
            } else if (hasClosedComplete) {
                reqGR.request_state = 'closed_complete';
            } else if (hasClosedSkipped) {
                reqGR.request_state = 'closed_skipped';
            }

            reqGR.update();
        }
    }            
})(current, previous);
1 ACCEPTED SOLUTION

@Pratiksha KC 

try this

(function executeRule(current, previous) {

    // Run only if state has changed
    if (!current.state.changes())
        return;

    // Constants - update as per your instance!
    var CLOSED_COMPLETE = 3;
    var CLOSED_INCOMPLETE = 4;
    var CLOSED_SKIPPED = 7;
    var INCOMPLETE_WITHDRAWN = '3'; // Confirm this value on your instance

    // Step 1: Check if any requested item (RITM) in this request is still active
    var activeAgg = new GlideAggregate('sc_req_item');
    activeAgg.addQuery('request', current.request);
    activeAgg.addQuery('active', true);
    activeAgg.addAggregate('COUNT');
    activeAgg.query();
    if (activeAgg.next() && activeAgg.getAggregate('COUNT') > 0) {
        // There is at least one active RITM. Do NOT update parent request state.
        return;
    }

    // Step 2: Aggregate counts of all RITMs grouped by state and incomplete_reason
    var agg = new GlideAggregate('sc_req_item');
    agg.addQuery('request', current.request);
    agg.groupBy('state');
    agg.groupBy('incomplete_reason');
    agg.addAggregate('COUNT');
    agg.query();

    // Flags to track RITM states
    var hasWithdrawn = false;
    var hasClosedIncomplete = false;
    var hasClosedComplete = false;
    var hasClosedSkipped = false;

    while (agg.next()) {
        var state = parseInt(agg.getValue('state'), 10);
        var reason = agg.getValue('incomplete_reason') || '';

        if (state === CLOSED_INCOMPLETE) {
            if (reason == INCOMPLETE_WITHDRAWN) {
                hasWithdrawn = true;
            } else {
                hasClosedIncomplete = true;
            }
        } else if (state === CLOSED_COMPLETE) {
            hasClosedComplete = true;
        } else if (state === CLOSED_SKIPPED) {
            hasClosedSkipped = true;
        }
    }

    // Determine new state for the sc_request based on priority
    var newReqState = '';

    if (hasWithdrawn) {
        newReqState = 'closed_cancelled';
    } else if (hasClosedIncomplete) {
        newReqState = 'closed_incomplete';
    } else if (hasClosedComplete) {
        newReqState = 'closed_complete';
    } else if (hasClosedSkipped) {
        newReqState = 'closed_skipped';
    }

    // Step 3: Update the parent request state only if changed
    if (newReqState) {
        var reqGR = new GlideRecord('sc_request');
        if (reqGR.get(current.request) && reqGR.request_state != newReqState) {
            reqGR.request_state = newReqState;
            reqGR.update();
        }
    }

})(current, previous);

If my response helped please mark it correct and close the thread so that it benefits future readers.

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

View solution in original post

11 REPLIES 11

Pratiksha KC
Tera Guru

Hi @Ankur Bawiskar  @KKM @Satish Rana1  @G Ponsekar 

They don't wants to go through each request and each RITM. 

They suggested to achieve this with GlideAggregate with below conditions.

Provided sample code - 

PratikshaKC_0-1753350904121.png

 

var ritmGA = new GlideAggregate('sc_req_item');
ritmGA.addQuery('request', current.request);
ritmGA.addAggregate('COUNT','state');
ritmGA.orderBy('state');
ritmGA.query();

 

while(ritmGA.next()){
  gs.info('count of items in state {0} is {1}',[ritmGA.state,ritmGA.getAggregate('COUNT','state')]);
}

 

Can please help me here. 

@Pratiksha KC 

try this

(function executeRule(current, previous) {

    // Only run if state changes
    if (!current.state.changes())
        return;

    // Prepare constants (confirm values in your instance)
    var CLOSED_COMPLETE = 3;
    var CLOSED_INCOMPLETE = 4;
    var CLOSED_SKIPPED = 7;
    var INCOMPLETE_WITHDRAWN = '3'; // or actual value from your instance

    // Step 1: Check if any RITM for this Request is still active (active=true)
    var activeAgg = new GlideAggregate('sc_req_item');
    activeAgg.addQuery('request', current.request);
    activeAgg.addQuery('active', true);
    activeAgg.addAggregate('COUNT');
    activeAgg.query();
    if (activeAgg.next() && activeAgg.getAggregate('COUNT') > 0) {
        // If any active, do NOT update parent
        return;
    }

    // Step 2: Get counts of each closed state and "withdrawn by requester" using GlideAggregate
    var agg = new GlideAggregate('sc_req_item');
    agg.addQuery('request', current.request);
    agg.groupBy('state');
    agg.groupBy('incomplete_reason');
    agg.addAggregate('COUNT');
    agg.query();

    // Priority flags
    var hasWithdrawn = false;
    var hasClosedIncomplete = false;
    var hasClosedComplete = false;
    var hasClosedSkipped = false;

    while (agg.next()) {
        var state = parseInt(agg.getValue('state'), 10);
        var reason = agg.getValue('incomplete_reason');

        if (state === CLOSED_INCOMPLETE && reason == INCOMPLETE_WITHDRAWN) {
            hasWithdrawn = true;
        } else if (state === CLOSED_INCOMPLETE) {
            hasClosedIncomplete = true;
        } else if (state === CLOSED_COMPLETE) {
            hasClosedComplete = true;
        } else if (state === CLOSED_SKIPPED) {
            hasClosedSkipped = true;
        }
    }

    // Compute new request state
    var newReqState = '';
    if (hasWithdrawn) {
        newReqState = 'closed_cancelled';
    } else if (hasClosedIncomplete) {
        newReqState = 'closed_incomplete';
    } else if (hasClosedComplete) {
        newReqState = 'closed_complete';
    } else if (hasClosedSkipped) {
        newReqState = 'closed_skipped';
    }

    // Only update if needed
    if (newReqState) {
        var reqGR = new GlideRecord('sc_request');
        if (reqGR.get(current.request) && reqGR.request_state != newReqState) {
            reqGR.request_state = newReqState;
            reqGR.update();
        }
    }

})(current, previous);

If my response helped please mark it correct and close the thread so that it benefits future readers.

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

@Pratiksha KC 

I could see you marked my answer as correct just now and then you reverted it.

If my response helped please mark it correct and close the thread so that it benefits future readers.

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

Hi @Ankur Bawiskar 

 

Everything is working fine except the condition - if incomplete reason is - withdrawn by requestor. 

It's not setting closed_canceled , it is going directly to block closed_incomplete

 

@Pratiksha KC 

try this

(function executeRule(current, previous) {

    // Run only if state has changed
    if (!current.state.changes())
        return;

    // Constants - update as per your instance!
    var CLOSED_COMPLETE = 3;
    var CLOSED_INCOMPLETE = 4;
    var CLOSED_SKIPPED = 7;
    var INCOMPLETE_WITHDRAWN = '3'; // Confirm this value on your instance

    // Step 1: Check if any requested item (RITM) in this request is still active
    var activeAgg = new GlideAggregate('sc_req_item');
    activeAgg.addQuery('request', current.request);
    activeAgg.addQuery('active', true);
    activeAgg.addAggregate('COUNT');
    activeAgg.query();
    if (activeAgg.next() && activeAgg.getAggregate('COUNT') > 0) {
        // There is at least one active RITM. Do NOT update parent request state.
        return;
    }

    // Step 2: Aggregate counts of all RITMs grouped by state and incomplete_reason
    var agg = new GlideAggregate('sc_req_item');
    agg.addQuery('request', current.request);
    agg.groupBy('state');
    agg.groupBy('incomplete_reason');
    agg.addAggregate('COUNT');
    agg.query();

    // Flags to track RITM states
    var hasWithdrawn = false;
    var hasClosedIncomplete = false;
    var hasClosedComplete = false;
    var hasClosedSkipped = false;

    while (agg.next()) {
        var state = parseInt(agg.getValue('state'), 10);
        var reason = agg.getValue('incomplete_reason') || '';

        if (state === CLOSED_INCOMPLETE) {
            if (reason == INCOMPLETE_WITHDRAWN) {
                hasWithdrawn = true;
            } else {
                hasClosedIncomplete = true;
            }
        } else if (state === CLOSED_COMPLETE) {
            hasClosedComplete = true;
        } else if (state === CLOSED_SKIPPED) {
            hasClosedSkipped = true;
        }
    }

    // Determine new state for the sc_request based on priority
    var newReqState = '';

    if (hasWithdrawn) {
        newReqState = 'closed_cancelled';
    } else if (hasClosedIncomplete) {
        newReqState = 'closed_incomplete';
    } else if (hasClosedComplete) {
        newReqState = 'closed_complete';
    } else if (hasClosedSkipped) {
        newReqState = 'closed_skipped';
    }

    // Step 3: Update the parent request state only if changed
    if (newReqState) {
        var reqGR = new GlideRecord('sc_request');
        if (reqGR.get(current.request) && reqGR.request_state != newReqState) {
            reqGR.request_state = newReqState;
            reqGR.update();
        }
    }

})(current, previous);

If my response helped please mark it correct and close the thread so that it benefits future readers.

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