Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
AbdelrahmanZaki
Participant
5,385

Hello SAP Community,

In this post, I will walk you through a technical solution for triggering workflow events from the save action of a Restful ABAP Programming (RAP) application. We aim to assign a buyer to each Purchase Requisition and send a workflow confirmation dialog to the buyer's inbox for necessary actions, such as creating a purchase order.

The main idea here is to utilize the unmanaged save in the behavior definition to call a function module in the background.

Using a managed save, the 'save' implementation method restricts you from calling functions, performing rollbacks, commits, or using classic ABAP statements. In contrast, an unmanaged save provides the 'save_modified' method, which allows you to call a function module in a background task and addresses the limitations of classic ABAP statements.

For more information, you can refer to this Q&A thread

 

Let's dive into the implementation details.

Scenario

We need to assign a buyer to each Purchase Requisition. Once the buyer is assigned, a workflow confirmation dialog is sent to their inbox, prompting them to take necessary actions, such as creating a purchase order.

Solution Outline

To achieve this, we'll use an unmanaged save in the behavior definition to call a function module in the background. Here's a step-by-step guide on how to implement this solution.

Note: I will include my complete solution. You might notice several options in the behavior definition. such as:

 

 

 

authorization master (instance);
update (features: instance, precheck);

 

 

 

These instance options enable you to check for edit authority (i.e., who has the edit role).

Additionally, the validation ensures that the Buyer field is validated upon the save action.

 

 

 

validation validateBuyer on save { field Buyer; create; update; } 

 

 

 

1. Apend the field Buyer which is from type same as system user (char12)

Note: I prefer to create a new z table without appending the field to standard table EBAN, but I used this case because I was searching for a way to add this editable field in standard screen of Purchase requisition ME53N .. anyway lets complete the structure ZEBAN is append structure for standard table EBAN

AbdelrahmanZaki_0-1720699505655.png

2. Implement the RAP Application Logic:

  1. Create CDS View: we will use standard cds I_PurchaseReqnItem as reference because our app is most like the standard fiori app Process Purchase Requisitions (App ID F1048)

     

 

 

 

@EndUserText.label: 'PR Buyer Assign'
@Metadata.allowExtensions: true

@ObjectModel.modelCategory: #BUSINESS_OBJECT
@ObjectModel.compositionRoot: true
@ObjectModel.transactionalProcessingEnabled: true
@ObjectModel.writeActivePersistence: 'ZMM_PR_BUYER_BO'

@ObjectModel:{
createEnabled: true,
updateEnabled: true,
deleteEnabled: true
}
@Search.searchable: true


define root view entity ZCDS_PR_Buyer_Assign

