Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[CAP] Fiori Elements – Display managed fields as value help

data-model.cds

1
2
3
4
5
6
7
8
using {
    managed
} from '@sap/cds/common';
 
entity managedEntity: managed {
    key ID    : UUID;
        field : String;
}

annotations.cds

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using myService as service from '../../srv/myService';
 
annotate service.managedEntity with @(
    Capabilities.SearchRestrictions: {Searchable: false},
    UI.PresentationVariant         : {
        SortOrder     : [{
            Property  : createdAt,
            Descending: true
        }],
        Visualizations: ['@UI.LineItem']
    },
    UI.HeaderInfo                  : {
        TypeName      : '{i18n>myEntity}',
        TypeNamePlural: '{i18n>myEntities}',
    },
    UI.SelectionFields             : [
        createdAt,
        createdBy
    ],
    UI.LineItem                    : [
    ]
) {
    createdAt @UI.HiddenFilter : false;
    createdBy @UI.HiddenFilter : false;
};

[CAP] Using a Tree in SAPUI5 Freestyle app

The following Links helped me implementing the tree functionality:

https://sapui5.hana.ondemand.com/#/entity/sap.m.Tree/sample/sap.m.sample.TreeOData

https://answers.sap.com/questions/13192367/sap-cds-how-to-add-hierarchy-annotations-saphierar.html

Define the data model in data-model.cds

1
2
3
4
5
6
7
entity Node {
    key NodeID         : Integer;
        HierarchyLevel : Integer;
        ParentNodeID   : Integer;
        Description    : String;
        drillState     : String;
}

Create testdata in my.test-Node.csv

1
2
3
4
5
6
7
8
NodeID;HierarchyLevel;ParentNodeID;drillState;Description 
1;0;null;"expanded";"1"
2;0;null;"expanded";"2"
3;0;null;"expanded";"3"
4;1;1;"leaf";"1.1"
5;1;1;"expanded";"1.2"
6;2;5;"leaf";"1.2.1"
7;2;5;"leaf";"1.2.2"

and deploy the testdata to your local sql db

1
cds deploy --to sqlite:db/test.db

Service Definition in test-service.cds

1
2
3
4
5
using my.test as db from '../db/data-model';
 
service testService {
     entity Nodes as projection on db.Node;
}

add the Tree controll to your Fiori UI view Tree.view.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<Tree
    id="Tree"
    items="{path: '/Nodes',
            parameters : {
                countMode: 'Inline',
                numberOfExpandedLevels: 3,
                treeAnnotationProperties: {
                                            hierarchyLevelFor : 'HierarchyLevel',
                                            hierarchyNodeFor : 'NodeID',
                                            hierarchyParentNodeFor : 'ParentNodeID',
                                            hierarchyDrillStateFor : 'drillState'
                                            }
            }
    }">
    <StandardTreeItem title="{Description}"/>
</Tree>

The output should be similar to this:

[SAPUI5] Binding with filter on XML View

https://sapui5.hana.ondemand.com/sdk/#/topic/5338bd1f9afb45fb8b2af957c3530e8f.html

There are two ways to use a filter.

Option 1:

1
2
3
4
5
6
7
items="{
                path: '/myItems',
                parameters : {
                  $filter : 'itemName eq \'myItemName\'',
                  $orderby : 'createdAt desc'
                },
}">

Option 2:

01
02
03
04
05
06
07
08
09
10
11
items="{
                path: '/myItems',
                parameters : {
                  $orderby : 'createdAt desc'
                },
                filters : {                                    
                  path : 'itemName ',
                  operator : 'EQ',
                  value1 : 'myItemName'
                },
}">

[OpenUI5] SAP Fiori elements add-on for OpenUI5 using an OData V4 service

Recently I found this blog post about the new SAP Fiori elements add-on for OpenUI5.
https://blogs.sap.com/2020/12/21/now-available-sap-fiori-elements-add-on-for-openui5/
It includes a little exercise to try it out for yourself. I wrote down all steps I had to make on my Linux Mint 20 installation.
These two links also helped me a lot.
https://github.com/sap-samples/cloud-cap-samples
https://cap.cloud.sap/docs/get-started/

Prerequisites (Node.js, Visual Studio Code, SAP Fiori tools, Git)

1
2
3
4
curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version
npm -v

Change npm’s default directory to prevent permission errors.
https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally

1
2
3
4
5
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
mkdir ~/.npm-global/lib
#add the following line to your .bashrc or .profile or .zshrc
export PATH=~/.npm-global/bin:$PATH

Step 1: Provide an OData V4 service

1
2
3
4
5
git clone https://github.com/sap-samples/cloud-cap-samples remote-odata-service
cd remote-odata-service
npm i
npm i -g @sap/cds-dk
cds watch fiori

