Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
laszlo_kajan2
Active Participant

This blog will guide you through all the steps to create a SAPUI5 Fiori-like app using the SAP Web IDE.

The example app is for recording results for quality management. It could be used by the quality inspector to record results using a tablet, walking down the line.

The presented app is not a reference. Its purpose is to demonstrate key solutions involved in providing the required functionality.

This blog was made possible by itelligence Sp. z o.o. Thanks to Artur Wojciechowski and Piotr Pudelski for supporting the creation of this blog.

Overview

App specification

  • In our case, quality management results are to be recorded per inspection characteristic. Inspection characteristics are grouped into inspection operations, which in turn are grouped into inspection lots.
  • Inspection results are usually recorded in sequence, recording all characteristics of an operation at a time.
  • Inspection characteristics can have three states: 'unset', 'reject', 'accept'.
  • Once an inspection characteristic result is recorded, it is to be locked against further changes.
  • Inspection lots are identified by order number (ORDER_NO). Also display the material short text (TXT_MAT).
  • Inspection operations are identified by short text. Only operations in range >= 100 and <= 499 are to be processed by the app.

Tool set

  • SAP Web IDE
  • git
  • SEGW - SAP Gateway Service Builder
  • BAPI (RFC) functions for Quality Management results
    • BAPI_INSPLOT_GETLIST, BAPI_INSPLOT_GETDETAIL, BAPI_INSPOPER_GETLIST, BAPI_INSPOPER_GETDETAIL, BAPI_INSPOPER_RECORDRESULTS

App development

  1. Design considerations
  2. OData service (blog post part 1)
  3. Fiori-like SAPUI5 app (blog post part 2)
    1. Web IDE
    2. git repository
    3. Fiori-like SAPUI5 Display
    4. Fiori-like SAPUI5 Update

Table of contents

Design considerations

Individual quality management results are recorded for inspection characteristics, at the bottom of a three-level hierarchy:

  • Inspection lot 1
    • Inspection operation 1
      • Inspection characteristic 1
      • Inspection characteristic 2
      • ...
    • Inspection operation 2
      • Inspection characteristic 1
      • ...
    • ...
  • Inspection lot 2
    • ...

There is exactly one inspection result recorded for each inspection characteristic.

The above hierarchy fits the master-master-detail Fiori app template. The master list is the inspection lot collection, the master2 list is the inspection operation collection of the parent master inspection lot, and the detail list is the inspection characteristic collection of the parent inspection operation:

  • Master list - inspection lot collection
    • Master2 list - inspection operation collection
      • Detail list - inspection characteristic collection

The OData service has to provide the above three collections.