as select from I_PurchaseReqnItem as header
    inner join eban on eban.banfn = header.PurchaseRequisition and eban.bnfpo = header.PurchaseRequisitionItem
    association [0..1] to I_PurchasingGroup as _PurchasingGroup on  $projection.PurchasingGroup = _PurchasingGroup.PurchasingGroup
  association [0..1] to pa0001 as pa on $projection.RequisitionerName =  pa.pernr
{

      //@Consumption.valueHelpDefinition: [{entity:{name:'C_PurchaseReqnHeader' , element: 'PurchaseRequisition'}}]
      @Consumption.valueHelpDefinition: [{entity:{name:'ZCDS_PR_SEARCH_VALUE' , element: 'PurchaseRequisition'}}]
      @Consumption.semanticObject: 'PurchaseRequisition'
      //semanticObjectAction : 'displayAdvanced'
      key header.PurchaseRequisition,
      
      @ObjectModel.readOnly: true
      header.PurchaseRequisitionItem,

      @Consumption.valueHelpDefinition: [{entity:{name:'/BSNAGT/P_USR21' , element: 'bname'}}]
      @ObjectModel.readOnly: false
      eban.buyer as Buyer,
      
      @ObjectModel.readOnly: false
      eban.comments as Comments,
      
      @ObjectModel.readOnly: true
      header.PurchaseRequisitionType,

      @Consumption.filter.hidden:true
      @ObjectModel.readOnly: true
      @ObjectModel.virtualElement : true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_PURCHASEREQN_PROF_TRA_EXT'
      // cast('' as batxt)                      as PurchasingDocumentTypeName,
      cast('' as abap.char( 20 ))          as PurchasingDocumentTypeName,


      @ObjectModel.readOnly: true
      @Consumption.semanticObject: 'Supplier'
      header.Supplier,
      
      @ObjectModel.virtualElement : true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_PURCHASEREQN_PROF_TRA_EXT'
      @ObjectModel.readOnly: true
      @EndUserText.label: 'Number of Items'
      cast(0 as abap.int8 )                as NumberOfItems,

      header.PurchasingDocumentSubtype,

      @EndUserText.label: 'Total Value'
      @Semantics.amount: {currencyCode: 'Currency'}
      @ObjectModel.readOnly: true
      @ObjectModel.virtualElement : true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_PURCHASEREQN_PROF_TRA_EXT'
      cast ( ('00')  as abap.curr(15,2) )  as TotalNetAmount,

      @EndUserText.label: 'Currency'
      @ObjectModel.readOnly: true
      @ObjectModel.virtualElement : true
      @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_PURCHASEREQN_PROF_TRA_EXT'
      cast ( ('')    as abap.cuky( 5 ) )   as Currency,
      
      @ObjectModel.readOnly: true
      header.Material,
      
      @ObjectModel.readOnly: true
      header.PurchaseRequisitionItemText,
      
      //@Semantics.businessDate.at:true
      //header.CreationDate, //this is BADAT field originally
      @ObjectModel.readOnly: true
      eban.creationdate as CreationDate,
      
      @ObjectModel.readOnly: true
      header.Plant,
      
      @ObjectModel.readOnly: true
      header.PurReqnReleaseStatus,
      
      @ObjectModel.readOnly: true
      header.PurchasingGroup,
      
      @ObjectModel.readOnly: true
      _PurchasingGroup.PurchasingGroupName as PurchasingGroupName,
      
      @ObjectModel.readOnly: true
      header.ProcessingStatus,
      
      @ObjectModel.readOnly: true
      header.RequisitionerName,
      //pa0001.ename as RequisitionerNameFull
      
      @ObjectModel.readOnly: true
      header.CreatedByUser,
      
      @ObjectModel.readOnly: true
      pa.ename as CreatedByFullName
      
}

where
header.PurchaseRequisitionItem = '00010'
and header.ProcessingStatus = 'N'
and header.PurReqnReleaseStatus = '05'
and header.PurchaseRequisitionType <> 'NB'

 

 

 

 


2.class for virtual elemets ZCL_PURCHASEREQN_PROF_TRA_EXT

 

 

 

 

 

 

class ZCL_PURCHASEREQN_PROF_TRA_EXT definition
  public
  final
  create public .

public section.

  interfaces IF_SADL_EXIT .
  interfaces IF_SADL_EXIT_CALC_ELEMENT_READ .
protected section.
private section.

  data MO_PURCHASEREQN_API type ref to CL_PURCHASEREQN_PROF_BOPF_API .
ENDCLASS.

CLASS ZCL_PURCHASEREQN_PROF_TRA_EXT IMPLEMENTATION.

  METHOD IF_SADL_EXIT_CALC_ELEMENT_READ~CALCULATE.

    DATA lt_calculated_purchasereqn TYPE tt_cpurreqn.
    DATA lt_calculated_purchasereqn2 TYPE table of ZCDS_PR_Buyer_Assign.

    DATA(lo_purchasereqn_api) = cl_purchasereqn_prof_bopf_api=>get_instance( ).

    "proceed only if atleast one row of data was read
    IF it_original_data IS NOT INITIAL.

      "only if atleast one of the transient fields are requested
      IF line_exists( it_requested_calc_elements[ table_line = 'PURREQNHEADERDESCRIPTION' ] )
        OR line_exists( it_requested_calc_elements[ table_line = 'TOTALNETAMOUNT' ] )
          OR line_exists( it_requested_calc_elements[ table_line = 'CURRENCY' ] )

              "Added in 1908 Dev code as a part of refactoring
              OR line_exists( it_requested_calc_elements[ table_line = 'NUMBEROFITEMS' ] )
              OR line_exists( it_requested_calc_elements[ table_line = 'PURCHASINGDOCUMENTTYPENAME' ] )
              .

