Extending SAP Fiori app based on SAP Gateway Service

One of the most common type of SAP standard Fiori app is based on SAP Gateway Service. This type of application uses front-end UI5 application and it consumes the data from service created win SAP Gateway in the backend. To extend such SAP standard Fiori is app, most cases require custom effort must implemented at gateway service in the backend.

The Setup

This blog will use Manage Customer Line Item(F0711) app as an example and go through step-by-step how to extend standard SAP gateway service and add custom field into Fiori app. As a sample scenario, we will add Consolidation Unit as this custom field.

Disclaimer

This solution works for Manage Customer Line Item(F0711) and Manage Supplier Line Item(F0712) however does not mean works for all Fiori app based on SAP Gateway Service. For instance, Balance Sheet/Income Statement(F0708) is also Gateway Service based app but extending the backend service alone will not bring the custom fields to the Fiori app. For this app, front-end UI5 code must be manually adjusted as well to add the custom fields. So it is all based on how the Fiori app is built by SAP. Luckily for Manage Customer Line Item(F0711) and Manage Supplier Line Item(F0712), no front-end code adjustment is required to bring custom fields to the Fiori app.

1. Identity OData service

You can identify the underlying service for Manage Customer Line Item(F0711) from Fiori app library

Go to transaction code SEGW and click on open a new project button. Search for project ‘FAR_CUSTOMER_LINE_ITEMS’ and open it.

Just a quick recap of how gateway service works. In Entity types folder, you define the data structure that you want to fetch from database and return it to OData service consumer. In Entity Sets folder is where the Entity Set for OData service is defined. Each Entity Set represents and return meaningful set of data. Each Entity Set can also define what operation(CRUD) can be performed from OData consumer. Behind each operation and entity set is a different ABAP class method that is processed.

If this is your first time using SEGW, I suggest reading below blogs first to get hand-on understanding of how the OData is built in SEGW.

Creation of Odata services for beginners | SAP Blogs

A Step by Step process to create Odata services in SAP / SAP HANA system | SAP Blogs

2. Identity Entity Set

As mentioned above, OData service is consumed by specifying what Entity Set to user. In our example, OData consumer is Fiori app so we must identity what Entity Set is called before actually extending the OData service.

Go to Fiori app Manage Customer Line Item(F0711) and open developer tool(F12) in your browser. Go to network tab. Now click on the Go button in the app to display the report output. At this point, you see a HTTPS call triggered, which is Fiori app triggering OData service in S4/HANA backend.

Now go to payload tab. You can see that batch process is used, which is to call multiple method in one HTTPS call. In the first GET call, you can identify entity set ‘Items’ is called. This is our entity set that we need to extend with custom fields and logic.

3. Extend Entity Set structure

Go to SEGW and open Data Model -> Entity Sets and you can see the entity set ‘Items’. Double click on it and it shows that the entity types is ‘Item’. Open Data Model -> Entity Types and you can find entity type ‘Item’. Double click on it and it shows that FAR_IFIARLINEITEM_EX is the structure and we must extend this structure by creating Append Structure.

Go to transaction code SE11 and view the structure FAR_IFIARLINEITEM_EX and it contains sub structure FAR_S_ARLINEITEM so in this blog we are going to append custom field ‘ZZ1_CUSTOMFIELD1’ there. Activate the append structure.

4. Create extension project by redefining standard gateway service

Reference blog Extending a service using the Gateway Service Builder | SAP Blogs

Create a new custom project in SEGW which redefines the original standard service. Right click Data model->Redefine->OData service. Enter the service name and version for the standard service FAR_CUSTOMER_LINE_ITEMS. Click Next and choose all the entity types and click Finish.

Select all the entity types to carry over to the new custom gateway project.

After clicking Finish, new project is created. Go to Data Model->Entity Types and you will see that all the entity types are carried over.

Now open Entity types ‘Item’ because we identified that that is the Entity Set that Fiori app is calling. So we must add custom fields in this Entity types in order to show them in Fiori app. We will add ‘ZZ1_CUSTOMFIELD1’ which is also added in structure FAR_S_ARLINEITEM. Make sure to define the same length and the field name must match the one in FAR_S_ARLINEITEM.

Save and activate the project. Make sure to tick the Overwrite Base service. Note that when base service is overwritten by the custom extension project, it does not mean the original project is modified or overwritten in anyway. The original service still exists and project is untouched. What the custom extension project is doing is to tell the originals service URL to redirect to service URL created by the custom extension project. This way, standard Fiori app will still calls the same service URL, but only the logic will be redirected to the custom one.

Now we have extended the data structure that will be returned to Fiori app. In the next step, we must pass actual data to the returning data.

5. Extend Entity Set class method

Go to Runtime Artifacts and double click on Data Provider Extension Class.

