Skip to Content

Introduction & Requirement

Introduction:

Program exits are like user exits given by SAP in SAP Workflows which can be used to tweak standard workflow functionalities. Program exits are the hooks given in SAP Workflows where we can execute additional methods that are programmed when predefined events occur. ABAP Classes containing these methods are added. ABAP classes used must support the IF_SWF_IFS_WORKITEM_EXIT interface. SAP has given us a way using which we can design program exits in a work item and write custom logic to tweak standard work item functionality in different ways. Sometimes, we may come across the scenarios where we may need to update database table, we may need to get container values at run time and update them dynamically at run time. We may also put validations at run time level using program exits and throw error messages when validations fail and also stop work items from being deleted from sap inbox.

The events on which we can program are below:

1.    Before Creation     

2.    After Creation

3.    Before Execution

4.    After Execution

5.    After Execution of a Synchronous Object Method

6.    Before Physical Deletion

7.    After a Status Change

8.    After Rule Execution

9.    After an Action

10. Before an Action

Requirement:

This document explains about the use of program exits to control the sap work items and put any custom functionality at work item level. In standard SAP, work item is deleted in case of any action on work item. If we need to put certain validations and control the work items by throwing error messages, we can use program exits effectively. 

Following 2 scenarios will explain how program exits can be used in various complex scenarios where requirement is to change the standard work items behavior and put validation on work item actions, throw error message on validation failure and stop work item from being deleted from SAP Inbox at validation failure. 

The scenarios given in this document explain the use of Program Exits in SAP Workflows to tweak the SAP Work item functionality without making major changes at workflow level. The other way to meet these requirements is to put a loop in the workflow step and send the work item again and again until validation is successful .Using Program exit method, we can effectively meet this requirement and avoid changes in SAP Workflows.

Scenario 1:

We are taking example of Journal Entry workflow which is triggered when accounting document is parked.

In Example Journal Entry workflow, the work items are sent to designated approvers for approval for posting. Based on approval limits, the work items are sent either for approval or for forwarding. Issue was that the work items were moving out of the inbox, allowing the approver to approve even though document was kept opened by another user, which was not correct. The requirement was to stop the user from approving the work item if document was being edited by another user and throw an error message. 

Pre-requisite:

  • Custom ABAP classes are required to be put in program exit tab of SAP Workflows.
  • The ABAP Class used in program exits must support the interface IF_SWF_IFS_WORKITEM_EXIT and this class must not have any call to the RFC function modules also there shouldn’t be any commit or roll back statements in it.

Solution Using Program Exit:

In Example Journal Entry Workflow, there is a decision step for approval as shown below:


/wp-content/uploads/2014/09/pic1_548139.jpg

In Order to control the work items sent through decision steps above, we introduced program exits in both the decision steps. For program exits, we need to create ABAP Class


/wp-content/uploads/2014/09/pic1_548139.jpg

  ABAP Class Creation:

  • The ABAP Class should support the interface IF_SWF_IFS_WORKITEM_EXIT. The properties of ABAP Class should be as shown in screen shot below:

 

   /wp-content/uploads/2014/09/pic1_548139.jpg

  • Add interface IF_SWF_IFS_WORKITEM_EXIT in the interface tab.


    

      /wp-content/uploads/2014/09/pic1_548139.jpg

     

  • The Attributes corresponding to standard interface are automatically populated in Attributes tab. An additional attribute WI_CONTEXT is added to get the current context of work items.

      

     /wp-content/uploads/2014/09/pic1_548139.jpg


    

  • Method IF_SWF_IFS_WORKITEM_EXIT~EVENT_RAISED is created automatically. Two additional methods AFTER_CREATION and AFTER_EXECUTION are added to handle predefined events of work items as shown in below screen shot:

     

      /wp-content/uploads/2014/09/pic1_548139.jpg

   

  Implementation of Method EVENT_RAISED:

The main logic for throwing error and restricting work item from moving out of inbox  if document is opened by another user is written in this method.

   Coding snippet of EVENT_RAISED Method:


Declare the local data used in the Class.

  DATA: lcl_wihead      TYPE swr_wihdr, “Work Item Structure.

        lw_container    TYPE swr_cont, “Container fields-value

        it_container    TYPE STANDARD TABLE OF  swr_cont.

* Local data declaration.

  DATA: lv_bukrs        TYPE bukrs,

        lv_belnr        TYPE belnr_d,

        lv_gjahr        TYPE gjahr,

        lv_message(50)  TYPE c.