***************performance improvement code*************************

        CALL METHOD lo_purchasereqn_api->calc_header_transient_fields
          EXPORTING
            it_original_data       = it_original_data
          IMPORTING
            et_purchasereqn_header = lt_calculated_purchasereqn.

***************performance improvement code*************************

        MOVE-CORRESPONDING lt_calculated_purchasereqn TO lt_calculated_purchasereqn2.

        MOVE-CORRESPONDING lt_calculated_purchasereqn2 TO ct_calculated_data.

      ENDIF.

    ENDIF.

  ENDMETHOD.

  METHOD IF_SADL_EXIT_CALC_ELEMENT_READ~GET_CALCULATION_INFO.

  ENDMETHOD.
ENDCLASS.

 

 

 

 


As you notice it is also copy from the standard one for virtual elements.

3.Create Metadata Extension:
Use the annotation in main CDS @Metadata.allowExtensions: true to allow extensions.

This extension manages the object page in fiori element app.

 

 

 

 

@Metadata.layer: #PARTNER
@Search.searchable: true
annotate view ZCDS_PR_Buyer_Assign with
{

  @Search: {defaultSearchElement: true, ranking: #MEDIUM, fuzzinessThreshold: 0.8}
  : {
  lineItem: [ { position: 10, importance: #HIGH } ],
  selectionField: [ { position: 10 } ],
  identification:[ { position: 10 } ]
  }
  PurchaseRequisition;
  
  : {
  lineItem: [ { position: 20, importance: #HIGH } ],
  selectionField: [ { position: 20 } ],
  identification:[ { position: 20 } ]
  }
  Buyer;
  
  : {
  lineItem: [ { position: 30, importance: #HIGH } ],
//  selectionField: [ { position: 30 } ],
  identification:[ { position: 30 } ]
  //multiLineText: true
  }
  Comments;
}

 

 

 

 

4.Behavior Definition (Unmanaged Save):

 

 

 

 

managed implementation in class zbp_cds_pr_buyer_assign unique;

define behavior for ZCDS_PR_Buyer_Assign 
lock master
authorization master ( instance )
with unmanaged save
{
  update ( features : instance, precheck );
  delete ( features : instance, precheck );

  field ( mandatory : create, readonly : update ) PurchaseRequisition;
  field ( mandatory : create ) buyer;


    field (readonly) PurchaseRequisitionItem;
    field (readonly) PurchaseRequisitionType;
    field (readonly) PurchasingDocumentTypeName;
    field (readonly) NumberOfItems;
    field (readonly) PurchasingDocumentSubtype;
    field (readonly) Currency;
    field (readonly) TotalNetAmount;
    field (readonly) Material;
    field (readonly) PurchaseRequisitionItemText;
    field (readonly) Plant;
    field (readonly) PurReqnReleaseStatus;
    field (readonly) PurchasingGroup;
    field (readonly) PurchasingGroupName;
    field (readonly) RequisitionerName;
    field (readonly) CreatedByUser;
    field (readonly) CreatedByFullName;


validation validateBuyer on save { field Buyer; create;update; }

}

 

 

 

 

5.Implement Behavior Class:

 

 

 

 

 

 

CLASS zbp_cds_pr_buyer_assign DEFINITION PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF zcds_pr_buyer_assign.
ENDCLASS.

CLASS zbp_cds_pr_buyer_assign IMPLEMENTATION.
ENDCLASS.​

 

 

 

 

 

 

 

 

 

CLASS lhc_ZCDS_PR_Buyer_Assign DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.

    METHODS validateBuyer FOR VALIDATE ON SAVE
      IMPORTING keys FOR ZCDS_PR_Buyer_Assign~validateBuyer.

    METHODS get_authorizations FOR INSTANCE AUTHORIZATION
        IMPORTING keys REQUEST requested_authorizations FOR ZCDS_PR_Buyer_Assign RESULT result.

    METHODS get_instance_features FOR INSTANCE FEATURES
      IMPORTING keys REQUEST requested_features FOR ZCDS_PR_Buyer_Assign RESULT result.

    METHODS is_update_granted
      RETURNING VALUE(update_granted) TYPE abap_bool.

ENDCLASS.

CLASS lhc_ZCDS_PR_Buyer_Assign IMPLEMENTATION.

  METHOD validateBuyer.


    " Read relevant data
    READ ENTITIES OF zcds_pr_buyer_assign IN LOCAL MODE
    ENTITY ZCDS_PR_Buyer_Assign
    FIELDS (  Buyer ) WITH CORRESPONDING #( keys )
    RESULT DATA(lt_buyer_assign)
  FAILED DATA(lt_failed).

    failed =  CORRESPONDING #( DEEP lt_failed  ).
    DATA lt_buyer TYPE SORTED TABLE OF demo_sales_bupa
      WITH UNIQUE KEY id.

    lt_buyer = CORRESPONDING #( lt_buyer_assign
                 MAPPING id = Buyer EXCEPT * ).


    DATA ls_buyer_assign LIKE LINE OF lt_buyer_assign.
    DATA ls_buyer LIKE LINE OF lt_buyer.
    DATA lo_message TYPE REF TO if_abap_behv_message.

    READ TABLE lt_buyer_assign INTO ls_buyer_assign INDEX 1.
    READ TABLE lt_buyer INTO ls_buyer INDEX 1.

    data(has_error) = abap_false.
    data message_number type numchar3.

    IF ls_buyer-id IS INITIAL.
        has_error = abap_true.
        message_number = 002.
    ELSE.
        select single BNAME from usr21 into (lv_BNAME) where BNAME = _buyer-id.
        if sy-subrc <> 0.
            has_error = abap_true.
            message_number = 003.
        endif.
    ENDIF.


    if has_error = abap_true.
        " If so we are loading a message from the global message class ZCONNECTION_MESSAGES.
          lo_message = me->new_message(
            id = 'ZFIORI'
            number = message_number "002
            severity = ms-error
          ).

          " Appending the message to the RAP runtime to show it to the user.
          APPEND VALUE #(
            %tky = ls_buyer_assign-%tky
            %msg = lo_message
          ) TO reported-zcds_pr_buyer_assign.

          " Abort the save by adding an entry to the failed component.
          APPEND VALUE #(
            %tky = ls_buyer_assign-%tky
          ) TO failed-zcds_pr_buyer_assign.
    endif.




  ENDMETHOD.


  METHOD get_authorizations.

    DATA update_grtanted TYPE abap_bool.
    "update_grtanted = abap_false.
      DATA lo_message TYPE REF TO if_abap_behv_message.

      READ ENTITIES OF zcds_pr_buyer_assign IN LOCAL MODE
        ENTITY ZCDS_PR_Buyer_Assign
        FIELDS ( Buyer ) WITH CORRESPONDING #( keys )
        RESULT DATA(ZCDS_PR_Buyer_Assign_Edit)
        FAILED failed.

      CHECK ZCDS_PR_Buyer_Assign_Edit is not initial.
      data(update_requested) = COND #( WHEN requested_authorizations-%update = if_abap_behv=>mk-on
                                       THEN abap_true ELSE abap_false ).
      data(delete_requested) = COND #( WHEN requested_authorizations-%delete = if_abap_behv=>mk-on
                                       THEN abap_true ELSE abap_false ).

      loop at ZCDS_PR_Buyer_Assign_Edit ASSIGNING FIELD-SYMBOL(<lfs_Buyer_Assign>).
        if update_requested = abap_true or delete_requested = abap_true.

            update_grtanted = is_update_granted(  ).

            if update_grtanted = abap_false.

                lo_message = me->new_message(
                    id = 'ZFIORI'
                    number = 004
                    severity = ms-error
                ).
                APPEND VALUE #(  %tky = <lfs_Buyer_Assign>-%tky ) to failed-ZCDS_PR_Buyer_Assign.
                APPEND VALUE #( %tky = keys[ 1 ]-%tky
                                 %msg = lo_message
                ) to reported-ZCDS_PR_Buyer_Assign.

            ENDIF.
        endif.
      endloop.

  ENDMETHOD.

  METHOD get_instance_features.

    READ ENTITIES OF zcds_pr_buyer_assign IN LOCAL MODE
        ENTITY ZCDS_PR_Buyer_Assign
         ALL FIELDS
         WITH CORRESPONDING #( keys )
         RESULT DATA(entities).


   data(lv_update_delete) = COND #( WHEN is_update_granted( ) IS INITIAL
                                                      THEN if_abap_behv=>fc-o-disabled
                                                      ELSE if_abap_behv=>fc-o-enabled ).
    result = VALUE #( FOR entity IN entities
                    ( %tky                   = entity-%tky
                      %update                = lv_update_delete
                      %delete                = lv_update_delete
                       ) ).

  ENDMETHOD.
  METHOD is_update_granted.
    "For instance auth

      AUTHORITY-CHECK OBJECT 'ZMM_BUYER'
        ID 'ACTVT'      FIELD '02'.
      update_granted = COND #( WHEN sy-subrc = 0 THEN abap_true ELSE abap_false ).
  ENDMETHOD.

