Some organisations have somewhat straight forward approval rules in place. By that I mean that there is a well defined structure where for example based on amount ranges and cost assignment types, one or more approvers will need to be determined to approve a spend. The approval process can span across several levels and the only variable that determines how many levels of approvals will be required are usually determined by the amount to be approved.

Then there are some organisations, where the approval  process is much more complex. For example a first level could be determined based on the account assignment, the second level could be based on the material type (service vs stock material), the amount of the spend, etc… you get the point, there are many more variables in play, that make the process more complex as more business rules need to be catered for….and the last thing that you want is for those rules to exist in your code! It is OK for the logic to embedded in code, but the rules (i.e whether John or Jane should approve) should be maintained by your business users. When the rules change or when employee leaves the organisation, such changes to your approval rules should be the responsibility of the business users to maintain.

Thankfully in SAP S/4HANA Cloud, especially since 1805 with the introduction of new functionality that allows you to keep track of approval levels in your custom logic, things just got a whole lot simpler!

In this simple example shown in the video, we will create a 2 item purchase requisition. As we are also performing the approval process at the item level, we will fire off 2 work items – one for each purchase requisition item. In this example, we are wanting to route the approval to a person that is neither the person responsible for the cost object, nor the manager of the person that created the requisition. We will therefor use the workflow approval Badi to define the logic to determine the approver(s). However as I said previously, we do not want to code in the logic the person that will receive the workflow approval request. No – we want to leverage a Business Rules like structure to hold this information.

To do so, we have created a custom business object – an approval table, as shown below.

The table that we added is simple in structure. For it we track the approval level, the cost object (the cost centre) and the approver of this combination. For the sake of simplicity, we will use the same table for the 2 approval levels that we have, but you can imagine, that you would have a different table for each approval level (if the structure was different of course).

From a coding point of view, there are two key elements in our logic.

The first one is retrieving the cost centre that was indicated as the cost assignment of the requisition items. To retrieve this information we directly call an API –> i_purreqnacctassgmt_api01. The code used here is:

 

SELECT SINGLE costcenter FROM i_purreqnacctassgmt_api01 INTO @data(lv_purchasereqcostcenter)
WHERE purchaserequisition = @purchasingdocument AND
purchaserequisitionitem = @purchasingdocumentitem.

Then the next piece of code is that which we use to retrieve the user that will become the approver. As I said, we do not want this in the code – so we need to go and fetch that information from our custom business object. The code used here is:

SELECT single approvinguser FROM yy1_approvalstable INTO @ls_badi_approver
WHERE CostObject = @lv_purchasereqcostcenter AND
ApprovingLvl = 1.

Essentially we are retrieving the business user ID of theApprover , for which the cost centre and approval level match where we are in the purchase requisition approval process.

Update 19 July 2018

By request, I am also adding the full custom logic code which I used to illustrate this determination.

    DATA:

      ls_badi_approver     TYPE if_mmpur_workflow_agents_v2=>bd_mmpur_s_badi_approver,
      lt_badi_approver     TYPE if_mmpur_workflow_agents_v2=>bd_mmpur_t_badi_approver,
      ls_previous_approver TYPE if_mmpur_workflow_agents_v2=>bd_mmpur_s_previous_approver,
      ls_new_approver      TYPE if_mmpur_workflow_agents_v2=>bd_mmpur_s_badi_approver.

    SELECT SINGLE costcenter FROM i_purreqnacctassgmt_api01 INTO @data(lv_purchasereqcostcenter)
    WHERE purchaserequisition = @purchasingdocument AND
          purchaserequisitionitem = @purchasingdocumentitem.


    SELECT single approvinguser FROM yy1_approvalstable INTO @ls_badi_approver
    WHERE   CostObject = @lv_purchasereqcostcenter AND
            ApprovingLvl = 1.

    APPEND  ls_badi_approver TO lt_badi_approver.
    ls_badi_approver-approvallevel = 1.

        SELECT single approvinguser FROM yy1_approvalstable INTO @ls_badi_approver
    WHERE   CostObject = @lv_purchasereqcostcenter AND
            ApprovingLvl = 2.

    APPEND  ls_badi_approver TO lt_badi_approver.
    ls_badi_approver-approvallevel = 2.


**  remove the previous approvers from the list of BAdI approvers
    LOOP AT previousapproverlist INTO ls_previous_approver.
      READ TABLE lt_badi_approver INTO ls_badi_approver
                              WITH KEY businessuser = ls_previous_approver-businessuser.
      CHECK sy-subrc = 0.
      DELETE lt_badi_approver WHERE approvallevel = ls_badi_approver-approvallevel.
    ENDLOOP.
*
**  determine the next approval level and appropriate approvers
    READ TABLE lt_badi_approver INTO ls_badi_approver INDEX 1.
    LOOP AT lt_badi_approver INTO ls_new_approver
                WHERE approvallevel = ls_badi_approver-approvallevel.
      APPEND ls_new_approver-businessuser TO approverlist.
    ENDLOOP.

If you want to replicate my custom business object, here is its structure.

Lastly, I am also adding the ‘After modification’ logic that I used in my custom business object. This logic is used to increment the ID number of the custom object entries as well as retrieve the name of the user id entered (useful to confirm that the entered code is a valid one).

* After Modify Determination for Node ID APPROVALSTABLE
*
* Importing Parameter : association (Navigation to Parent/Child/Associated Node Instances)
*                       write (API for creating and updating Custom Business Object Node Instances)
* Changing Parameter  : APPROVALSTABLE (Current Node Data)

* set ID
IF approvalstable-entryid IS INITIAL.
   SELECT MAX( entryid ) FROM yy1_approvalstable INTO @DATA(current_max_id).
   approvalstable-entryid = current_max_id + 1.
ENDIF.


IF approvalstable-approvinguser IS NOT INITIAL.
   approvalstable-approvername = cl_abap_context_info=>get_user_formatted_name( approvalstable-approvinguser ).
ENDIF.



If you enjoy this post, please consider subscribing to our youtube channel and follow the hashtag #S4HCKS on twitter.

Version used in recording 

Privacy Preference Center