Currently Being Moderated

Using Workflow Programming Exit for Travel Expense Approval Workflow: Copy attachments of travel expense attachments to workitem

Summary:
A programming exit is an ABAP class that the system executes at a specific time during the processing of a workflow. Programming exits enable you to implement your own enhancements and adaptations.
ABAP classes that you use as programming exits must not use the following elements:
●      COMMIT WORK
●      ROLLBACK WORK
●      Calling of function module DB_COMMIT
●      Any type of RFC calls
●      Any changes to a system element in the container
This article describes a business scenario where Program Exit can be used in workflow. Whenever a user creates travel expense report from ESS portal and attaches some documents with it, the attachments are linked to BUS2089 instance using Generic Object Services. Later on if an approver wants to see the attachments of the expense report, he/she should open the SAP back-end transaction (launched from portal using SAP GUI HTML). From there approver can view the attachments using GOS dropdown.
This process requires that approver should have access authorization to back-end transaction. At the same time to end user it is inconvenient to launch SAP transaction to view attachments of expense. Client requested a functionality where attachments of the expense report are directly available as work item attachment.
Reader should have basic understanding of SAP Workflow and Generic Object Services.
Author:Parag Parikh   
Company: Deloitte Consulting LLP
Created on: 24th March 2012
Author Bio
Parag Parikh.jpg
Parag Parikh is an SAP ABAP, SAP workflow consultant with 4.5 years of experience.  He has extensively worked on SAP ABAP and SAP workflow. Parag also has functional skills for SAP FS-CD solution. He has worked on many SAP modules including SAP FI/CO, SD, MM, QM, PP, PLM-RM, SRM, HCM, ESS/MSS and EH&S. Parag is working with Deloitte Consulting LLP as Workflow Consultant.  
Requirements in detail
1) Files attached to any travel expense report created by employee are linked to instance of Business Object BUS2089 using Generic Object Services
2) The approver should be able to view the attachments when he receives the work item in his/her inbox (SBWP) or UWL
3) The approver can approve/reject or send the expense report back to employee for revision. While revising the expense report, employee may add/remove some attachments. Hence it is necessary that every time a work item is created for travel expense approval step, we copy the attachments of BUS2089 instance to work item.
 
Creating Programming Exit Class
1) Create class ZHRXMCL_TRIP_APP_PROG_EXT in SE24.  Use interface IF_SWF_IFS_WORKFLOW_EXIT.
Exit class.JPG
2) Interface IF_SWF_IFS_WORKITEM_EXIT contains method EVENT_RAISED. SAP webflow engine calls this method when events like work item created, ready etc. are fired by workflow environment. Hence this method can be used to identify work item related events.
3) In the forwarded declaration for the class, declare type pool SWRCO. This type pool contains necessary data declaration to use program exit.
FI-TV1.JPG
 
Declare additional attributes as shown below in the class.Attrbiute WI_CONTEXT provides us the context of the work item for which program exit is trigerred.
4) Below is the sample code to be written in method EVENT_RAISED. We first check if the event triggered was 'CREATED'. If yes, we go ahead and call method AFTER_CREATION to handle event.
*--After creation, call out method
*--Set current work item context
  me->wi_context = im_workitem_context.

  IF im_event_name <> swrco_event_after_creation.
    EXIT.
  ENDIF.

*--Call after creation method
  me->after_creation( ).
5) Files attached to any travel expense report created by employee are linked to instance of Business Object BUS2089 using Generic Object Services. Hence in the method AFTER_CREATION we should first try to read the GOS Attachment and then copy these attachments to work item.
Restriction on program exit for workflow is that, within program exit methods we can not have call to an RFC FM. SAP FM available for reading and copying GOS attachments are RFC FM or internally calls RFC FM. Example is FM  BDS_BUSINESSDOCUMENT_GET_INFO. If we try to use SAP provided classes for GOS, again we need to investigate and make sure that the classes internally do not call RFC, which again makes this task laborious.
To overcome above restriction, one of the workaround is to create a custom event when work item is created. In response to this event, we can call a custom task which copies the attachment of travel expense to the approval work item. This will create a loose coupling between work item created event and process of copying GOS attachments to work item.
Programming Exit Class  workflow.JPG
 