ENDCLASS.


CLASS lsc_ZCDS_PR_Buyer_Assign DEFINITION INHERITING FROM cl_abap_behavior_saver.
  PROTECTED SECTION.


    METHODS save_modified             REDEFINITION .

ENDCLASS.

CLASS lsc_ZCDS_PR_Buyer_Assign IMPLEMENTATION.


  METHOD save_modified.

    DATA ls_PR_BUYER_BO TYPE zmm_PR_BUYER_BO.
    DATA lt_PR_BUYER_BO TYPE TABLE OF zmm_PR_BUYER_BO.

    DATA(trigger_wf) = abap_true.

    IF create IS NOT INITIAL.
      "Populate the values
      lt_PR_BUYER_BO = CORRESPONDING #( create-zcds_pr_buyer_assign ).
      READ TABLE lt_PR_BUYER_BO INTO ls_PR_BUYER_BO INDEX 1.


      GET TIME STAMP FIELD ls_PR_BUYER_BO-crea_date_time.
      ls_PR_BUYER_BO-crea_uname = sy-uname.

      GET TIME STAMP FIELD ls_PR_BUYER_BO-lchg_date_time.
      ls_PR_BUYER_BO-lchg_uname = sy-uname.

      MODIFY zmm_pr_buyer_bo FROM ls_PR_BUYER_BO.

      UPDATE eban
            SET buyer = ls_PR_BUYER_BO-buyer
                comments = ls_PR_BUYER_BO-comments
            WHERE banfn = ls_PR_BUYER_BO-purchaserequisition AND
              bnfpo = '00010'.


    ELSEIF update IS NOT INITIAL.

      lt_PR_BUYER_BO = CORRESPONDING #( update-zcds_pr_buyer_assign ).
      READ TABLE lt_PR_BUYER_BO INTO ls_PR_BUYER_BO INDEX 1.


      GET TIME STAMP FIELD ls_PR_BUYER_BO-lchg_date_time.
      ls_PR_BUYER_BO-lchg_uname = sy-uname.

      MODIFY zmm_pr_buyer_bo FROM ls_PR_BUYER_BO.


      IF ls_PR_BUYER_BO-buyer IS NOT INITIAL.
        UPDATE eban
                    SET buyer = ls_PR_BUYER_BO-buyer
                        comments = ls_PR_BUYER_BO-comments
                    WHERE banfn = ls_PR_BUYER_BO-purchaserequisition AND
                      bnfpo = '00010'.
      ELSE.
        UPDATE eban
              SET comments = ls_PR_BUYER_BO-comments
              WHERE banfn = ls_PR_BUYER_BO-purchaserequisition AND
                bnfpo = '00010'.
      ENDIF.

    ELSEIF delete IS NOT INITIAL.
      trigger_wf = abap_false.
      lt_PR_BUYER_BO = CORRESPONDING #( delete-zcds_pr_buyer_assign ).

      READ TABLE lt_PR_BUYER_BO INTO ls_PR_BUYER_BO INDEX 1.
      GET TIME STAMP FIELD ls_PR_BUYER_BO-lchg_date_time.
      ls_PR_BUYER_BO-lchg_uname = sy-uname.

      MODIFY zmm_pr_buyer_bo FROM ls_PR_BUYER_BO.

      UPDATE eban
          SET buyer = ''
              comments = ''
          WHERE banfn = ls_PR_BUYER_BO-purchaserequisition AND
            bnfpo = '00010'.

    ENDIF.


    IF trigger_wf = abap_true.
      IF ls_PR_BUYER_BO IS INITIAL.


      ENDIF.

      CALL FUNCTION 'ZMM_WF_PR_ASSIGN_NOT' IN BACKGROUND TASK
        EXPORTING
          i_pr_buyer = ls_PR_BUYER_BO.
    ENDIF.

  ENDMETHOD.