* Local Constant:

  CONSTANTS: lc_e       TYPE enqmode VALUE ‘E’,

             lc_fipp    TYPE char4   VALUE ‘FIPP’.

* Get Header details of Context for Work Item.

  me->wi_context = im_workitem_context.

* Event After Creation.

  IF im_event_name = swrco_event_after_creation.

    me->after_creation( ).

  ELSEIF im_event_name = swrco_event_after_execution ” Even After Execution

    OR    im_event_name = swrco_event_state_changed” Even After Changed

    OR    im_event_name = swrco_event_before_execution.” Even Before Changed

* Call the header method to get the workitem data.

    CALL METHOD wi_context->get_header

      RECEIVING

        re_workitem_header = lcl_wihead.

* Workflow interface to read the container.

    CALL FUNCTION ‘SAP_WAPI_READ_CONTAINER’

      EXPORTING

        workitem_id      = lcl_wihead-wi_id

        language         = sy-langu

        user             = sy-uname

      TABLES

        simple_container = it_container.

    CLEAR: lw_container,

           lv_bukrs,

           lv_belnr,

           lv_gjahr.

    READ TABLE it_container INTO lw_container WITH KEY element = lc_fipp.

    IF sy-subrc = 0.

      lv_bukrs =  lw_container-value+20(4).

      lv_belnr =  lw_container-value+24(10).

      lv_gjahr =  lw_container-value+34(4).

    ENDIF.

    CALL FUNCTION ‘ENQUEUE_EFBKPF’

      EXPORTING

        mode_bkpf      = lc_e

        mandt          = sy-mandt

        bukrs          = lv_bukrs

        belnr          = lv_belnr

        gjahr          = lv_gjahr

        x_bukrs        = ‘ ‘

        x_belnr        = ‘ ‘

        x_gjahr        = ‘ ‘

        _scope         = ‘2’

        _wait          = ‘ ‘

        _collect       = ‘ ‘

      EXCEPTIONS

        foreign_lock   = 1

        system_failure = 2

        OTHERS         = 3.

    IF sy-subrc <> 0.

* Implement suitable error handling here

      IF sy-subrc = 1.

        CLEAR lv_message.

        CONCATENATE sy-msgv1 text-t01

          INTO lv_message

          SEPARATED BY space.

        MESSAGE e601 (mc) WITH lv_message.

      ENDIF.

    ELSE.

      CALL FUNCTION ‘DEQUEUE_ALL’.

    ENDIF.


Execution:

  • Document 200000165 is parked and a work item is sent to designated approver (I am approver in this case). The event is triggered and workflow sends a work item in my inbox as I am the approver in this case.
  • Click on Park button:

  

  /wp-content/uploads/2014/09/pic1_548139.jpg

Document is sent for approval.


  /wp-content/uploads/2014/09/pic1_548139.jpg

  I opened document 200000165 in change mode and then tried to execute this work item: Work item remains in inbox and we get following error message (X_GUPTAV is my user id in this example):


   /wp-content/uploads/2014/09/pic1_jpg_548169.png 

 

Program exit code is executed as soon as we click on the work item and code checks if the document is opened and throws an error message when document is opened by same/another user. If document is not opened in change mode and user clicks on work item, there will be no error message and workflow processing will proceed ahead.


  

Scenario 2:

In example JE Workflow, there is an option to forward the work item if designated approver of work item is not authorized to approve the request.

/wp-content/uploads/2014/09/pic1_548139.jpg

   The requirement is to send the work item to 1st level approver with an option to forward the work item to 2nd level approver as 1st level approver is not authorized. The work item will look like below:


/wp-content/uploads/2014/09/pic1_548139.jpg

   When forward button is pressed, the user should get a pop up to select the 2nd level approver and then there should be another pop up to write comments for 2nd level approval. If wrong approver is chosen by user in first pop up, there should be an error message and work item should be intact in inbox. In any pop up if cancel is selected, there should be an error message that action cancelled by user.

   

  

Solution using Program exit:

As already explained in scenario 1, we need to create a custom ABAP class and assign in program exit tab for the decision activity as below:


   /wp-content/uploads/2014/09/pic1_548139.jpg

    All the other steps are same as scenario 1 e.g. ABAP class creation, methods, events etc.

 

 

Coding snippet of EVENT_RAISED Method:

  

METHOD if_swf_ifs_workitem_exit~event_raised.