Shown below is the sample code for method AFTER_CREATION where we trigger the custom event.
*--Local Variables
  DATA:l_workitem_id TYPE sww_wiid        ,
       l_value1      TYPE string          ,
       l_value2      TYPE string          .


  DATA:l_pernr TYPE persno   ,
       l_reinr TYPE reinr    .


  DATA:   l_object_key   TYPE swr_struct-object_key,
          lt_container    TYPE STANDARD TABLE OF swr_cont,
          ls_container TYPE swr_cont.

*--Local reference to work item container
  DATA:lrf_container TYPE REF TO if_swf_ifs_parameter_container.

*--Get work item ID
  CALL METHOD wi_context->get_workitem_id
    RECEIVING
      re_workitem = l_workitem_id.

*--Get work item container
  CALL METHOD wi_context->get_wi_container
    RECEIVING
      re_container = lrf_container.

*--Get Trip Number from container element
  TRY.
      CALL METHOD lrf_container->get
        EXPORTING
          name  = 'TripNumber'
        IMPORTING
          value = l_value1.
*    unit       =
*    returncode =
    CATCH cx_swf_cnt_elem_not_found .
    CATCH cx_swf_cnt_elem_type_conflict .
    CATCH cx_swf_cnt_unit_type_conflict .
    CATCH cx_swf_cnt_container .
  ENDTRY.

*--Get employee number from container element
  TRY.
      CALL METHOD lrf_container->get
        EXPORTING
          name  = 'EmployeeNumber'
        IMPORTING
          value = l_value2.
*    unit       =
*    returncode =
    CATCH cx_swf_cnt_elem_not_found .
    CATCH cx_swf_cnt_elem_type_conflict .
    CATCH cx_swf_cnt_unit_type_conflict .
    CATCH cx_swf_cnt_container .
  ENDTRY.

*--Call FM to get relationships if any of trip and copy attachments to work item
  l_pernr = l_value2.
  l_reinr = l_value1.

*--Create event to attach files
  l_object_key = l_reinr.
  ls_container-element = 'PersonnelNumber'.   
  ls_container-value   = l_pernr.
  APPEND ls_container TO lt_container.
  ls_container-element = 'TripNumber'
  ls_container-value   = l_reinr.
  APPEND ls_container TO lt_container.
  ls_container-element = 'WorkItem'
  ls_container-value   = l_workitem_id.
  APPEND ls_container TO lt_container.
  CALL FUNCTION 'SAP_WAPI_CREATE_EVENT'
    EXPORTING
      object_type     = 'ZHRXMTRIP'
      object_key      = l_object_key
      event           = 'SentForApproval'
    TABLES
      input_container = lt_container.
6) Shown below is the structure of custom business object ZHRXMTRIP and its event SentForApproval. We also see that event has parameters personnel number, trip number and approval work item number. These parameters can be used to first read GOS attachment and then copy them to approval work item.
Custom BO.JPG
Custom Business Object ZHRXMTRIP
Event Parameter.JPG
Parameters for event SentForApproval
7) Define a custom method in any SE24 class that you are using for workflow task (class with interface IF_WORKFLOW) and add logic below to archive desired functionality. In order to modularize the code, we see that FM ZHREXP_ATTACHMENTS_TO_WIis defined. This FM contains desired functionality to copy and attach files to workitem.
*--Attach the BUS2089 attachments to work item
  CALL FUNCTION 'ZHREXP_ATTACHMENTS_TO_WI'
    EXPORTING
      im_workitemid                  = i_workitem
      im_pernr                       = i_pernr
      im_reinr                       = i_reinr
    EXCEPTIONS
      no_attachment_found            = 1
      error_reading_attachment       = 2
      error_instantiating_attachment = 3
      OTHERS                         = 4.
  IF sy-subrc &lt;> 0.
    IF sy-subrc = 1.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
            RAISING no_attachment_found .
    ELSEIF sy-subrc = 2.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
            RAISING error_reading_attachment .
    ELSEIF sy-subrc = 3.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
            RAISING error_instantiating_attachment.
    ENDIF.
  ENDIF.