Step 2: Generate a SAP Fiori elements List Report Object Page (LROP) app with Fiori tools

1. Open VSC, press Ctrl + P and search for > Fiori: Open Application Generator

2. Choose SAP Fiori elements application
In my case there was no default generator, so first I had to install it.

1
npm install -g @sap/generator-fiori-elements@latest

This can also be done directly in VSC.

3. Select List Report Object Page
4. Select Connect to an OData Service as Data source and enter as URL http://localhost:4004/browse
5. Choose Books as the Main entity and texts as Navigation entity
6. Complete the mandatory information module name (e.g. bookshop) and Project folder path for storing your app. Of course, you can also fill in the optional information.

Step 3: Make changes in package.json and ui5.yaml required for using OpenUI5

package.json

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
    "name": "fiorielements_openui5",
    "version": "0.0.1",
    "private": true,
    "sapux": true,
    "description": "A Fiori application.",
    "keywords": [
        "ui5",
        "openui5",
        "sapui5"
    ],
    "main": "webapp/index.html",
    "scripts": {
        "start": "fiori run --open index.html",
        "start-local": "fiori run --config ./ui5-local.yaml --open index.html",
        "build": "ui5 build -a --clean-dest --include-task=generateManifestBundle generateCachebusterInfo",
        "deploy": "fiori add deploy-config"
    },
    "devDependencies": {
        "@sap/ux-specification": "latest",
        "@sap/ux-ui5-tooling": "1",
        "@ui5/cli": "2.5.0",
        "@ui5/fs": "2.0.1",
        "@ui5/logger": "2.0.0"
    },
    "ui5": {
        "dependencies": [
            "@sap/ux-ui5-tooling",
            "@sap/open.fe"
        ]
    },
    "dependencies": {
        "@sap/open.fe": "1.85.0"
    }
}

ui5.yaml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
specVersion: '2.2'
metadata:
  name: 'fiorielements_openui5'
type: application
framework: 
  name: OpenUI5 
  version: "1.85.0" 
  libraries:  
  - name: sap.m 
  - name: sap.ui.core 
  - name: sap.uxap
  - name: themelib_sap_fiori_3
server:
  customMiddleware:
  - name: fiori-tools-proxy
    afterMiddleware: compression
    configuration:
      ignoreCertError: false # If set to true, certificate errors will be ignored. E.g. self-signed certificates will be accepted
      backend:
      - path: /browse
        url: http://localhost:4004
  - name: fiori-tools-appreload
    afterMiddleware: compression
    configuration:
     port: 35729
     path: webapp

Step 4: Run the V4 application

1
2
3
cd ~/projects/fiorielements_openui5
npm i
npm start

Now http://localhost:8080/index.html should be opened in your browser.
“Note: Clicking on the Go button in List Report application might request  user and password. Please enter user alice, no password.”
Finally I got my list items.

[Fiori] Debug deployed Fiori App

When opening the Dev-Tools for a deployed Fiori App, it will look like this:

You won’t see any controller.js to debug.
What to do? Close the Debugger-Tools and hit CTRL+ALT+SHIFT+P to open the Technical Information Dialog

Check the Checkbox (or choose a specific controller) and reload the app.

It reloads with a new URL parameter and if you open the Dev-Tools, you will now see the controller.js.

Other options to debug or at least to collect some information about your app are the UI5 Diagnostics (hit CTRL+ALT+SHIFT+S) and the UI5 Inspector which is a Brower Addon.

[ABAP Env] Create Data Model & OData Service

Recently I worked through the tutorial on creating a travel bookings app in the SAP Cloud Platform ABAP Environment.

Find a good introduction and overview on this topic here: Getting Started with ABAP in the Cloud – Part I
And the travel bookings app tutorial here: Getting Started with ABAP in the Cloud – Part II

These are my notes on the steps needed to create the data model and publish it as oData service.

#LayerNomenclatureDescription
1Database TableZTABLEPlace your raw data first
2Data Definition (Interface View)ZI_Relation between different tables (e.g. currency or text table)
3Projection View (Consumption View)ZC_Configure the UI depending on your scenario.
Use different projection views for different usages of the same interface view and the same physical table.
4Service DefinitionZSD_Expose the projection view (and underlying associations like currency, country…) as service
5Service BindingZSB_How to we want to make the service available? Defines the binding type (OData V2 / OData V4)
Activate it with the “Activate” Button within the editor window.
Select the Entity and hit “Preview…” to see whtat we defined in our projection view.

If you’ve done this, you are able to view the data in a generated Fiori Elements app. But if you also want to create, edit, delete data, you’ll have to add some behavior functionality.