* Types Declaration.

  TYPES: BEGIN OF ty_usr_det,

          user          TYPE xubname,

          frwd_reason   TYPE txline,

         END OF ty_usr_det.

* Data Declaration.

  DATA: lcl_wihead      TYPE swr_wihdr, “Work Item Structure.

        lw_container    TYPE swr_cont,  “Container fields-value

        indxkey         TYPE srtfd VALUE ‘KEYVALUE’,

        ls_usr_det      TYPE ty_usr_det,

        lv_bukrs        TYPE bukrs,

        lv_belnr        TYPE belnr_d,

        lv_gjahr        TYPE gjahr,

        lv_user_id      TYPE usnam,

        lv_frwd_reason  TYPE txline,

        lv_user         TYPE xubname,

        lv_action       TYPE char4,

        it_container    TYPE STANDARD TABLE OF  swr_cont,

        it_return       TYPE STANDARD TABLE OF bapiret2,

        it_bapiaddr3    TYPE bapiaddr3,

        lv_message(50)  TYPE c.

* Begin of Change by x_wadhawanm – Defect 6226 – EWMK916075

  DATA: t_vbkpf         TYPE STANDARD TABLE OF vbkpf,

        t_msg           TYPE STANDARD TABLE OF msg_tab_line,

        w_msg           TYPE msg_tab_line,

        w_vbkpf         TYPE vbkpf.

* End of Change by x_wadhawanm – Defect 6226 – EWMK916075

* Local Constant declaration

  CONSTANTS: lc_0001(4) TYPE c       VALUE ‘0001’,

             lc_can(7)  TYPE c       VALUE ‘CX_CANC’,

             lc_e       TYPE enqmode VALUE ‘E’,

             lc_sb(2)   TYPE c       VALUE ‘SB’,

             lc_fipp    TYPE char4   VALUE ‘FIPP’,

             lc_zfipp    TYPE char5   VALUE ‘ZFIPP’.

* Get Header details of Context for Work Item.

  me->wi_context = im_workitem_context.

* Event After Creation.

  IF im_event_name = swrco_event_after_creation.

    me->after_creation( ).

  ELSEIF im_event_name = swrco_event_after_execution

  OR     im_event_name =  swrco_event_state_changed.

* Call the header method to get the workitem data.

    CALL METHOD wi_context->get_header

      RECEIVING

        re_workitem_header = lcl_wihead.

* Workflow interface to read the container.

    CALL FUNCTION ‘SAP_WAPI_READ_CONTAINER’

      EXPORTING

        workitem_id      = lcl_wihead-wi_id

        language         = sy-langu

        user             = sy-uname

      TABLES

        simple_container = it_container.

    CLEAR: lw_container,

           lv_bukrs,

           lv_belnr,

           lv_gjahr.

    READ TABLE it_container

      INTO lw_container

      WITH KEY element = lc_fipp.

    IF sy-subrc = 0.

      lv_bukrs =  lw_container-value+20(4).

      lv_belnr =  lw_container-value+24(10).

      lv_gjahr =  lw_container-value+34(4).

    ENDIF.

    CALL FUNCTION ‘ENQUEUE_EFBKPF’

      EXPORTING

        mode_bkpf      = lc_e

        mandt          = sy-mandt

        bukrs          = lv_bukrs

        belnr          = lv_belnr

        gjahr          = lv_gjahr

        x_bukrs        = ‘ ‘

        x_belnr        = ‘ ‘

        x_gjahr        = ‘ ‘

        _scope         = ‘2’

        _wait          = ‘ ‘

        _collect       = ‘ ‘

      EXCEPTIONS

        foreign_lock   = 1

        system_failure = 2

        OTHERS         = 3.

    IF sy-subrc <> 0.

* Implement suitable error handling here

      IF sy-subrc = 1.

        CLEAR lv_message.

        CONCATENATE sy-msgv1 text-003

          INTO lv_message

          SEPARATED BY space.

        MESSAGE e601(mc) WITH lv_message.

      ENDIF.

    ELSE.

      CALL FUNCTION ‘DEQUEUE_ALL’.

    ENDIF.

    READ TABLE it_container

    INTO lw_container

    WITH KEY element = ‘_WI_RESULT’.

    IF sy-subrc = 0.

      lv_action = lw_container-value+0(4).

      IF lv_action = lc_0001 AND

        sy-ucomm NE ‘CX_CONT’.

        CALL FUNCTION ‘ZFI_JEWF_USER_SEL’

          IMPORTING

            user_id        = lv_user_id

            forward_reason = lv_frwd_reason.

        IF sy-ucomm EQ lc_can.

          MESSAGE text-001 TYPE lc_e.

        ENDIF.

        SELECT SINGLE user_id

          FROM zfi_appr_limit2

          INTO lv_user

         WHERE  user_id EQ lv_user_id.

        IF sy-subrc <> 0.

          MESSAGE text-002 TYPE lc_e.

        ENDIF.

        lv_user =  lv_user_id.

        ls_usr_det-user = lv_user.

        ls_usr_det-frwd_reason = lv_frwd_reason.

        indxkey = ‘SB’.

        EXPORT  ls_usr_det FROM ls_usr_det TO

                  DATABASE indx(st) ID indxkey.

      ENDIF.

    ENDIF.