8) Below is the code for FM ZHREXP_ATTACHMENTS_TO_WI
 
FUNCTIONzhrexp_attachments_to_wi.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IM_WORKITEMID) TYPE  SWW_WIID OPTIONAL
*"     VALUE(IM_PERNR) TYPE  PERNR
*"     VALUE(IM_REINR) TYPE  REINR
*"  TABLES
*"      T_ATTA STRUCTURE  SWR_ATT_ID OPTIONAL
*"  EXCEPTIONS
*"      NO_ATTACHMENT_FOUND
*"      ERROR_READING_ATTACHMENT
*"      ERROR_INSTANTIATING_ATTACHMENT
*"---------------------------------------------------------------------
  DATA BEGIN OF ls_docid_structure.
          INCLUDE STRUCTURE soentryi1.
  DATA END OF ls_docid_structure.

  DATA: ls_lpor           TYPE sibflporb,
        lt_conn           TYPE TABLE OF bdn_con,
        ls_conn           TYPE bdn_con,
        ls_atta           TYPE swr_att_id,
        ls_key            TYPE soodk,
        ls_text           TYPE soli,
        ls_comment        TYPE bcss_dbpc,
        lt_hex_cont       TYPE TABLE OF solix,
        ls_hex_cont       TYPE solix,
        lrf_document      TYPE REF TO cl_document_bcs,
        lrf_bcs_exception TYPE REF TO cx_root,
        ls_att_header     TYPE swr_att_header.

  DATA: l_att_txt         TYPE string,
        l_text            TYPE string,
        l_file_ext        TYPE char3,
        l_document_id     TYPE sofolenti1-doc_id,
        l_binfile         TYPE xstring.

 
* Field Symbols
     FIELD-SYMBOLS <p> TYPE x.

* Constants
  CONSTANTS : lc_x        TYPE  char1      VALUE 'X',
              lc_bus2089  TYPE  bds_clsnam VALUE 'BUS2089',
              lc_clstype  TYPE  char2      VALUE 'BO',
              lc_e        TYPE  char1      VALUE 'E',
              lc_t        TYPE  char1      VALUE 'T',
              lc_b        TYPE  char1      VALUE 'B'.


  CONCATENATE im_pernr im_reinr INTO ls_lpor-instid.
  ls_lpor-typeid  = lc_bus2089.
  ls_lpor-catid   = lc_clstype.


  CALL FUNCTION 'BDS_ALL_CONNECTIONS_GET'
    EXPORTING
      classname        = lc_bus2089
      classtype        = lc_clstype
      objkey           = ls_lpor-instid
      all              = lc_x
      no_gos_docs      = ''
    TABLES
      all_connections  = lt_conn
    EXCEPTIONS
      no_objects_found = 1
      error_kpro       = 2
      internal_error   = 3
      not_authorized   = 4
      OTHERS           = 5.
  IF sy-subrc &lt;> 0.
    MESSAGE e681(zhr_msg) WITH im_pernr im_reinr RAISING
    error_reading_attachment.
  ELSEIF lt_conn[] IS INITIAL.
    MESSAGE e680(zhr_msg) WITH im_pernr im_reinr RAISING
    no_attachment_found.
  ENDIF.

*--Process the attachment list
  LOOP AT lt_conn INTO ls_conn.
    l_document_id = ls_conn-loio_id.
    CLEAR ls_docid_structure.
    MOVE l_document_id TO ls_docid_structure.