Creating the OData service

  1. Use SEGW transaction to create a new OData service for the app: "ZTUT_QM_00".
  2. Create three entity types for the three collections identified above: right click 'Data Model', choose 'Import' / 'RFC/BOR Interface'
    1. Entity type name: 'InspLot'
      1. Data Source Attributes: 'Remote Function Call'
      2. Name: 'BAPI_INSPLOT_GETLIST'
      3. Check 'Create Default Entity Set'
      4. Next
      5. Select parameters
        1. Expand INSPLOT_LIST[]
        2. Check: INSPLOT, ORDER_NO, TXT_MAT
        3. Next
      6. Mark 'INSPLOT' as 'Is Key'
      7. Finish
      8. Double click 'Entity Types' / 'InspLot' / 'Properties'
        1. Mark 'OrderNo' as 'Sortable' and 'Filterable'
      9. Note that an 'Entity Set', 'InspLotSet' has been created automatically
        1. Mark it as 'Searchable'
    2. Entity type name: 'InspLotOp'
      1. Proceed as above
      2. BAPI name: 'Z_TUT_QM_00_INSPOPER_GETLIST_0' (to be created below)
        Inspection operations have to be filtered by operation number and short text to allow searching. Since 'BAPI_INSPOPER_GETLIST' does not feature filtering by these fields, the wrapper function module 'Z_TUT_QM_00_INSPOPER_GETLIST_0' is created.
        1. Create new function module 'Z_TUT_QM_00_INSPOPER_GETLIST_0' in new function group 'ZTUT_QM_00'
        2. Set attribute 'Remote-Enabled Module'
        3. Copy import parameter 'INSPLOT' from 'BAPI_INSPOPER_GETLIST'
        4. Add new import parameter 'R_INSPOPER' with type 'range table type' of data element 'QIBPVORNR'
          1. Create new 'range table type' as needed
          2. Mark import parameter as 'Optional' and 'Pass Value'
        5. Add new import parameter 'TXT_OPER' type 'BAPI2045L2-TXT_OPER', 'Optional' and 'Pass Value'
        6. Copy all export parameters from 'BAPI_INSPOPER_GETLIST'
        7. Copy all tables from 'BAPI_INSPOPER_GETLIST'
        8. lmplement 'Z_TUT_QM_00_INSPOPER_GETLIST_0' as follows:
            CALL FUNCTION 'BAPI_INSPOPER_GETLIST'
              EXPORTING
                insplot              = insplot
              IMPORTING
                return               = return
                return2              = return2
              TABLES
                inspoper_list        = inspoper_list
                handheld_worklist    = handheld_worklist.

            " INSPOPER table with selection parameters sign option high low for inspoper e.g. I BT  0499  0100
            IF r_inspoper IS NOT INITIAL.
              DELETE inspoper_list WHERE not inspoper IN r_inspoper.
            ENDIF.

            " TXT_OPER e.g. = '*##2*'
            IF txt_oper IS NOT INITIAL.
              DELETE inspoper_list WHERE NOT ( txt_oper CP txt_oper ).
            ENDIF.
        9. Return to transaction SEGW
      3. Parameters: 'INSPOPER_LIST[]' / 'INSPLOT', 'INSPOPER', 'TXT_OPER'
      4. Keys: 'INSPLOT', 'INSPOPER' (all fields that make up the primary key must be marked).
      5. Mark 'Insplot', 'Inspoper' and 'TxtOper' as filterable
      6. Mark entity set 'InspLotOpSet' as 'Searchable' and 'Requires Filter'
    3. Entity type name: 'InspLotOpChar'
      1. Proceed as above
      2. BAPI name: 'Z_TUT_QM_00_INSPOPER_GETDETA0' (to be created below)
        'BAPI_INSPOPER_GETDETAIL' can not be used to retrieve properties of exactly one characteristic. The function module returns characteristic requirements and characteristic results in separate tables ('CHAR_REQUIREMENTS' and 'CHAR_RESULTS'). This is a problem for the service implementation, because entity properties must come from one table of the function module.
        In order to provide a filter for inspection characteristic and combine 'CHAR_REQUIREMENTS' and 'CHAR_RESULTS', the wrapper function module 'Z_TUT_QM_00_INSPOPER_GETDETA0' is created.
        1. Create new function module 'Z_TUT_QM_00_INSPOPER_GETDETA0' in function group 'ZTUT_QM_00'
        2. Set attribute 'Remote-Enabled Module'
        3. Copy import parameters 'INSPLOT' and 'INSPOPER' from 'BAPI_INSPOPER_GETDETAIL'
        4. Create new import parameter 'INSPCHAR' type 'BAPI2045D4-INSPCHAR', 'Optional', 'Pass Value'
        5. Copy export parameter 'RETURN' from 'BAPI_INSPOPER_GETDETAIL'
        6. Create new table parameter 'CHARACTERISTICS' like 'ZTUT_QM_00_CHAR' (to be created below)
          1. Create structure 'ZTUT_QM_00_CHAR' for inspection characteristic requirements and results using .INCLUDE:
        7. lmplement 'Z_TUT_QM_00_INSPOPER_GETLIST_0' as follows:
            DATA:
              big_return            TYPE bapiret2,
              big_char_requirements TYPE STANDARD TABLE OF bapi2045d1
                WITH UNIQUE SORTED KEY inspchar COMPONENTS inspchar,
              big_char_results      TYPE STANDARD TABLE OF bapi2045d2
                WITH UNIQUE HASHED KEY uh COMPONENTS inspchar.

            DATA:
              wa_characteristics LIKE LINE OF characteristics,
              cond               TYPE string.

            FIELD-SYMBOLS:
               LIKE LINE OF big_char_requirements,
               LIKE LINE OF big_char_results.

            CLEAR characteristics.

            CALL FUNCTION 'BAPI_INSPOPER_GETDETAIL'
              EXPORTING
                insplot                = insplot
                inspoper               = inspoper
                read_char_requirements = 'X'
                read_char_results      = 'X'
              IMPORTING
                return                 = big_return
              TABLES
                char_requirements      = big_char_requirements
                char_results           = big_char_results.

            return = big_return.

            IF big_return IS INITIAL.
              " Combine CHAR_REQUIREMENTS and CHAR_RESULTS tables into CHARACTERISTICS table
              SORT big_char_requirements BY inspchar.

              IF inspchar IS NOT INITIAL.
                cond = |inspchar = { inspchar }|.
              ENDIF.

              LOOP AT big_char_requirements ASSIGNING  WHERE (cond).
                READ TABLE big_char_results ASSIGNING         WITH TABLE KEY uh COMPONENTS inspchar = -inspchar.
                IF sy-subrc  TO wa_characteristics.
                  MOVE-CORRESPONDING  TO wa_characteristics-ch.
                  APPEND wa_characteristics TO characteristics.
                ELSE.
                  return-type = 'E'.
                  return-message = |Inspection characteristic { -inspchar } not found.|.
                ENDIF.
              ENDLOOP.
            ENDIF.
        8. Return to transaction SEGW
      3. Parameters: 'INSPLOT', 'INSPOPER', 'INSPCHAR', 'CHAR_DESCR', 'SEL_SET1', 'CLOSED_CH', 'EVALUATED_CH', 'EVALUATION_CH', 'ERR_CLASS_CH', 'VALID_VALS_CH', 'NONCONF_CH', 'CODE1_CH', 'CODE_GRP1_CH'
      4. Keys: 'INSPLOT', 'INSPOPER', 'INSPCHAR'
      5. Mark 'Insplot', 'Inspoper' and 'Inspchar' as filterable
      6. Mark 'ClosedCh', 'EvaluatedCh', 'EvaluationCh', 'ErrClassCh', 'ValidValsCh', 'NonconfCh', 'Code1Ch' and 'CodeGrp1Ch' as 'Updatable'
      7. Mark entity set 'InspLotOpCharSet' as 'Updatable' and 'Requires Filter'
  3. Create associations between the entity types in order to facilitate navigation between master, master2 and detail
    1. Association name 'InspLot_InspLotOp'
      1. Right click 'Associations', choose 'Create'


      2. Note the new 'Navigation Properties' in entity types 'InspLot' and 'InspLotOp'.
      3. Change the 'ABAP Field Name' of navigation property 'InspLot' from 'INSPLOT' to 'INSPLOT_NP' in order to avoid collision with (regular) property 'Insplot'
    2. Association name 'InspLotOp_InspLotOpChar'
      1. Proceed as above


      2. Note how this time 'Create related Navigation Property' is not checked on the 'Create Association' screen
  4. Provide implementation for the OData service
    1. Service Entity Set 'InspLotSet'
      1. Operation 'GetEntitySet (Query)'
        1. Right click 'GetEntitySet (Query)', choose 'Map to Data Source'
        2. Type 'Remote Function Call', name 'BAPI_INSPLOT_GETLIST'
        3. Click 'Propose Mapping'
        4. Under 'OrderNo', add a new row for input parameter 'ORDER' (you can drag and drop 'ORDER' from the 'Data Source Parameter' list):
        5. 'BAPI_INSPLOT_GETLIST' does not implement sorting by order number 'OrderNo'. Reimplement the operation to add sorting:
          1. Generate runtime objects (Ctrl+F3)
          2. Right click 'GetEntitySet (Query)', choose 'Go to ABAP Workbench'
          3. Right click 'Methods' / 'Inherited Methods' / 'INSPLOTSET_GET_ENTITYSET', choose 'Redefine'
          4. Implement sorting as follows:
                TRY.
                    CALL METHOD super->insplotset_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.

                    " Implement sorting
                    DATA: lt_orderby TYPE /iwbep/t_mgw_tech_order.
                    DATA: stab    TYPE abap_sortorder_tab,
                          wa_stab LIKE LINE OF stab.
                    FIELD-SYMBOLS:  LIKE LINE OF lt_orderby.

                    lt_orderby = io_tech_request_context->get_orderby( ).
                    LOOP AT lt_orderby ASSIGNING .
                      CLEAR wa_stab.
                      wa_stab-name = -property.
                      IF -order EQ 'desc'. wa_stab-descending = 'X'. ENDIF.
                      wa_stab-astext = space.
                      APPEND wa_stab TO stab.
                    ENDLOOP.
                    SORT et_entityset BY (stab).
                ENDTRY.
          5. Return to transaction SEGW
      2. Operation 'GetEntity (Read)'
        1. Proceed as above
        2. RFC name 'BAPI_INSPLOT_GETDETAIL'
        3. Map all key properties to RFC input parameters: 'Insplot' to 'NUMBER'
        4. Map 'OrderNo' to 'GENERAL_DATA\ORDERID', 'TxtMat' to 'GENERAL_DATA\TXT_INSP_OBJECT'
    2. Service Entity Set 'InspLotOpSet'
      1. Operation 'GetEntitySet (Query)'
        1. Proceed as above
        2. RFC name 'Z_TUT_QM_00_INSPOPER_GETLIST_0'
        3. Click 'Propose Mapping'
        4. Add input range for data source parameter 'R_INSPOPER[]' under 'Inspoper':
          1. Accept range semantics as proposed

      2. Operation 'GetEntity (Read)'
        1. Proceed as above
        2. RFC name 'BAPI_INSPOPER_GETDETAIL'
        3. Click 'Propose Mapping'
        4. Add input parameter 'Inspoper' for data source parameter 'INSPOPER'
    3. Service Entity Set 'InspLotOpCharSet'
      1. Operation 'GetEntitySet (Query)'
        1. Proceed as above
        2. RFC name 'Z_TUT_QM_00_INSPOPER_GETDETA0'
        3. Click 'Propose Mapping'
      2. Operation 'GetEntity (Read)'
        1. Proceed as above
        2. RFC name 'Z_TUT_QM_00_INSPOPER_GETDETA0'
        3. Click 'Propose Mapping'
      3. Operation 'Update'
        1. Proceed as above
        2. RFC name 'BAPI_INSPOPER_RECORDRESULTS'
        3. Map properties to parameters as shown below:
        4. Generate runtime objects (Ctrl+F3)
  5. Register the OData service
    1. Right click 'Service Maintenance' / 'GATEWAYLOCAL', choose 'Register', 'yes'. System alias is 'LOCAL' in case of an embedded gateway deployment.
    2. Accept everything on screen, 'Continue'. Service now should be registered:
  6. Test the OData service
    1. Click 'SAP Gateway Client' button
    2. Accept 'Request URI' '/sap/opu/odata/SAP/ZTUT_QM_00_SRV/?$format=xml', execute query
    3. Test that the following queries are successful, appending the given path to '/sap/opu/odata/SAP/ZTUT_QM_00_SRV':
      1. /InspLotSet
      2. /InspLotSet?$orderby=OrderNo
      3. /InspLotSet?$filter=substringof ( '21' , OrderNo ) // replace '21' with a sub-string gives a match
      4. Copy 'href' of link titled 'InspLotOpSet' and execute the query, e.g.
        /InspLotSet('030000000051')/InspLotOpSet
      5. Copy 'href' of link titled 'InspLot' and execute the query, e.g.
        /InspLotOpSet(Insplot='030000000051',Inspoper='0150')/InspLot
      6. Replace /InspLot with ?$expand=InspLot, e.g.
        /InspLotOpSet(Insplot='030000000051',Inspoper='0150')?$expand=InspLot
      7. Return to result of point 4
      8. Copy 'href' of link titled 'InspLotOpCharSet', e.g.
        /InspLotOpSet(Insplot='030000000051',Inspoper='0100')/InspLotOpCharSet
      9. Copy 'href' of link titled 'InspLotOpChar' and execute the query, e.g.
        InspLotOpCharSet(Insplot='030000000051',Inspoper='0100',Inspchar='0010')
      10. Test result update
        1. Click button 'Use as Request', choose HTTP method MERGE
        2. Remove all elements from <m:properties> except '<d:Insplot>', '<d:Inspoper>', '<d:Inspchar>' and '<d:ValidValsCh>'. Set '<d:ValidValsCh>' to a new value.
        3. Execute (F8)
        4. Return to the previous (GET) request. Execute (F8) and check that '<d:ValidValsCh>' is set to the new value.
  7. The OData service is now ready to use

Further reading

Creating the Fiori-like SAPUI5 app (blog post part 2)

Part 2 of this blog covers the steps to create the Fiori-like SAPUI5 quality management app from scratch.

Afterword to part 1 of this blog post

Thank you for reading part 1 of this blog post. I hope you found it useful.

4 Comments