6Behavior Definition on Data DefinitionZI_Created on top of the Data Definition. Will get the same name es the Data Definition.
Implementation Type: Managed
Defines the operations create, delete, edit.
7Behavior Implementation on Definition ViewZBP_I_The code for the behavior… For the travel app tutorial, some logic for a generated unique key and field validation.
The class inherits from cl_abap_behavior_handler.
8Behavior Definition on Projection ViewZC_Created on top of the Projection View. Will get the same name es the Projection View.
Defines the operations create, delete, edit.

[Fiori] Transactions and Reports

SE38:

  • /UI2/START_URL
  • /UI2/START_TCODE
  • /UI2/FLP_ADMIN_UI

SICF:

  • Frontend-Services: /sap/bc/ui5_ui5/sap/
  • Backend-Services: /sap/opu/odata/sap/ und /sap/bc/bsp/sap/

Tcodes:

sicfPflege des HTTP-Service-Baums
(SAP Internet Communication Framework)
segwSAP Gateway Service Builder
/n/iwbep/view_logSAP Gateway Protokoll-Viewer
/n/iwfnd/gw_clientSAP Gateway Client
/n/iwfnd/apps_logSAP Gateway Anwendungsprotokoll-Viewer
/n/iwfnd/error_logSAP Gateway Fehlerprotokoll
/n/iwfnd/maint_serviceServices aktivieren und verwalten
/n/iwfnd/cache_cleanupBereinigung des Gateway-Modellcache (Frontend)
/n/ui2/custCustomizing für UI-Technologien
/n/ui2/flpSAP Fiori Launchpad
/n/ui2/flcSAP Fiori Launchpad – Prüfungen
/n/ui2/fliaFiori Launchpad: Absichtsanalyse
/n/ui2/flpd_custFiori Launchpad: Designer (mandantenüber.)/n/ui2/flpcm_cust (3170196)
/n/ui2/flpd_confFiori Launchpad: Designer (mandantenabh.)/n/ui2/flpcm_conf (3170196)
/n/ui2/flpcm/custFLP-Content-Manager
/n/ui2/flpcm/confFLP-Content-Manager
/n/ui2/semobjSemantisches Objekt definieren – Kunde
/n/ui2/semobj_sapSemantisches Objekt definieren – SAP
/n/ui2/theme_designerUI Theme Designer
swfvisuWorkflow Visualisierungs-Metadaten
swfvmd1Workflow Visualisierungs-Metadaten

[ABAP] Workflow mail step -> Add attachment

Recently I got the demand to enhance the leave request approvel workflow with some mail steps. These mails should also include the attachments, which can be uploaded in the “Leave Request” Fiori App.

To achive this, I used the exit functionality in the mail step.

There you have to provide a class name. The class has to implement the following interface:

1
IF_SWF_IFS_WORKITEM_EXIT

You will get a method you can implement.

This Method has two parameters, the “Event Name” and the “Workitem Context”.

With the event, you are able to control, in which situations your exit should be fired. In my case, I just need my code run when the workitem is created (event “CREATED”). You’ll find all usable events in domain SWW_EVTTYP.

To get and pass back the attachment to the mail step, a few things need to be done.
First, get the curent workitem container and check, if there is already any attachment. If not, read the request id from the leave request. With this request id, you are able to find the attachment you need. I’ve already written a method for that, you’ll find below. Then convert the xstring to a solix table, create the attachment document with function module “SO_DOCUMENT_INSERT_API1” and “SWO_CREATE” and finally pass it to the container.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
METHOD if_swf_ifs_workitem_exit~event_raised.
 
    DATA: lv_container     TYPE REF TO if_swf_ifs_parameter_container,
          lv_attach        TYPE TABLE OF obj_record,
          lv_folder_id     TYPE soodk,
          wa_document_info TYPE sofolenti1,
          lv_data          TYPE sodocchgi1,
          lv_objtype       TYPE swo_objtyp,
          lv_objkey        TYPE swo_typeid,
          lv_return        TYPE swotreturn,
          lv_sofm          TYPE swo_objhnd,
          lv_objject       TYPE obj_record,
          tb_obj           TYPE TABLE OF obj_record,
          it_solix_tab1    TYPE solix_tab,
          req_id           TYPE tim_req_id,
          lv_doc_type      TYPE so_obj_tp.
 
    CHECK im_event_name = 'CREATED'.
 
* Fetch Container
 
    lv_container = im_workitem_context->get_wi_container( ).
 