*--Check class of document
*  For text of ASC document, use BCS to easily fetch contents
    IF ls_conn-docuclass = 'txt' OR ls_conn-docuclass = 'TXT' OR
       ls_conn-docuclass = 'asc' OR ls_conn-docuclass = 'ASC'.
      CLEAR ls_key.
      ls_key-objtp = ls_docid_structure-objtp.
      ls_key-objyr = ls_docid_structure-objyr.
      ls_key-objno = ls_docid_structure-objno.
      TRY.
          CALL METHOD cl_document_bcs=>getu_instance_by_key
            EXPORTING
              i_sood_key   = ls_key
              i_no_enqueue = lc_x
            RECEIVING
              result       = lrf_document.
        CATCH cx_document_bcs .
          CALL METHOD lrf_bcs_exception->get_text
            RECEIVING
              result = l_text.
          MESSAGE e681(zhr_msg) WITH im_pernr im_reinr RAISING
          error_instantiating_attachment.
      ENDTRY.

*--Read content
      TRY.
          CALL METHOD lrf_document->if_document_bcs~get_body_part_content
            EXPORTING
              im_part    = 1
            RECEIVING
              re_content = ls_comment.
        CATCH cx_document_bcs .
          CALL METHOD lrf_bcs_exception->get_text
            RECEIVING
              result = l_text.

          MESSAGE e681(zhr_msg) WITH im_pernr im_reinr RAISING
                                     error_reading_attachment.
      ENDTRY.

      CLEAR:l_att_txt,ls_text.
      LOOP AT ls_comment-cont_text INTO ls_text.
        CONCATENATE l_att_txt ls_text INTO l_att_txt.
      ENDLOOP.

      l_file_ext = ls_conn-docuclass.
      TRANSLATE l_file_ext TO UPPER CASE.                "#EC TRANSLANG
      ls_att_header-file_type       = lc_t.
      ls_att_header-file_extension  = l_file_ext.
      CONCATENATE ls_conn-descript l_file_ext INTO ls_att_header-file_name.
      ls_att_header-language        = lc_e.
      CALL FUNCTION 'SAP_WAPI_ATTACHMENT_ADD'
        EXPORTING
          workitem_id    = im_workitemid
          att_header     = ls_att_header
          att_txt        = l_att_txt
          document_owner = ls_conn-crea_user
          do_commit      = lc_x
        IMPORTING
          att_id         = ls_atta.
      APPEND ls_atta TO t_atta.
      CLEAR ls_atta.
    ELSE.
*--For other types of document, SO_DOCUMENT_READ_API1 returns contents of the file
*  in HEX format
      CLEAR lt_hex_cont[].
*--Read the data
      CALL FUNCTION 'SO_DOCUMENT_READ_API1'
        EXPORTING
          document_id                = l_document_id
        TABLES
          contents_hex               = lt_hex_cont
        EXCEPTIONS
          document_id_not_exist      = 1
          operation_no_authorization = 2
          x_error                    = 3
          OTHERS                     = 4.

      IF sy-subrc NE 0.
        MESSAGE e681(zhr_msg) WITH im_pernr im_reinr RAISING error_reading_attachment.
      ENDIF.

      CLEAR l_binfile.
      LOOP AT lt_hex_cont INTO ls_hex_cont.
        ASSIGN ls_hex_cont TO <p> CASTING.
        CONCATENATE l_binfile <p> INTO l_binfile IN BYTE MODE.
      ENDLOOP.

      IF im_workitemid IS NOT INITIAL.
        l_file_ext = ls_conn-docuclass.
        TRANSLATE l_file_ext TO UPPER CASE.              "#EC TRANSLANG
        ls_att_header-file_type       = lc_b.
        ls_att_header-file_extension  = l_file_ext.
        CONCATENATE ls_conn-descript l_file_ext INTO ls_att_header-file_name.
        ls_att_header-language        = lc_e.
        CALL FUNCTION 'SAP_WAPI_ATTACHMENT_ADD'
          EXPORTING
            workitem_id    = im_workitemid
            att_header     = ls_att_header
            att_bin        = l_binfile
            document_owner = ls_conn-crea_user
            do_commit      = lc_x
          IMPORTING
            att_id         = ls_atta.
        APPEND ls_atta TO t_atta.
        CLEAR ls_atta.
      ENDIF.
    ENDIF"Binary or text
  ENDLOOP.

  IF t_atta[] IS INITIAL.
    MESSAGE e680(zhr_msg) WITH im_pernr im_reinr RAISING
    no_attachment_found.
  ENDIF.

