Workflows tend to be part of the core business in SAP Sourcing and business requirements will most often transform a ‘simple’ workflow process into a very complex one.

Since the introduction of WF in Sourcing (and the TWE ‘era’) a specific pattern to script workflows has emerged and it has been carried forward into all projects. Today we are going to change that.

**WARNINGS**

  • Implementing recommendations in this blog post might make your life easier
  • Throughout this blog post it will be assumed that consultants have following knowledge
    • Workflows definition / update / scripting
    • Java EE/BeanShell

WORKFLOW TYPOLOGY

The typology used throughout projects is fairly similar:

  • Workflow definition with X number of Approval Steps (total maximum possible steps)
  • Approval Matrix Definition maintained *somewhere*
  • Specific Approval Sequence picked up in PRE-PHASE-CHANGE script and added to the document into an Extension Collection
  • Workflow scripting handles the ‘next approver’ from the document Extension Collection

So, WHAT IS THE PROBLEM?

For each approval step the script is required to

  • Check if approval status is APPROVED or REJECTED
    • APPROVED
      • Approval Sequence is complete -> move document to ‘Approved’ phase
      • If not complete, add next approver
    • REJECTED
      • move document to ‘Draft’ (or previous phase)

Pattern in case of APPROVED for above is:

  • for WF STEP 1:

if(approvalMatrix.size() == 1) {
  //move to Approved
}
if(approvalMatrix.size() >= 1) {
  //add next approver
}

  • for WF STEP 2:

if(approvalMatrix.size() == 2) {
  //move to Approved
}
if(approvalMatrix.size() >= 2) {
  //add next approver
}

  • etc … for all steps

WHY IS THAT A PROBLEM? And why is it complicating our lives?

The pattern above implies that:

  • there is one distinct version of PRESCRIPT for EACH workflow step
  • similarly, there will be one distinct version of POSTSCRIPT for EACH workflow step

To maintain such a workflow, an IT consultant will have to:

  • save/maintain each prescript/postscript version individually
  • do a lot of repetitive work for any minor update
  • be VERY careful when doing updates not to disturb the process

WHAT IS THE SOLUTION?

The solution is to make scripting GENERIC.

  • Single version of PRESCRIPT for ALL steps
    • the script should be able to ‘know’ from which step it was executed
  • Single version of POSTSCRIPT for ALL steps
    • the script should be able to ‘know’ from which step it was executed

HOW?

  • Step 1: Make sure you have a gate identifier. Solution is to ‘decode’ the current step from the Activity ID (last digit/digits)

Screen Shot 2015-07-30 at 4.41.19 PM.png

  • Step 2: Use following code to identify gate -> ‘current approval step’
    • Script will get ending digit(s) from identifier:
      • ‘approval_gate_1’ = 1
      • ‘approval_gate_12’ = 12
      • ‘approval_gate_1485’ = 1485 😀

import java.util.regex.Matcher;
import java.util.regex.Pattern;
private Integer gate = null;
// btoma - Get the step No. from gate NativeID - last digit(s)
// btoma - to facilitate PRESCRIPT on all steps
void getGate() {
  Pattern p = Pattern.compile("\\d+");
  Matcher m = p.matcher(nativeName);
  while(m.find()) {
  gate = Integer.valueOf(m.group());
  }
}
getGate();


  • Step 3: Update WF script code, to use gate instead of hardcoded numbers

if(approvalMatrix.size() == gate) {
  //move to Approved
}
if(approvalMatrix.size() >= gate) {
  //add next approver
}


  • Step 4: Copy-Paste your PRESCRIPT on rest of WF steps
  • Step 5: Repeat 1-4 for POSTSCRIPT

OTHER RECOMMENDATIONS?

  • Maintain scripts locally, in a source control sistem (SVN, GIT).
  • Perform changes locally, and copy-paste your script to all WF steps in one go.
  • Don’t forget about logging and error reporting

The end.

Bogdan Toma

