Task result showing success and workitem rejected of id XXXX. But it still appears in UI for Approval

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="AIZ-TaskRule-TerminateApprovalWorkItems">
  <Description>Close Open Work Items of specific type that are older than x days old.</Description>
  <Signature returnType="Map">
    <Inputs>
      <Argument name="log">
        <Description>The log object associated with the SailPointContext.</Description>
      </Argument>
      <Argument name="context">
        <Description>A sailpoint.api.SailPointContext object that can be used to query the database if necessary.</Description>
      </Argument>
      <Argument name="taskResult">
        <Description>A sailpoint.object.TaskResult object that can be used to report task results to IIQ.</Description>
      </Argument>
    </Inputs>
    <Returns>
      <Argument name="workItemsCount">
        <Description>workItemsCount</Description>
      </Argument>
      <Argument name="failedWorkItemsFound">
        <Description>workItemsFound</Description>
      </Argument>
      <Argument name="workItemsFound">
        <Description>workItemsFound</Description>
      </Argument>
    </Returns>
  </Signature>
  <Source>

import sailpoint.object.*;
import sailpoint.api.Workflower;
import sailpoint.object.Filter;
import sailpoint.object.QueryOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import org.apache.log4j.Logger;

Logger logger = Logger.getLogger("AIZWorkflow.TerminateQuicklinkWorkItems");
logger.debug("ENTRY : Inside TerminateQuicklinkWorkItems");

List workItemsList = new ArrayList();
List failedWorkItemsList = new ArrayList();

int workItemsCount = 0;
int numDays = 30;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.DAY_OF_MONTH, -numDays);
date = cal.getTime();

QueryOptions qo = new QueryOptions();
qo.addFilter(Filter.eq("type", "Approval"));
qo.addFilter(Filter.le("created", date));

workItemsCount = context.countObjects(WorkItem.class, qo);
Iterator workItems = context.search(WorkItem.class, qo);

logger.debug("WorkItems size::" + workItems);
int i = 0;

try {
    context.startTransaction(); // Begin transaction

    if (workItems != null) {
        while (workItems.hasNext()) {
            i++;
            logger.debug("======================Record Number::" + i);

            WorkItem pendingWorkItem = (WorkItem) workItems.next();
            String wiName = pendingWorkItem.getName();
            logger.debug("WorkItem Id:::" + wiName);
            logger.debug("WorkItem Type:::" + pendingWorkItem.getType());
            String wiDescription = pendingWorkItem.getDescription();
            logger.debug("WorkItem description:::" + wiDescription);

            try {
                // Change state
                pendingWorkItem.setState(WorkItem.State.Finished);
                context.saveObject(pendingWorkItem);
                
                // Validate update
                WorkItem updatedWorkItem = context.getObjectById(WorkItem.class, pendingWorkItem.getId());
                logger.debug("Updated WorkItem State: " + updatedWorkItem.getState());

                workItemsList.add("WorkItem Finished:" + wiName + "\r\n");
            } catch (Exception ex) {
                logger.error("Failed to finish WorkItem: " + wiName, ex);
                taskResult.setCompletionStatus(TaskResult.CompletionStatus.Warning);
                taskResult.addMessage(new Message(Message.Type.Warn, "The task completed successfully but there were one or more errors", (Object[]) null));
                failedWorkItemsList.add("WorkItem Failed:" + wiName + "\r\n --------------------------------------------------------- \r\n ");
            }
        }
    }

    context.commitTransaction(); // Commit transaction

    // Set the handler after committing the transaction
    for (Object workItemObj : workItemsList) {
        WorkItem finishedWorkItem = context.getObjectById(WorkItem.class, ((String)workItemObj).split(":")[1].trim());
        if (finishedWorkItem != null) {
            finishedWorkItem.setHandler("sailpoint.api.Workflower"); // Set the handler
            context.saveObject(finishedWorkItem);
        }
    }

} catch (Exception e) {
    logger.error("Exception occurred during transaction", e);
    context.rollbackTransaction(); // Rollback transaction in case of exception
    taskResult.setCompletionStatus(TaskResult.CompletionStatus.Warning);
    taskResult.addMessage(new Message(Message.Type.Warn, "The task encountered an error and was rolled back", (Object[]) null));
}

TaskResult taskResult = context.getObjectByName(TaskResult.class, "AIZ-TerminateApprovalWorkItems");
if (taskResult != null) {
    // Set attributes
    taskResult.setAttribute("workItemsCount", String.valueOf(workItemsCount));
    
    if (!workItemsList.isEmpty()) {
        taskResult.setAttribute("workItemsFound", "Work Item\n" + String.join("\n", workItemsList));
    } else {
        taskResult.setAttribute("workItemsFound", "No Matching WorkItems Found");
    }

    if (!failedWorkItemsList.isEmpty()) {
        taskResult.setAttribute("failedWorkItemsFound", "Work Item\n" + String.join("\n", failedWorkItemsList));
    } else {
        taskResult.setAttribute("failedWorkItemsFound", "No Matching WorkItems Found");
    }

    // Set completion status
    taskResult.setCompletionStatus(TaskResult.CompletionStatus.Success);
    context.saveObject(taskResult);
}

return "Success";

  </Source>
</Rule>

Hi @autorun6464, Welcome to the developer community.

What exactly are you trying to do in your rule?
Are you trying to approve a workItem using code?

1 Like

Hi @autorun6464,

in addition to the questions of @aleksander_jachowicz:

you use start and commit transaction for what?
the problem is the result of task or the approval?

for the result, this rule return Success in every case.
for the approval, you are not approving the workitem