ENDCLASS.

 

 

 

 

 

6.Create FM zmm_wf_pr_assign_not

 

 

 

 

 

FUNCTION zmm_wf_pr_assign_not
  IMPORTING
    VALUE(i_pr_buyer) TYPE zmm_pr_buyer_bo.

*  Data Declaration for Class
  DATA lr_wf_pgr TYPE REF TO zmm_wf_pr_assign_notification.
  DATA ls_pr_buyer TYPE zmm_pr_buyer_bo.

  CREATE OBJECT lr_wf_pgr.

  MOVE-CORRESPONDING i_pr_buyer TO ls_pr_buyer.
*   Trigger Workflow

  CONCATENATE 'US' ls_pr_buyer-buyer INTO ls_pr_buyer-buyer.

  lr_wf_pgr->register_buyer( EXPORTING i_pr_buyer = ls_pr_buyer ).

ENDFUNCTION.

 

 

 

 

 

Table zmm_pr_buyer_bo:

 

AbdelrahmanZaki_0-1720941239948.png

 

AbdelrahmanZaki_0-1720941343822.png

 

3. Create Workflow: (Class based workflow)

1. Workflow template

AbdelrahmanZaki_1-1720941370881.pngAbdelrahmanZaki_2-1720941384081.pngAbdelrahmanZaki_3-1720941400977.pngAbdelrahmanZaki_4-1720941417448.png

 

