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
- SAP HANA Cloud Connector
- HANA Cloud Platform
- SAP Fiori Master Master Detail Application template
- 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
- Design considerations
- OData service (blog post part 1)
- Fiori-like SAPUI5 app (blog post part 2)
- Web IDE
- git repository
- Fiori-like SAPUI5 Display
- 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 operation 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
- Master2 list - inspection operation collection
The OData service has to provide the above three collections.
Creating the OData service
- Use SEGW transaction to create a new OData service for the app: "ZTUT_QM_00".
- Create three entity types for the three collections identified above: right click 'Data Model', choose 'Import' / 'RFC/BOR Interface'
- Entity type name: 'InspLot'
- Data Source Attributes: 'Remote Function Call'
- Name: 'BAPI_INSPLOT_GETLIST'
- Check 'Create Default Entity Set'
- Next
- Select parameters
- Expand INSPLOT_LIST[]
- Check: INSPLOT, ORDER_NO, TXT_MAT
- Next
- Mark 'INSPLOT' as 'Is Key'
- Finish
- Double click 'Entity Types' / 'InspLot' / 'Properties'
- Mark 'OrderNo' as 'Sortable' and 'Filterable'
- Note that an 'Entity Set', 'InspLotSet' has been created automatically
- Mark it as 'Searchable'
- Entity type name: 'InspLotOp'
- Proceed as above
- 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.- Create new function module 'Z_TUT_QM_00_INSPOPER_GETLIST_0' in new function group 'ZTUT_QM_00'
- Set attribute 'Remote-Enabled Module'
- Copy import parameter 'INSPLOT' from 'BAPI_INSPOPER_GETLIST'
- Add new import parameter 'R_INSPOPER' with type 'range table type' of data element 'QIBPVORNR'
- Create new 'range table type' as needed
- Mark import parameter as 'Optional' and 'Pass Value'
- Add new import parameter 'TXT_OPER' type 'BAPI2045L2-TXT_OPER', 'Optional' and 'Pass Value'
- Copy all export parameters from 'BAPI_INSPOPER_GETLIST'
- Copy all tables from 'BAPI_INSPOPER_GETLIST'
- 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.
- Return to transaction SEGW
- Parameters: 'INSPOPER_LIST[]' / 'INSPLOT', 'INSPOPER', 'TXT_OPER'
- Keys: 'INSPLOT', 'INSPOPER' (all fields that make up the primary key must be marked).
- Mark 'Insplot', 'Inspoper' and 'TxtOper' as filterable
- Mark entity set 'InspLotOpSet' as 'Searchable' and 'Requires Filter'
- Entity type name: 'InspLotOpChar'
- Proceed as above
- 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.- Create new function module 'Z_TUT_QM_00_INSPOPER_GETDETA0' in function group 'ZTUT_QM_00'
- Set attribute 'Remote-Enabled Module'
- Copy import parameters 'INSPLOT' and 'INSPOPER' from 'BAPI_INSPOPER_GETDETAIL'
- Create new import parameter 'INSPCHAR' type 'BAPI2045D4-INSPCHAR', 'Optional', 'Pass Value'
- Copy export parameter 'RETURN' from 'BAPI_INSPOPER_GETDETAIL'
- Create new table parameter 'CHARACTERISTICS' like 'ZTUT_QM_00_CHAR' (to be created below)
- 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.
- Return to transaction SEGW
- 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'
- Keys: 'INSPLOT', 'INSPOPER', 'INSPCHAR'
- Mark 'Insplot', 'Inspoper' and 'Inspchar' as filterable
- Mark 'ClosedCh', 'EvaluatedCh', 'EvaluationCh', 'ErrClassCh', 'ValidValsCh', 'NonconfCh', 'Code1Ch' and 'CodeGrp1Ch' as 'Updatable'
- Mark entity set 'InspLotOpCharSet' as 'Updatable' and 'Requires Filter'
- Entity type name: 'InspLot'
- Create associations between the entity types in order to facilitate navigation between master, master2 and detail
- Association name 'InspLot_InspLotOp'
- Association name 'InspLotOp_InspLotOpChar'
- Provide implementation for the OData service
- Service Entity Set 'InspLotSet'
- Operation 'GetEntitySet (Query)'
- Right click 'GetEntitySet (Query)', choose 'Map to Data Source'
- Type 'Remote Function Call', name 'BAPI_INSPLOT_GETLIST'
- Click 'Propose Mapping'
- Under 'OrderNo', add a new row for input parameter 'ORDER' (you can drag and drop 'ORDER' from the 'Data Source Parameter' list):
- 'BAPI_INSPLOT_GETLIST' does not implement sorting by order number 'OrderNo'. Reimplement the operation to add sorting:
- Generate runtime objects (Ctrl+F3)
- Right click 'GetEntitySet (Query)', choose 'Go to ABAP Workbench'
- Right click 'Methods' / 'Inherited Methods' / 'INSPLOTSET_GET_ENTITYSET', choose 'Redefine'
- 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.
- Return to transaction SEGW
- Operation 'GetEntity (Read)'
- Proceed as above
- RFC name 'BAPI_INSPLOT_GETDETAIL'
- Map all key properties to RFC input parameters: 'Insplot' to 'NUMBER'
- Map 'OrderNo' to 'GENERAL_DATA\ORDERID', 'TxtMat' to 'GENERAL_DATA\TXT_INSP_OBJECT'
- Operation 'GetEntitySet (Query)'
- Service Entity Set 'InspLotOpSet'
- Operation 'GetEntitySet (Query)'
- Operation 'GetEntity (Read)'
- Proceed as above
- RFC name 'BAPI_INSPOPER_GETDETAIL'
- Click 'Propose Mapping'
- Add input parameter 'Inspoper' for data source parameter 'INSPOPER'
- Service Entity Set 'InspLotOpCharSet'
- Operation 'GetEntitySet (Query)'
- Proceed as above
- RFC name 'Z_TUT_QM_00_INSPOPER_GETDETA0'
- Click 'Propose Mapping'
- Operation 'GetEntity (Read)'
- Proceed as above
- RFC name 'Z_TUT_QM_00_INSPOPER_GETDETA0'
- Click 'Propose Mapping'
- Operation 'Update'
- Operation 'GetEntitySet (Query)'
- Service Entity Set 'InspLotSet'
- Register the OData service
- Test the OData service
- Click 'SAP Gateway Client' button
- Accept 'Request URI' '/sap/opu/odata/SAP/ZTUT_QM_00_SRV/?$format=xml', execute query
- Test that the following queries are successful, appending the given path to '/sap/opu/odata/SAP/ZTUT_QM_00_SRV':
- /InspLotSet
- /InspLotSet?$orderby=OrderNo
- /InspLotSet?$filter=substringof ( '21' , OrderNo ) // replace '21' with a sub-string gives a match
- Copy 'href' of link titled 'InspLotOpSet' and execute the query, e.g.
/InspLotSet('030000000051')/InspLotOpSet - Copy 'href' of link titled 'InspLot' and execute the query, e.g.
/InspLotOpSet(Insplot='030000000051',Inspoper='0150')/InspLot - Replace /InspLot with ?$expand=InspLot, e.g.
/InspLotOpSet(Insplot='030000000051',Inspoper='0150')?$expand=InspLot - Return to result of point 4
- Copy 'href' of link titled 'InspLotOpCharSet', e.g.
/InspLotOpSet(Insplot='030000000051',Inspoper='0100')/InspLotOpCharSet - Copy 'href' of link titled 'InspLotOpChar' and execute the query, e.g.
InspLotOpCharSet(Insplot='030000000051',Inspoper='0100',Inspchar='0010') - Test result update
- Click button 'Use as Request', choose HTTP method MERGE
- Remove all elements from <m:properties> except '<d:Insplot>', '<d:Inspoper>', '<d:Inspchar>' and '<d:ValidValsCh>'. Set '<d:ValidValsCh>' to a new value.
- Execute (F8)
- Return to the previous (GET) request. Execute (F8) and check that '<d:ValidValsCh>' is set to the new value.
- The OData service is now ready to use
Further reading
- Step-by-step guide to build an OData Service based on RFCs by Volker Drees
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.