well what i am doing here is i am trying to reject all the workitem type approval that are pending for more than 30 days . i mean like here i am only checking type of workitem to change state to Rejected do i need tocheck approvalitems too??

You need to process using Workflower

	    Workflower flower = new Workflower((SailPointContext)context);
	    flower.process(workitemObj, true);

something like below

	    workitemObj.setState(WorkItem.State.Finished);
	    workitemObj.setCompleter("completer");

	      ApprovalSet aset = workitemObj.getApprovalSet();
	      if (aset != null) {
	        List<ApprovalItem> items = aset.getItems();
	        if (items != null)
	          for (ApprovalItem appitem : items) {
	            if (appitem.getState() == null) {
	              //appitem.setState(WorkItem.State.Finished);
	              appitem.setState(WorkItem.State.Rejected);
	              appitem.setApprover("spadmin");
	              //appitem.setComments(comments);
	            } 
	          }  
	      } 
	     
	    Workflower flower = new Workflower((SailPointContext)context);
	    flower.process(workitemObj, true);

it is rejecting workitem but one at a time like when i run task it deletes one at a time… can i reject in bulk so that i have to run task only one time

import sailpoint.object.*;
import org.apache.log4j.Logger;
import java.text.SimpleDateFormat;
import java.util.*;
import sailpoint.api.Workflower;
import sailpoint.object.QueryOptions;
import sailpoint.object.Filter;

Logger logger = Logger.getLogger("AIZWorkflow.CloseOpenWorkItems");
logger.debug("ENTRY : Inside CloseOpenWorkItems");

List workItemsList = new ArrayList();
List failedWorkItemsList = new ArrayList();

int workItemsCount = 0;


SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

QueryOptions qo = new QueryOptions();
qo.setCloneResults(true);
qo.addFilter(Filter.eq("type", "Approval"));		

workItemsCount = context.countObjects(WorkItem.class, qo);

Iterator workItems = context.search(WorkItem.class, qo);
logger.debug("WorkItems size::" + workItemsCount);

int i = 0;

if (workItems != null) {
  while (workItems.hasNext()) {
    i++;
    logger.debug("======================Record Number::" + i);

    WorkItem pendingWorkItem = workItems.next();
    logger.debug("WorkItem Id:::" + pendingWorkItem.getName());

    String workItemId = pendingWorkItem.getName();

    workItemsList.add("WorkItem Rejected:" + workItemId + "\r\n --------------------------------------------------------- \r\n ");

    logger.debug("pendingWorkItem match Found::" + pendingWorkItem.getName());
    try {
      logger.debug("Inside try pendingWorkItem match Found::" + pendingWorkItem.getName());
      
      Workflower workflower = new Workflower(context);
      workflower.reject(pendingWorkItem);  // Directly reject the work item
      context.decache(pendingWorkItem);    // Ensure the context is refreshed
      logger.debug("WorkItem rejected: " + workItemId);

      workItemsList.add("WorkItem Processed:" + workItemId + "\r\n --------------------------------------------------------- \r\n ");
    } catch (Exception ex) {
      logger.error("Reject WorkItem failed for: " + workItemId);
      logger.error("Reject WorkItem failed: " + ex.getMessage(), ex);
      failedWorkItemsList.add("WorkItem Failed:" + workItemId + "\r\n --------------------------------------------------------- \r\n ");
    }
  }
}

can you share the log output .

Try this code and let me know the result, if this still doesn’t work please provide the logs


import sailpoint.object.*;
import org.apache.log4j.Logger;
import java.text.SimpleDateFormat;
import java.util.*;
import sailpoint.api.Workflower;
import sailpoint.object.QueryOptions;
import sailpoint.object.Filter;
import sailpoint.api.IncrementalObjectIterator;


Logger logger = Logger.getLogger("AIZWorkflow.CloseOpenWorkItems");
logger.debug("ENTRY : Inside CloseOpenWorkItems");

List workItemsList = new ArrayList();
List failedWorkItemsList = new ArrayList();

int workItemsCount = 0;


SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

QueryOptions qo = new QueryOptions();
qo.setCloneResults(true);
qo.addFilter(Filter.eq("type", "Approval"));		

workItemsCount = context.countObjects(WorkItem.class, qo);

IncrementalObjectIterator workItems = new IncrementalObjectIterator(context, WorkItem.class, qo);
logger.debug("WorkItems size::" + workItemsCount);

int i = 0;

if (workItems != null) {
  while (workItems.hasNext()) {
    i++;
    logger.debug("======================Record Number::" + i);

    WorkItem pendingWorkItem = workItems.next();
    logger.debug("WorkItem Id:::" + pendingWorkItem.getName());

    String workItemId = pendingWorkItem.getName();

    workItemsList.add("WorkItem Rejected:" + workItemId + "\r\n --------------------------------------------------------- \r\n ");

    logger.debug("pendingWorkItem match Found::" + pendingWorkItem.getName());
    try {
      logger.debug("Inside try pendingWorkItem match Found::" + pendingWorkItem.getName());
      
      Workflower workflower = new Workflower(context);
      workflower.reject(pendingWorkItem);  // Directly reject the work item
      context.decache(pendingWorkItem);    // Ensure the context is refreshed
      logger.debug("WorkItem rejected: " + workItemId);

      workItemsList.add("WorkItem Processed:" + workItemId + "\r\n --------------------------------------------------------- \r\n ");
    } catch (Exception ex) {
      logger.error("Reject WorkItem failed for: " + workItemId);
      logger.error("Reject WorkItem failed: " + ex.getMessage(), ex);
      failedWorkItemsList.add("WorkItem Failed:" + workItemId + "\r\n --------------------------------------------------------- \r\n ");
    }
  }
}

1 Like

yup that worked… Thank you