2. Workflow Class

 

 

 

class ZMM_WF_PR_ASSIGN_NOTIFICATION definition
  public
  final
  create public .

public section.

  interfaces BI_OBJECT .
  interfaces BI_PERSISTENT .
  interfaces IF_WORKFLOW .

  events REGISTER
    exporting
      value(I_PR_BUYER) type ZMM_PR_BUYER_BO .

  methods REGISTER_BUYER
    importing
      !I_PR_BUYER type ZMM_PR_BUYER_BO .
  methods NOTIFICATION
    importing
      !I_PR_BUYER type ZMM_PR_BUYER_BO .
protected section.
private section.
ENDCLASS.



CLASS ZMM_WF_PR_ASSIGN_NOTIFICATION IMPLEMENTATION.


  method NOTIFICATION.
  endmethod.


  METHOD REGISTER_BUYER.



* Data Declarations
    DATA: lv_objtype          TYPE sibftypeid,
          lv_event            TYPE sibfevent,
          lv_objkey           TYPE sibfinstid,
          lr_event_parameters TYPE REF TO if_swf_ifs_parameter_container.
*          lv_param_name       TYPE swfdname,
**          lv_id               TYPE char10.
*          lv_id               TYPE zmm_pgr_not_log.


* Setting values of Event Name
    lv_objtype = 'ZMM_WF_PR_ASSIGN_NOTIFICATION'. " Your Class Name
    lv_event   = 'REGISTER'.  " Event Name.

* Instantiate an empty event container
    CALL METHOD cl_swf_evt_event=>get_event_container
      EXPORTING
        im_objcateg  = cl_swf_evt_event=>mc_objcateg_cl
        im_objtype   = lv_objtype
        im_event     = lv_event
      RECEIVING
        re_reference = lr_event_parameters.

