Quantcast
Channel: SCN : Blog List - All Communities
Viewing all articles
Browse latest Browse all 2548

Step-By-Step, End-To-End Guide to Building a SAP Fiori-Like SAPUI5 App - Part 1

$
0
0

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: fig 1.png
        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'
        fig 2.png
        fig 3.png
        fig 4.png
      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
        fig 5.png
        fig 6.png
        fig 7.png
      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):
          fig 8.png
        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':
          fig 9.png
          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:
          fig 10.png
        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:
      fig 11.png
  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)
          fig 12.png
        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.


Viewing all articles
Browse latest Browse all 2548

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>