* Read attachment to confirm that there is no duplication
 
    TRY.
        lv_container->get(
          EXPORTING
            name  = '_ATTACH_OBJECTS'
          IMPORTING
            value = lv_attach ).
 
      CATCH: cx_swf_cnt_elem_not_found,
             cx_swf_cnt_elem_type_conflict,
             cx_swf_cnt_unit_type_conflict,
             cx_swf_cnt_container.
    ENDTRY.
 
    CHECK lv_attach IS INITIAL.
 
    CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET'
      EXPORTING
        owner     = sy-uname
        region    = 'B'
      IMPORTING
        folder_id = lv_folder_id.
 
* Get Request ID
 
    lv_container->get(
      EXPORTING
        name       = 'RequestId'       
      IMPORTING
        value      = req_id ).         
 
* Get XSTRING of attachment
 
    zcl_xxx=>get_req_attachment(
      EXPORTING
        iv_req_id     = req_id               
      IMPORTING
        ev_xstring    = DATA(xstring)
        es_attachment = DATA(ls_attachment) ).
 
    CHECK xstring IS NOT INITIAL.
 
* Get document type
 
    SELECT SINGLE doc_type FROM toadd INTO @lv_doc_type
       WHERE mimetype EQ @ls_attachment-file_type.
    IF sy-subrc NE 0.
      lv_doc_type = 'PDF'. "If doc_type not found, at least try with pdf.
    ENDIF.
 
* Create and set document
 
    it_solix_tab1 = cl_document_bcs=>xstring_to_solix( xstring ).
 
* Creating First attachment
 
    lv_data-obj_name   = ls_attachment-file_name.
    lv_data-obj_descr  = ls_attachment-file_name.
    lv_data-obj_langu  = sy-langu.
    lv_data-sensitivty = 'P'.
*    lv_data-doc_size   = ls_attachment-file_size.
 
    CALL FUNCTION 'SO_DOCUMENT_INSERT_API1'
      EXPORTING
        folder_id                  = lv_folder_id
        document_data              = lv_data
        document_type              = lv_doc_type
      IMPORTING
        document_info              = wa_document_info
      TABLES
        contents_hex               = it_solix_tab1
      EXCEPTIONS
        folder_not_exist           = 1
        document_type_not_exist    = 2
        operation_no_authorization = 3
        parameter_error            = 4
        x_error                    = 5
        enqueue_error              = 6
        OTHERS                     = 7.
 
* Populate object type and object key for create an instance
 
    lv_objtype = 'SOFM'.
    lv_objkey  = wa_document_info-doc_id.
 
    CALL FUNCTION 'SWO_CREATE'
      EXPORTING
        objtype           = lv_objtype
        objkey            = lv_objkey
      IMPORTING
        object            = lv_sofm
        return            = lv_return
      EXCEPTIONS
        no_remote_objects = 1
        OTHERS            = 2.
 
* Prepare for attaching the object to container
 
    lv_objject-header  = 'OBJH'.
    lv_objject-type    = 'SWO'.
    lv_objject-handle  = lv_sofm.
    APPEND lv_objject TO tb_obj.
 
*—can be used for other workitems
 
    lv_container->set(
      EXPORTING
        name  = '_ATTACH_OBJECTS'
        value = tb_obj[] ).
 
*–this will add the attachment to email
 
    lv_container->set(
      EXPORTING
        name  = 'ATTACHMENTS'
        value = tb_obj[] ).
 
* Commit the changes
 
    im_workitem_context->do_commit_work( ).
 
  ENDMETHOD.

The following function modules are needed to read the leave request attachment:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  METHOD get_req_attachment.
 
    DATA: lv_has_errors     TYPE  ptreq_has_error_flag,
          lt_messages       TYPE  ptarq_uia_messages_tab,
          lt_attachments    TYPE  hress_t_ptarq_att_info,
          ex_has_attachment TYPE  boole_d.
 
    CALL FUNCTION 'PT_ARQ_ATTACHMENT_GET'
      EXPORTING
        im_request_id     = iv_req_id
*       IM_VERSION_NO     =
*       IM_DOCUMENT_TYPE  =
      IMPORTING
        ex_has_errors     = lv_has_errors
        ex_messages       = lt_messages
        et_attachments    = lt_attachments
        ex_has_attachment = ex_has_attachment.
 
    CHECK ex_has_attachment EQ abap_true.
 
    TRY.
        es_attachment = lt_attachments[ 1 ].
      CATCH cx_sy_itab_line_not_found.
    ENDTRY.
 
 
    CALL FUNCTION 'PT_ARQ_ATTACHMENT_DETAIL_GET'
      EXPORTING
        iv_arc_doc_id   = es_attachment-archiv_doc_id
*        iv_doc_type     =
      IMPORTING
        ex_file_content = ev_xstring
        ex_has_errors   = lv_has_errors
        ex_messages     = lt_messages.
 
  ENDMETHOD.