Under method, find ITEMSET_GET_ENTITYSET and redefine. Make sure to uncomment the existing code and pass the parameters with the same name. What’s happening is that this class is actually a child class of the standard class CL_FAR_CUSTOMER_LINE_I_DPC_EXT, which is part of the standard project FAR_CUSTOMER_LINE. By calling the method ITEMSET_GET_ENTITYSET of FAR_CUSTOMER_LINE, we don’t have to copy paste all the existing logic from the original project to our custom project. All you have to do is to call the existing logic by calling super->itemset_get_entityset.

The original logic inside method super->itemset_get_entityset will return accounting document data and return to internal table et_entityset. You can see ZZ1_CustomField1 in et_entityset because it uses FAR_S_ARLINEITEM as structure. Implement you logic to pass the data into internal table. Activate the class and methods.

  METHOD itemset_get_entityset.
    TRY.
        CALL METHOD super->itemset_get_entityset
          EXPORTING
            iv_entity_name           = iv_entity_name
            iv_entity_set_name       = iv_entity_set_name
            iv_source_name           = iv_source_name
            it_filter_select_options = it_filter_select_options
            is_paging                = is_paging
            it_key_tab               = it_key_tab
            it_navigation_path       = it_navigation_path
            it_order                 = it_order
            iv_filter_string         = iv_filter_string
            iv_search_string         = iv_search_string
            io_tech_request_context  = io_tech_request_context
          IMPORTING
            et_entityset             = et_entityset
            es_response_context      = es_response_context.
      CATCH /iwbep/cx_mgw_busi_exception.
      CATCH /iwbep/cx_mgw_tech_exception.
    ENDTRY.

    LOOP AT et_entityset ASSIGNING FIELD-SYMBOL(<lw_entityset>).
      <lw_entityset>-zz1_customfield1 = 'Dummy'.
      "Your logic here
    ENDLOOP.
  ENDMETHOD.

Now go to Fiori app Manage Customer Line Item. Go to setting and you will see that Custom field 1 is available as report column. Add it and you can see that value mapped in the previous step is displayed.

Now that we confirmed that the data mapped to the field in our code is reflected to the report output, we will now fetch Consolidation Unit data for each Journal Entry and map to the custom field. Implement below code in method ‘itemset_get_entityset’.

  METHOD itemset_get_entityset.
    TRY.
        CALL METHOD super->itemset_get_entityset
          EXPORTING
            iv_entity_name           = iv_entity_name
            iv_entity_set_name       = iv_entity_set_name
            iv_source_name           = iv_source_name
            it_filter_select_options = it_filter_select_options
            is_paging                = is_paging
            it_key_tab               = it_key_tab
            it_navigation_path       = it_navigation_path
            it_order                 = it_order
            iv_filter_string         = iv_filter_string
            iv_search_string         = iv_search_string
            io_tech_request_context  = io_tech_request_context
          IMPORTING
            et_entityset             = et_entityset
            es_response_context      = es_response_context.
      CATCH /iwbep/cx_mgw_busi_exception.
      CATCH /iwbep/cx_mgw_tech_exception.
    ENDTRY.

    DATA: lt_acdoca TYPE STANDARD TABLE OF acdoca.
    lt_acdoca = CORRESPONDING #( et_entityset MAPPING
                                 rbukrs = companycode
                                 awref  = accountingdocument
                                 gjahr  = fiscalyear
                                 awitem = accountingdocumentitem
                                   ).
    SELECT DISTINCT
           acdoca~rldnr,
           acdoca~rbukrs,
           acdoca~gjahr,
           acdoca~awref,
           acdoca~awitem,
           acdoca~rbunit
      FROM @lt_acdoca AS lt_acdoca
     INNER JOIN acdoca
        ON acdoca~rldnr = '0L'
       AND acdoca~rbukrs = lt_acdoca~rbukrs
       AND acdoca~gjahr  = lt_acdoca~gjahr
       AND acdoca~awref  = lt_acdoca~awref
       AND acdoca~awitem  = lt_acdoca~awitem
      INTO TABLE @DATA(lt_acctdoc)
        ##db_feature_mode[itabs_in_from_clause].

    DATA:lv_item(6)  TYPE n.

    LOOP AT et_entityset ASSIGNING FIELD-SYMBOL(<lw_entityset>).
      CLEAR:lv_item.
      "To make item number compatible
      lv_item = <lw_entityset>-accountingdocumentitem.

      READ TABLE lt_acctdoc ASSIGNING FIELD-SYMBOL(<lw_acctdoc>)
        WITH KEY rbukrs = <lw_entityset>-companycode
                 awref = <lw_entityset>-accountingdocument
                 gjahr = <lw_entityset>-fiscalyear
                 awitem = lv_item.

      IF sy-subrc = 0.
        <lw_entityset>-zz1_customfield1 = <lw_acctdoc>-rbunit. "Map Consolidation Unit
      ENDIF.
    ENDLOOP.
  ENDMETHOD.

Save and activate the method. Go to the Fiori app and the result shows consolidation unit for each accounting document item in the custom field.

In my next blog, I will go through how to add search help in filter prompt for our custom field in Fiori app. Extending SAP Gateway Service based standard report – SAP Extensibility 101