ENDMETHOD.

Execution:

  • A document is parked in which the amount is such that 1st level approver is not authorized to approve it and it has to be sent to next level approver.


   /wp-content/uploads/2014/09/pic1_548139.jpg

  

  • A work item is sent to 1st level approver for forwarding the work item to next authorized approver as below:

     /wp-content/uploads/2014/09/pic1_548139.jpg

     If wrong approver is input by user then an error message is thrown and work item stays in inbox as below:


    /wp-content/uploads/2014/09/pic1_548139.jpg

      If correct approver is input in the pop up which is maintained in ZFI_APPR_LIMIT2, another pop up comes where user can put forwarding comments as below:

     

    /wp-content/uploads/2014/09/pic1_548139.jpg

    If cancel button in above pop ups is pressed, an error message is thrown as below:

  

   /wp-content/uploads/2014/09/pic1_548139.jpg

    If ok button is pressed, the work item is sent to the next level approver given in 1st pop up:

  

    /wp-content/uploads/2014/09/pic1_jpg_548169.png

   

I hope the above examples explain this program exit functionality and might be useful to workflow consultants in their developments.

Any review comments or improvement comments are welcome!!



To report this post you need to login first.

9 Comments

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

  1. Paul Bakker

    Vivek,

    Thanks for that – some good examples of using a feature that I’ve never explored myself.

    I’m not sure I agree with some of your scenarios though – for example in Scenario 2, why would a workitem be sent to an unauthorized user in the first place? Wouldn’t it be simpler to fix the agent assignment instead?

    I have a question about Scenario 1: why you are also checking for locks in the events ‘After Execution’ and ‘After Changed’ (of the workitem). Isn’t it too late then?

    thanks again for posting this

    Paul B

    (0) 
    1. vivek gupta Post author

      Hi Paul,

      Thanks for raising these queries..

      Scenario1, we are using locking FM to check if document is locked by any other user or not after approve/forward buttons are pressed . After execution is triggered after buttons on workitem are pressed and we check the locking of document by any other user and we give error message if this is the case.

      Scenario2:I need to explain a bit more about this in the document. The business scenario is to check 2 levels of approvals from 2 custom tables. First approvers are fetched from 1st custom table against the company code and work item is sent. Approve or forward option is decided based on the eligibility of user from second custom table which has approvers against amount range for which approval can be done. If approver from 1st custom table is not authorized, forward option is sent in the work item else approve option is sent.

      Hope this clarifies.

      Thanks,

      Vivek

      (0) 
  2. andrew curtis

    You can use

    im_workitem_context->get_top_container( ).


    instead of the SAP_WAPI.  I guess my point is, there are loads of Methods in the Std Classes that can help you.


    A

    (0) 
  3. Ioan Radulescu

    just implemented one programmer exit and the one thing that maybe isn’t clear is that the programmer exit is only executed when the user is doing something personally with the workitem. With the user’s user not WF-BATCH. So if the user didn’t touch it, nothing is generated for instance within the workitem (I was creating an attachment in the workitem for the user to see before doing anything at all). This is of course not so bad in the business workplace, but terrible when using the ABAP WD inbox functionality (basically the workitem stays naked in the inbox).

    (0) 
  4. Siddhartha Srivastava

    Hi Vivek,

    I have exactly followed your article. In mycase I am sending an email before WI Creation. but its is not triggering the event (SWRCO_EVENT_AFTER_CREATION), as I do not see any email sent in SOST.

    What could I be missing ?

    Thanks,

    Sid

    (0) 
  5. Suresh M

    Nice document Vivek. Thanks for sharing.

    If possible, can you please brief the second point which you have mentioned under pre-requisites.

    (0) 

Leave a Reply