ENDFUNCTION.

9) Now we can use the SE24 class method that calls the FM above in a standard task created in PFTC.
Copy_Att_task.JPG
In trigerring event tab of the task, provide the  name of custom BO event that we trigerred from program exit class.
TRig_Exvent.JPG
 
Binding.JPG
Shown above is binding of required details from trigerring event to task container.
10) In travel expense approval workflow, we can then specify name of program exit class in the program exit tab as shown below.
Program Exit Tab.JPG
11) Now, every time a travel expense report approval work item is created in approver's UWL, all the attachments of the expense are copied to work item as shown below. If needed we can remove the Business Object instance attached by default with work item.
FinalResult.png

Related Content

Below links are useful to understand SAP Workflow Program Exit.

Copyright

© Copyright 2012 SAP AG. All rights reserved.
No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP AG. The information contained herein may be changed without prior notice.
Some software products marketed by SAP AG and its distributors contain proprietary software components of other software vendors.
Microsoft, Windows, Excel, Outlook, and PowerPoint are registered trademarks of Microsoft Corporation.
IBM, DB2, DB2 Universal Database, System i, System i5, System p, System p5, System x, System z, System z10, System z9, z10, z9, iSeries, pSeries, xSeries, zSeries, eServer, z/VM, z/OS, i5/OS, S/390, OS/390, OS/400, AS/400, S/390 Parallel Enterprise Server, PowerVM, Power Architecture, POWER6+, POWER6, POWER5+, POWER5, POWER, OpenPower, PowerPC, BatchPipes, BladeCenter, System Storage, GPFS, HACMP, RETAIN, DB2 Connect, RACF, Redbooks, OS/2, Parallel Sysplex, MVS/ESA, AIX, Intelligent Miner, WebSphere, Netfinity, Tivoli and Informix are trademarks or registered trademarks of IBM Corporation.
Linux is the registered trademark of Linus Torvalds in the U.S. and other countries.
Adobe, the Adobe logo, Acrobat, PostScript, and Reader are either trademarks or registered trademarks of Adobe Systems Incorporated in the United States and/or other countries.
Oracle is a registered trademark of Oracle Corporation.
UNIX, X/Open, OSF/1, and Motif are registered trademarks of the Open Group.
Citrix, ICA, Program Neighborhood, MetaFrame, WinFrame, VideoFrame, and MultiWin are trademarks or registered trademarks of Citrix Systems, Inc.
HTML, XML, XHTML and W3C are trademarks or registered trademarks of W3C®, World Wide Web Consortium, Massachusetts Institute of Technology.
Java is a registered trademark of Oracle Corporation.
JavaScript is a registered trademark of Oracle Corporation, used under license for technology invented and implemented by Netscape.
SAP, R/3, SAP NetWeaver, Duet, PartnerEdge, ByDesign, SAP Business ByDesign, and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and other countries.
Business Objects and the Business Objects logo, BusinessObjects, Crystal Reports, Crystal Decisions, Web Intelligence, Xcelsius, and other Business Objects products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of Business Objects S.A. in the United States and in other countries. Business Objects is an SAP company.
All other product and service names mentioned are the trademarks of their respective companies. Data contained in this document serves informational purposes only. National product specifications may vary.
These materials are subject to change without notice. These materials are provided by SAP AG and its affiliated companies ("SAP Group") for informational purposes only, without representation or warranty of any kind, and SAP Group shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP Group products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty.

Comments

Delete Document

Are you sure you want to delete this document?