To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. Devesh Sati Prasad

    Great post, Bogdan.

    Although in my recent projects I have been dealing mostly with single step approvals, I do remember implementing a 15-step workflow for a client. And yes, I had to go through the repetitive task of updating each pre-script for even a small change. This will come handy the next time I face a similar situation.

    Thanks

    Devesh

    PS: Good programmers are lazy programmers. Hence proved. 😉

    (0) 
  2. ofir duran

    Hi Bogdan,

    Currently I’m working with CLM Workflow definition, I do not know anything about SAP/SCN/CLM, I’m a Java Developer, so far I had created a 4 approval steps, the problem is that I don’t understand how the sequence works, because I got the order of approvers from the collaborator’s list, it seems that just the first activity is always executed and never goes to the next step for the next approver. In the code I check for the Name of the collaborator on each step, here is my code, the question is how can I achieve the next step for the next approver?

    Thanks in advance.

    Regards

    import com.sap.odp.api.common.exception.*;

    import com.sap.odp.api.common.log.Logger;

    import com.sap.odp.api.common.log.LogMessageIfc;

    import com.sap.odp.api.ibean.*;

    import com.sap.odp.api.common.types.*;

    import com.sap.odp.api.workflow.*;

    import com.sap.odp.api.ibean.IBeanIfc;

    import com.sap.eso.api.contracts.*;

    import com.sap.odp.api.doc.collaboration.*;

    import com.sap.odp.api.doc.IapiDocumentLockManager;

    import com.sap.odp.api.common.types.*;

    import com.sap.odp.api.doccommon.userdefined.UserDefinedBizDoc1IBeanIfc;

    import com.sap.odp.api.usermgmt.masterdata.*;

    import com.sap.odp.api.doc.collaboration.*;

    import com.sap.odp.api.util.*;

    import java.math.*;

    // Variable for Approver

    ObjectReferenceIfc principal = null;

    // Logger Instance for logging messages

    private LogMessageIfc log = Logger.createLogMessage(session);

    // Starting Workflow

    log.setLogMessage(“MAWF-Prescript-Inicio-Request Approval 1”);

    Logger.info(log);

    // Instance of the Document

    contractBean = doc.getParentIBean();

    // Name in Contract Documents Tab (Creating a Contract/DocumentType)

    docName = doc.getDisplayName();

    log.setLogMessage(“MAWF-Prescript-DocumentName: ” + docName);

    Logger.info(log);

    // Get the user who creates the document

    String userName = doc.getCreatedByUser().getDisplayName();

    log.setLogMessage(“MAWF-Prescript-Created by User: ” + userName);

    Logger.info(log);

    // List of Collaborators of a Document

    collaboratorsCollection = doc.getCollaborators();

    collaboratorsIterator = collaboratorsCollection.iterator();

    // Check if collaborators collection’s size is greater than zero.

    if (collaboratorsCollection.size() > 0) {

    // Iterate over the collection.

    for (int i = collaboratorsCollection.size() – 1; i >= 0; –i) {

      // Get collection member

        collaboratorsCollection_member = collaboratorsCollection.get(i);

        // Check if member has value.

        if (hasValue(collaboratorsCollection_member)) {

        // Get the collaboration role of the collection member.

            collaboratorRole = collaboratorsCollection_member.getCollaboratorRole().getDisplayName();

           

            // Get approver of Role “DIRECTOR PUBLICIDAD”.

            if(collaboratorsCollection_member.getDisplayName().equalsIgnoreCase(“DIRECTOR PUBLICIDAD”)) {

            log.setLogMessage(“MAWF-Prescript-Principal: ” + collaboratorsCollection_member.getPrincipal());

            Logger.info(log);

            log.setLogMessage(“MAWF-Prescript-Principal: ” + collaboratorsCollection_member.getPrincipal());

            Logger.info(log);       

            principal = collaboratorsCollection_member.getPrincipal();

            }

        }

      }

    }

    if (hasValue(principal)) {

      // Add the user account as the approver

        addApprover(principal);

        // log details

        log.setLogMessage(“Added user: ” + principal.getDisplayName() + ” as approver”);

        Logger.info(log);

    }

    // Ending Workflow

    log.setLogMessage(“MAWF-Prescript-Fin-Request Approval”);

    Logger.info(log);

    (0) 
    1. Bogdan Toma Post author

      Hi,

      At first glance, the script should work fine, if you have copied it on all steps as PreScript. But it looks as if you are picking the same approver for every step … so it’s a bit unclear.

      The transition should be made automatically by the system.

      Bogdan

      (0) 

Leave a Reply