** Set up the name/value pair to be added to the container
*    lv_param_name  = 'I_PGR_LOG'.  " parameter name of the event
*    lv_id          = i_pgr_log.

* Add the name/value pair to the event conainer
    TRY.
        CALL METHOD lr_event_parameters->set
          EXPORTING
            name  = 'I_PR_BUYER'
            value = I_PR_BUYER.

      CATCH cx_swf_cnt_cont_access_denied .
      CATCH cx_swf_cnt_elem_access_denied .
      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_elem_def_invalid .
      CATCH cx_swf_cnt_container .
    ENDTRY.

* Raise the event passing the prepared event container
    TRY.
        CALL METHOD cl_swf_evt_event=>raise
          EXPORTING
            im_objcateg        = cl_swf_evt_event=>mc_objcateg_cl
            im_objtype         = lv_objtype
            im_event           = lv_event
            im_objkey          = lv_objkey
            im_event_container = lr_event_parameters.
      CATCH cx_swf_evt_invalid_objtype .
      CATCH cx_swf_evt_invalid_event .
    ENDTRY.

    COMMIT WORK.

  ENDMETHOD.
ENDCLASS.

 

 

 

 

Action the Complete button of this specific task in 

AbdelrahmanZaki_5-1720937288302.png

AbdelrahmanZaki_4-1720937262313.png

Create Enhancement implementation for badi /IWWRK/ES_WF_WI_BEFORE_UPD_IB

make sure to map filter values correctly as below

AbdelrahmanZaki_6-1720937399206.png

AbdelrahmanZaki_0-1720942366029.png

 

 

 

 

class ZCL_MM_WF_PGR_NOT definition
  public
  final
  create public .

public section.

  interfaces /IWWRK/IF_WF_WI_BEFORE_UPD_IB .
  interfaces IF_BADI_INTERFACE .
protected section.
private section.
ENDCLASS.



CLASS ZCL_MM_WF_PGR_NOT IMPLEMENTATION.


  method /IWWRK/IF_WF_WI_BEFORE_UPD_IB~BEFORE_UPDATE.


* Local Data Declaration
    DATA: lv_subrc  TYPE sy-subrc,
          lv_status TYPE sww_wistat.

    CLEAR: lv_subrc,
           lv_status.
    IF iv_decision_key EQ '0001'.
* Status: Ready to Committed Status
      CALL FUNCTION 'SAP_WAPI_WORKITEM_COMPLETE'
        EXPORTING
          workitem_id = is_wi_details-wi_id
        IMPORTING
          return_code = lv_subrc
          new_status  = lv_status.
      IF lv_subrc EQ 0
        AND lv_status NE 'COMPLETED'.
        CLEAR: lv_status.
* Status: Committed to Completed Status
        CALL FUNCTION 'SAP_WAPI_WORKITEM_COMPLETE'
          EXPORTING
            workitem_id = is_wi_details-wi_id
          IMPORTING
            return_code = lv_subrc
            new_status  = lv_status.
      ENDIF.
    ENDIF.
  endmethod.
ENDCLASS.

 

 

 

4.Publish app to Fiori Launchpad

I went with the minimum option (without SAP Business Application Studio) as follows:

published the cds view in SEGW project and created a project from template (List Report) in webide then deploy it to server under name zmm_pr_assign

AbdelrahmanZaki_4-1720940223496.png

AbdelrahmanZaki_2-1720939795896.png

 

 

Target mapping

AbdelrahmanZaki_3-1720940086280.png

I'm sure you will manage to create tile, catalog, group, and pfcg role. 🙂

 

5.Output:

AbdelrahmanZaki_8-1720937777702.png

AbdelrahmanZaki_5-1720942130979.pngAbdelrahmanZaki_6-1720942160666.png

Once saved here you find wf item in my inbox with binded details of PR.. with the complete button visible

AbdelrahmanZaki_12-1720938047471.png

 

I've included all the important details in sequence, but there may still be some missing information.

Please feel free to ask about any additional details you'd like me to include.


Regards,

Abdelrahman Zaki

 

5 Comments
Labels in this area