Category: SAP

  • How to Integrate ChatGPT in SAP ABAP

    Introduction

    A general idea of how to integrate ChatGPT with SAP ABAP:

    1. First, you would need to have access to an instance of the ChatGPT model, either through the OpenAI API or by running the model locally.
    2. Next, you would need to create an ABAP program that calls the ChatGPT API and passes it input text, such as a user’s question.
    3. The program would then need to handle the API response and parse the generated text output.
    4. Finally, the program would need to display the generated text in an appropriate format, such as in an SAP GUI screen or in an output file.

    Here’s an example of some code that could be used in an ABAP program to call the OpenAI API and get a response from ChatGPT:

    CALL FUNCTION 'HTTP_POST'
      EXPORTING
        url = 'https://api.openai.com/v1/engines/davinci/completions'
        encoding = 'UTF-8'
      IMPORTING
        response = l_response
      CHANGING
        data = l_data
        headers = l_headers
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state = 2
        http_processing_failed = 3
        OTHERS = 4.
    

     

    How to Integrate ChatGPT in SAP ABAP

    As shown in below image, we will follow three simple steps to integrate ChatGPT APIs within SAP ABAP Report.

    Integrate ChatGPT in SAP ABAP

    1. Get API of Open AI

    We have already discussed all the steps involved regarding API creation in this article.

    2. Create ABAP Report

    Go to SE38, and create a new ABAP Report. Create one Input Parameter as shown below:

    ChatGPT ABAP Report

    3. Integrate ChatGPT Call

    Write the given code in your report:

    REPORT ZCHATGPT.
    
    PARAMETERS: l_ques type string.
    
    data: l_response type string,
          l_data type string,
          lv_payload_x type xstring,
          l_max_tokens type i.
    
    "l_ques = 'What is the meaning of life?'. EXAMPLE
    l_max_tokens = 50.
    l_data = '{' && '"prompt":' && '"' && l_ques && '",' && '"max_tokens":' && l_max_tokens && '}'.
    
    CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
    EXPORTING
    text = l_data
    IMPORTING
    buffer = lv_payload_x.
    
       DATA: lo_http_client TYPE REF TO if_http_client.
        DATA: response TYPE string,
              lv_auth  TYPE string.
        CONSTANTS : lv_url TYPE string VALUE 'https://api.openai.com/v1/engines/davinci/completions'.
    
    
          "create HTTP client by url
          CALL METHOD cl_http_client=>create_by_url
            EXPORTING
              url                = lv_url
            IMPORTING
              client             = lo_http_client
            EXCEPTIONS
              argument_not_found = 1
              plugin_not_active  = 2
              internal_error     = 3
              OTHERS             = 4.
    
          IF sy-subrc <> 0.
            "error handling
          ENDIF.
    
          "setting request method
          lo_http_client->request->set_method('POST').
    
          "adding headers
          lo_http_client->request->set_header_field( name = 'Content-Type' value = 'application/x-www-form-urlencoded' ).
          lo_http_client->request->set_header_field( name = 'Accept' value = 'application/json' ).
          lo_http_client->request->set_header_field( name = 'Authorization' value = 'Bearer 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' ).
    
          lo_http_client->request->set_form_field(
      EXPORTING
        name  = 'prompt'                    " Name of form field
        value =   l_ques   ).
    
    
          "lo_http_client->request->set_data( lv_payload_x ).
    
          "Available Security Schemes for productive API Endpoints
          "OAuth 2.0
    
          CALL METHOD lo_http_client->send
            EXCEPTIONS
              http_communication_failure = 1
              http_invalid_state         = 2
              http_processing_failed     = 3
              http_invalid_timeout       = 4
              OTHERS                     = 5.
    
          IF sy-subrc = 0.
            CALL METHOD lo_http_client->receive
              EXCEPTIONS
                http_communication_failure = 1
                http_invalid_state         = 2
                http_processing_failed     = 3
                OTHERS                     = 5.
          ENDIF.
    
          IF sy-subrc <> 0.
            "error handling
            response = lo_http_client->response->get_cdata( ).
            l_response = response.
          ELSE.
            response = lo_http_client->response->get_cdata( ).
            IF response IS NOT INITIAL.
              l_response = response.
            ELSE.
              l_response = 'Call was successful, but got no response'.
            ENDIF.
          ENDIF.
    
    WRITE l_response.

     

    Code Explanation

    Here, I have added variables l_question and l_max_tokens to hold the user’s question and the maximum token value, respectively. I have then added these values to the l_data variable, which is passed as the data parameter in the HTTP_POST call. The response variable l_response will hold the generated text as a result of the API call.

    Here, I have created an object of class if_http_client and added the headers using the add_header_field method. Then i have passed this object as a parameter ‘manager’ in the ‘HTTP_POST’ call.

    It’s important to note that the format of the data passed to the OpenAI API must be in JSON format, so that’s why I have added the prompt and max_tokens in JSON format in the l_data variable.

    Remember to replace <YOUR_API_KEY> with the API key that you have generated using the Open AI platform.

    Output Screen

    Chat GPT integration with SAP ABAP

    Tutorial Video

    You can watch the video below to learn implementation:

    [embedyt] https://www.youtube.com/watch?v=VvEO2MDpdAc[/embedyt]
  • How to Integrate ChatGPT in SAP UI5

    Preface – This post is part of the UI5 Integration Programs series.

    Introduction

    It is not possible to directly integrate ChatGPT using a CDN (Content Delivery Network) as GPT-3 model is not hosted on any public CDN. GPT-3 is a proprietary model owned by OpenAI, and access to it is provided through the OpenAI API, which requires an API key to use.

    You can use the OpenAI API in your JavaScript application by making HTTP requests to the API endpoint and using the API key. The OpenAI API provides a prompt endpoint that allows you to send a prompt to GPT-3 and receive a response.

    Here’s an example of how you might use the fetch API in JavaScript to send a prompt to GPT-3 and log the response:

    const API_KEY = 'YOUR_API_KEY';
    const prompt = 'What is the meaning of life?';
    
    fetch(`https://api.openai.com/v1/engines/davinci/completions`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${API_KEY}`
        },
        body: JSON.stringify({
            prompt,
            max_tokens: 20
        })
    }).then(response => response.json())
        .then(data => {
        console.log(data.choices[0].text);
    });
    

    How to Integrate ChatGPT in SAP UI5

    As shown in below image, we will follow three simple steps to integrate ChatGPT APIs within SAP UI5 App.

    How to Integrate ChatGPT in SAP UI5

    1. Get API of Open AI

    We have already discussed all the steps involved regarding API creation in this article.

    2. Create UI5 Project

    Use Web IDE or SAP BAS and generate a simple UI5 Application using a generator.

    3. Integrate ChatGPT Call

    We have create a very simple view with input box, button and a text area to show output as shown in below view:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Get Answers from ChatGPT">
                        <content>
                            <VBox>
                                <Input id="idInput"/>
                                <Button text="Get Answer" press="onPressGPT"/>
                                <Text id="idText"/>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    And on the press of Button, we have written the given code in controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
    
            },
    
            onPressGPT: function () {
                var that = this;
                const API_KEY = '';
                var prompt = this.byId("idInput").getValue();
                fetch(`https://api.openai.com/v1/engines/davinci/completions`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': `Bearer ${API_KEY}`
                        },
                        body: JSON.stringify({
                            prompt,
                            max_tokens: 2000
                        })
                    }).then(response => response.json())
                    .then(data => {
                        that.byId("idText").setText(data.choices[0].text);
                    });
            }
        });
    });

    Output

    The Output without pressing the button looks like this:

    UI5 ChatGPT output view

  • Call Transaction Method in SAP BDC

    Introduction

    A Call transaction is a very simple report program. Once you execute and come out of the program, there is no log to cross check.

    Syntax:

    CALL TRANSACTION <transaction code> USING <it_bdcdata>
    MODE ‘A/E/N’
    UPDATE ‘A/S/L’
    MESSAGE INTO <it_msg_details>.

    Here, it_bdcdata represents the internal table that has instructions for one time execution of the t-code. This is the same table that we discussed in the section “SAP BDC Technical Details”. So, this internal table at one moment will hold instructions for only one record.

    Here, we have three different options for MODE. The modes determine the control over screen display.

    • A: It means, while execution of the program, all screens will be displayed. It is best suited for testing purpose as it is a foreground testing.
    • N: It means, while execution of the program, no screens will be shown even in case of success or error. This is best suited for production execution as it is a background job.
    • E: It means, the screens with message will be displayed every time there is an error. This is also used for testing purpose, in case SY-SUBRC fails for method N, and you are not able to identify the position of error.

    Here, we have three different options for UPDATE. The update command signifies Create, Update and delete operation over table/database. And, this UPDATE command provided the control over the sequence of database operations. Like, if data will be saved for all external file one by one, or in parallel.

    • A: It means Asynchronous. It means irrespective of the face that first set of data was processed and data was being saved in db, the next round of data process will start and not wait for the completion of first. This also means for large amount of data, the speed of the program will be faster in this mode. But, also there is a very rare chance of getting errors.
    • S: It means Synchronous. It means, every time the command CALL TRANSACTION is executed, until the data is saved in table and a success SY-SUBRC comes, it will not execute the CALL TRANSACTION for the next set of data. It is preferred in Production mode, as it is error free (Although slower).
    • L: It means Local. This is the command which signifies that the update for entire data (whole excel or csv or txt) will be executed at once, in the end, and only after the “COMMIT WORK” statement. The use case for Local Update or Update Function Module is where you either want all data to updated or none. The best use case is updating header and detail, and if detail or header fails, none of these tables will be updated. You can read more about it here.

    Here, it_msg_details saves all the messages that are produced over the screen (success, warning, information or error).

    Call Transaction Method Flow

    As you can see in the above design flow, the excel will be converted into internal table, and then BDC Codes (CALL TRANSACTION) will be called where <it_bdcdata> will be in form of BDCDATA format with various fields such as Program, DYNPRO, etc including field and value holding data of first row of the excel. Once the database process completes, the next data of the excel will be processed and so on.

    Steps to upload data in SAP system using BDC

    To understand the above process, we will show case a simple example where we will:

    1. Create multiple tables for Employee Data that can be created using a report.

    We have created these tables: zBarry_emp (for employee basic information), zBarry_sal (for employee Salary information) and zBarry_add (for employee address details). The fields are as shown below:

    zBarry_emp

    Field Name Field Type
    EMPID (Key) INT4
    FNAME CHAR20
    LNAME CHAR20
    PHONE CHAR20

    zBarry_sal

    Field Name Field Type
    EMPID (Key) INT4
    SALARY CHAR20

    zBarry_add

    Field Name Field Type
    EMPID (Key) INT4
    CITY CHAR20
    PIN CHAR20
    STATE CHAR20
    COUNTRY CHAR20

    2. The report will be able to take many fields as input.

    Now, we will create a report ZBARRYEMP_REPORT to take multiple inputs via screen and save them in the above tables. The code of the same is shown below:

    REPORT ZBARRYEMP_REPORT.
    Data: ls_emp type ZBARRY_EMP,
          ls_sal type zbarry_sal,
          ls_add type zbarry_add,
          lv_MSG type char20.
    
    PARAMETERS: p_empid TYPE int4,
    p_fname type char20,
    p_lname type char20,
    p_phone type char20,
    p_salary type char20,
    p_city type char20,
    p_pin type char20,
    p_state type char20,
    p_con type char20.
    
    " mapping for Employee Info
    ls_emp-empid = p_empid.
    ls_emp-fname = p_fname.
    ls_emp-lname = p_lname.
    ls_emp-phone = p_phone.
    
    
    " mapping for Employee Salary
    ls_sal-empid = p_empid.
    ls_sal-salary = p_salary.
    
    " mapping for Employee Address
    ls_add-empid = p_empid.
    ls_add-city = p_city.
    ls_add-pin = p_pin.
    ls_add-state = p_state.
    ls_add-country = p_con.
    
    " SQL Operations.
    INSERT ZBARRY_EMP FROM ls_emp.
    If Sy-subrc = 0.
    lv_MSG = 'Create is successful'.
    else.
      lv_MSG = 'Create Failed'.
           Endif.
    
     INSERT ZBARRY_sal FROM ls_sal.
    If Sy-subrc = 0.
    lv_MSG = 'Create is successful'.
    else.
      lv_MSG = 'Create Failed'.
           Endif.
    
      INSERT ZBARRY_add FROM ls_add.
    If Sy-subrc = 0.
    lv_MSG = 'Create is successful'.
    else.
      lv_MSG = 'Create Failed'.
           Endif.
    
           if lv_MSG EQ 'Create Failed'.
             MESSAGE lv_MSG TYPE 'E' DISPLAY LIKE 'E'.
               ENDIF.

     

    Output:

    ABAP Report for BDC

    3. Then, we will create a t-code for our report.

    We will create a T-code “ZMYTCODE” using SE93 for our report “ZBARRYEMP_REPORT”.

    Tcode for BDC

    Steps to Record a transaction code using BDC

    4. Thereafter, we will run a BDC recording (using T-Code SHDB) and get BDCDATA from that recorder.

    Step 1. Go to t-code SHDB and click on “New Recording”

    SHDB New Recording

    Step 2: Provide T-Code, any name for recording and set update mode as “Synchronous”.

    Create Recording SHDB

    Step 3: It will open your Report. Now, provide all the data, and press execute.

    BDC Recorder

    Now click, back to see your BDCDATA, for our example it looks like this:

    INDEX PROGRAM DYNPRO DYNBEGIN FNAM FVAL
    1 T ZMYTCODE
    2 ZBARRYEMP_REPORT 1000 X
    3 BDC_CURSOR P_CON
    4 BDC_OKCODE =ONLI
    5 P_EMPID 12
    6 P_FNAME Rudra
    7 P_LNAME Pandey
    8 P_PHONE 99999999
    9 P_SALARY INR 9999999
    10 P_CITY Mughalsarai
    11 P_PIN 232101
    12 P_STATE Uttar Pradesh
    13 P_CON India
    14 ZBARRYEMP_REPORT 1000 X
    15 BDC_OKCODE /EE
    16 BDC_CURSOR P_EMPID

    Now, here you can see that all our entered data is also recorded in the recording.

    Here BDC_OKCODE “=ONLI” is for our “Execute” button, and BDC_OKCODE = “/EE” is showcasing that we pressed back. We will use the code until we press execute.

    You can test your recording by clicking “Process” button:

    Test BDC

    While testing, do change data with a new set. Before exiting, you must save your recording.

    Steps to Create a BDC Program

    5. Now, we will create a program that accepts excel input and convert that excel into an internal table.

    Step 1: Create a new ABAP report “ZBARRYEMP_BDC” using t-code SE38.

    Step 2: Create the following:

    • local structure of type “bdcdata” where we will map our excel data with bdcdata that we recorded earlier
    • local internal table of type “bdcdata” where we will push our local structure that we have created above
    • local structure and internal table of type “bdcmsgcoll” where we will save the message for every call that we make to the recording
    • local internal table and local structure to hold excel data that we will upload

    We have created the following:

    REPORT ZBARRYEMP_BDC.
    " local structure with combined fields of emp table, salary table and address table
    TYPES: BEGIN OF ls_emp,
      empid type INT4,
      fname type char20,
      lname type char20,
      phone type char20,
      salary type char20,
      city type char20,
      pin type char20,
      state type char20,
      country type char20,
      END OF ls_emp.
    
    DATA: ls_bdcdata TYPE bdcdata,
          ls_msg type bdcmsgcoll.
    
    DATA: lt_bdcdata TYPE TABLE OF bdcdata,
          lt_bdcmsg TYPE TABLE OF bdcmsgcoll,
          lt_bankdata TYPE TABLE OF ls_emp.

     

    Step 3: Now, we will import the excel data using Function Module ‘TEXT_CONVERT_XLS_TO_SAP’ and push it to our internal table it_empdata. You can read more about Excel upload in ABAP here.

    " Uploading Excel and converting it into Interna Table
    TYPE-POOLS truxs.
    PARAMETERS p_file TYPE rlgrap-filename.
    
    DATA : t_upload  TYPE STANDARD TABLE OF ls_emp,
           wa_upload TYPE ls_emp,
           it_type   TYPE truxs_t_text_data.
    
    AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
      CALL FUNCTION 'F4_FILENAME'
        EXPORTING
          field_name = 'p_file'
        IMPORTING
          file_name  = p_file.
    
    START-OF-SELECTION.
      CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
        EXPORTING
          i_tab_raw_data       = it_type
          i_filename           = p_file
        TABLES
          i_tab_converted_data = t_upload[]
        EXCEPTIONS
          conversion_failed    = 1
          OTHERS               = 2.
      IF sy-subrc <> 0.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                WITH sy-msgv1 sy-msgv2 .
      ENDIF.
    
    END-OF-SELECTION.

     

    Step 4: Now in a loop we will keep pushing the bdcdata parameters that is

    • PROGRAM, DYNPRO, DYNBEGIN: These will remain constant for one screen (in our case, constant for whole program as we have only one screen). These will be taken from the BDCDATA that we have generated i.e.
    ZBARRYEMP_REPORT 1000 X
    • FNAM, FVAL: These will hold the key and values (In our case, the keys are the parameters that we used for input in our ABAP report “ZBARRYEMP_REPORT” while the values will be taken from excel upload.
    • The first two fields for a screen are always BDC_CURSOR  and BDC_OKCODE.  The value can be retrieved from the generated BDCDATA. In this case, the values are ‘P_CON ‘ and ‘=ONLI’, respectively.

     

    Step 5: Once the values are taken as per BDCDATA structure, we call the “CALL TRANSACTION” statement. These entire statements will be looped until the operation finishes for the entire excel data.

    The syntax for CALL TRANSACTION is:

    CALL TRANSACTION <transaction code> USING <it_bdcdata>
    MODE ‘A/E/N’
    UPDATE ‘A/S/L’
    MESSAGES INTO <it_msg_details>.

     

    For our example, the above value will become:

    CALL TRANSACTION ‘ZMYTCODE’ USING lt_bdcdata
    MODE ‘N’
    UPDATE ‘S
    MESSAGES INTO lt_bdcmsg.

     

    Step 6: Now upload an excel file with the given format. In our example, we have an excel as shown below:

    Excel format BDC

    Note: Do not include the header. The excel should look like this:

    Excel with Data for BDC

    Once you are done with the ABAP Changes, then run the report, upload the excel file and once the ABAP Report executes, check the table to see if all the records are uploaded or not.

    ABAP Code for BDC Program

    REPORT ZBARRYEMP_BDC.
    " local structure with combined fields of emp table, salary table and address table
    TYPES: BEGIN OF ls_emp,
      empid type int2,
      fname type char20,
      lname type char20,
      phone type char20,
      salary type char20,
      city type char20,
      pin type char20,
      state type char20,
      country type char20,
      END OF ls_emp.
    
    DATA: ls_bdcdata TYPE bdcdata,
          ls_msg type bdcmsgcoll.
    
    DATA: lt_bdcdata TYPE TABLE OF bdcdata,
          lt_bdcmsg TYPE TABLE OF bdcmsgcoll,
          lt_empdata TYPE TABLE OF ls_emp.
    
    " Uploading Excel and converting it into Interna Table
    TYPE-POOLS truxs.
    PARAMETERS p_file TYPE rlgrap-filename.
    
    DATA : t_upload  TYPE STANDARD TABLE OF ls_emp,
           wa_upload TYPE ls_emp,
           it_type   TYPE truxs_t_text_data.
    
    AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
      CALL FUNCTION 'F4_FILENAME'
        EXPORTING
          field_name = 'p_file'
        IMPORTING
          file_name  = p_file.
    
    START-OF-SELECTION.
      CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
        EXPORTING
          i_tab_raw_data       = it_type
          i_filename           = p_file
        TABLES
          i_tab_converted_data = t_upload[]
        EXCEPTIONS
          conversion_failed    = 1
          OTHERS               = 2.
      IF sy-subrc <> 0.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                WITH sy-msgv1 sy-msgv2 .
      ENDIF.
    
      " Loop the above table t_upload[] data until all data is uploaded via BDC
      LOOP AT t_upload into wa_upload.
    * Screen 1 - Field 1 is always BDC_CURSOR
    ls_bdcdata-PROGRAM = 'ZBARRYEMP_REPORT'.
    ls_bdcdata-DYNPRO = '1000'.
    ls_bdcdata-DYNBEGIN = 'X'.
    ls_bdcdata-fnam = 'BDC_CURSOR'.
    ls_bdcdata-fval = 'P_CON'.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 2 - Always BDC_OKCODE
    ls_bdcdata-fnam = 'BDC_OKCODE'.
    ls_bdcdata-fval = '=ONLI'.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 3
    ls_bdcdata-fnam = 'P_EMPID'.
    ls_bdcdata-fval = wa_upload-empid.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 4
    ls_bdcdata-fnam = 'P_FNAME'.
    ls_bdcdata-fval = wa_upload-fname.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 5
    ls_bdcdata-fnam = 'P_LNAME'.
    ls_bdcdata-fval = wa_upload-lname.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 6
    ls_bdcdata-fnam = 'P_PHONE'.
    ls_bdcdata-fval = wa_upload-phone.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 7
    ls_bdcdata-fnam = 'P_SALARY'.
    ls_bdcdata-fval = wa_upload-salary.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 8
    ls_bdcdata-fnam = 'P_CITY'.
    ls_bdcdata-fval = wa_upload-city.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 9
    ls_bdcdata-fnam = 'P_PIN'.
    ls_bdcdata-fval = wa_upload-pin.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 10
    ls_bdcdata-fnam = 'P_STATE'.
    ls_bdcdata-fval = '=ONLI'.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    
    * Screen 1 - Field 10
    ls_bdcdata-fnam = 'P_CON'.
    ls_bdcdata-fval = wa_upload-country.
    APPEND ls_bdcdata to lt_bdcdata.
    CLEAR ls_bdcdata.
    ENDLOOP.
    
    "Call BDC Transaction
    CALL TRANSACTION 'ZMYTCODE' USING lt_bdcdata MODE 'A' UPDATE 'S' MESSAGES INTO lt_bdcmsg.
    CLEAR lt_bdcdata.
    
    END-OF-SELECTION.

     

    Output

    BDC Program Output

  • BDC (Batch Data Communication) in SAP ABAP: Complete Guide

    Introduction

    In SAP environment, suppose you need to upload a data from an external source like an excel sheet. You have a program for the upload already in the system. You will therefore, visit the program or transaction, and then simply open the file location, upload the file, check for errors and that’s it.

    Therefore, these will be the steps that you will follow for a file upload. Suppose, you have Ten Thousand files to be uploaded via the same program. Wouldn’t it be a tedious job? SAP knew it, and hence created something called SAP BDC, which records your upload steps and automatically replicate it for next sets or batches of data. In this article, we will learn everything about SAP BDC with simple examples.

    What is BDC – Batch Data Communication in SAP ABAP?

    SAP BDC stands for Batch Data Communication. It was renamed by SAP to Batch Input, about 20 years ago. Still, the famous name i.e. BDC is used to refer it.

    In terms of definition, Batch Input or BDC are the sets of methods provided by SAP to transfer/migrate data from other SAP or Non SAP Systems.

    Why we need BDC?

    We need Batch Input of BDC for the following reasons:

    1. Data conversion or migration from Non SAP systems (e.g. csv, excel, text) to SAP Systems (e.g. SAP Table). It mostly happen for a new development (Master Data Migration) and SAP Upgradation.

    BDC Process Flow

    2. Automate daily tasks of a user. If the daily task of user is to upload data from a 3rd party to SAP System via T-Code.

    SAP BDC Design

    If you are asked to upload a set of data into database, in single table, you would quickly create a report, with file uploader, and use SQL to push that data into required table. But, if you are asked to upload hundred columns of data into tons of tables, based upon various conditions, based upon a T-Code, then it will be a tedious job.

    BDC solves our problem, by cutting our second task. Our part is to just push the excel until the transaction screen, and the rest is taken care.

    In below image, the usual case would be that you will open a t-code, enter required input and click save. In case of BDC, it creates recording of your upload process and give you the code of the recording. Using the provided code, you can create a program to upload excel and pass the data to that BDC recoded code, and the rest is taken care automatically.

    BDC Design

    SAP BDC Technical Details

    Every time you record your screen, a few fields are auto generated (called BDCDATA) as below:

    • Program Name (PROGRAM): The name of program for the transaction
    • Screen Number (DYNPRO): The screen number is auto generated
    • Field Name (s) [FNAM]: The field name for which value was provided. In case of multiple field, it will be repeated
    • Field Value (s) [FVAL]: For all the above fields, the entered value is recorded here
    • OK Code [BDC_OKCODE]: The event that occurred during recording. Either you pressed Enter or Clicked a button, the code for the same will be captured here
    • DYNBEGIN: This indicates that the new screen has started
    • BDC_CURSOR: It saves the current position of the cursor

    A common example based upon above structure is shown below:

    INDEX PROGRAM DYNPRO DYNBEGIN FNAM FVAL
    1 SAPMM07M 400 X
    2 BDC_CURSOR RM07M-LGORT
    3 BDC_OKCODE /00
    4 MKPF-BLDAT 22.12.2022
    5 MKPF-BUDAT 22.12.2022
    6 RM07M-BWARTWA 413
    7 RM07M-WERKS 2010
    8 RM07M-LGORT HRSL
    9 RM07M-WVERS2 X
    10 SAPMM07M 410 X
    11 BDC_CURSOR MSEG-UMLGO
    12 BDC_OKCODE /00
    13 MSEG-MATNR SLBW
    14 MSEG-ERFMG 20
    15 MSEG-ERFME to
    16 MSEG-WERKS 2010
    17 MSEG-LGORT HRSL
    18 MSEG-CHARG A693264
    19 MSEG-UMLGO HRSL

    You do not have to understand the above code, just check the field names discussed before and how they appear in the BDCDATA generated. You can even check the structure “BDCDATA” in SE11. Also, you can check another SE11 structure BDCMSGCOLL which is used for Collecting messages in the SAP System.

    Note: The recording by SHDB that we will discuss later is a client dependent process, and it has to be saved as a local file in desktop and has to be uploaded the same in to other systems.

    SAP BDC Transaction Codes (Tcode)

    The following T-Codes are used with respect to BDC or Batch Input:

    T-Code Use
    SM35 It is used to run Batch Input Sessions
    SHDB It is used to record a BDC (Batch Input) Session
    BDCUPDATE It is used to check updates in Batch Input

     

    Apart from these, you can find all other relevant T-Codes here.

    Methods of Batch Input or Types of BDC Call

    Now, we have a basic idea of BDC and its terminologies. Now, we will learn how to start with a BDC process. There are two different ways of doing the same. These are:
    1. Call Transaction Method
    2. Classical Batch Input Method or BDC Session Method

    We have discussed each individually in a different article (click them) and created respective programs.

    Error handling in SAP BDC

    There are many reasons due to which your BDC might fail; we will discuss a few issues and errors that are very generic to BDC.

    Important Guidelines for SAP BDC

    Following are the important guidelines in terms of SAP BDC:

    • BDC works by executing t-codes using data uploaded, hence all the data and logic validations are not done in BDC programs but are done in individual t-codes (the reports running behind those t-codes).
    • BDC is suitable for very large amount of data.
    • BDC should be tested in mode A and E, and should be deployed in production in mode N.
    • For different screens you must update the DYNPRO number, else the program will fail.
    • Every time you press enter or click, it is recorded in the BDCDATA. You should write code for every event in your BDC Program.

    Why BDC is not recommended

    BSC is closely associated with screens and t-codes. Every new release of a product in SAP, there might be chance of enhancing the screen; hence making the old BDC becomes non-applicable. Hence, BDC is not recommended for longer run.

    Alternative to SAP BDC

    The alternative to SAP BDC is SAP BAPI. There are several BAPIs that can replace the data transfer of a particular transaction. Even SAP recommends using BDC only in case there are no BAPIs for a t-code.

  • Using models.js in SAP UI5 (to maintain all Global Models)

    Preface – This post is part of the UI5 Programs series.

    What is model.js file in SAP UI5?

    A model in terms of UI5 is a set of data (mostly in JSON format) that can be binded with elements of UI5. For different properties of different elements, the type of model data differs, for example:

    • For the property “visible” of a button, the required model (Data within the model) should be either true or false
    • For the property “text” of a button, the required model (Data within the model) should be a string
    • For the data of the table, the required model should be a JSON data
    • For the data of Drop down, the required model should be JSON data [where one field should act as a key and another as value]
    • For the data of Table count that is shown next to the table name [Example User(90)], the required model (Data within the model) should be a numeric
    • For the data of a Form, the required model should be an Object [with multiple keys and values, where each key will be an element of the form]
    • In case you need to transfer login details to multiple pages, the required model should be an Object [where the key-value pair will save ID and hashed session password/data]

    The model.js in SAP UI5 is a dedicated file to save multiple global variables that can hold data (commonly known as a model) as per requirement.

    The model data refreshes to initial values every time the browser is refreshed; hence it is recommended not to save any data that is required not to be lost during browser refresh.

    The layout of the model.js looks something like this in the folder structure:

    model.js file

    Setting up a Global Model using model.js file in SAP UI5

    There are three steps to using a Global Model.

    1. Create a model object in Model.js file

    The first step is to create a model in model.js file. The model.js file is already created within the model folder of webapp. In case their is no such file, create a file, name it “model.js” with given content:

    sap.ui.define([
        "sap/ui/model/json/JSONModel",
        "sap/ui/Device"
    ], function (JSONModel, Device) {
        "use strict";
    
        return {
    
            createDeviceModel: function () {
                var oModel = new JSONModel(Device);
                oModel.setDefaultBindingMode("OneWay");
                return oModel;
            }
    
        };
    });

    Now, we will add our own code within this file. Let us call it “createAppConfigModel” with given data:

    //app Congiguration model
    createAppConfigModel: function () {
        var appData = {
            "editable": false,
            "count": 0,
            "formData": {},
            "tableData": []
        };
        var oModel = new JSONModel(appData);
        return oModel;
    }

    Now, your Model.js will look like this:

    sap.ui.define([
        "sap/ui/model/json/JSONModel",
        "sap/ui/Device"
    ], function (JSONModel, Device) {
        "use strict";
    
        return {
    
            createDeviceModel: function () {
                var oModel = new JSONModel(Device);
                oModel.setDefaultBindingMode("OneWay");
                return oModel;
            },
            //app Congiguration model
            createAppConfigModel: function () {
                var appData = {
                    "editable": false,
                    "count": 0,
                    "formData": {},
                    "tableData": []
                };
                var oModel = new JSONModel(appData);
                return oModel;
            }
    
        };
    });

     

    2. Configure the Component.js file for the Global Model Object

    In the Component.js file, in case your Model.js file was already there, the model configuration is added like this:

    sap.ui.define([
        "sap/ui/core/UIComponent",
        "sap/ui/Device",
        "YRR/YRR/model/models"
    ], function (UIComponent, Device, models) {
        "use strict";
    
        return UIComponent.extend("YRR.YRR.Component", {
    
            metadata: {
                manifest: "json"
            },
    
            /**
             * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
             * @public
             * @override
             */
            init: function () {
                // call the base component's init function
                UIComponent.prototype.init.apply(this, arguments);
    
                // enable routing
                this.getRouter().initialize();
    
                // set the device model
                this.setModel(models.createDeviceModel(), "device");
    
    
            }
        });
    });

    Here, the model file location is added at the top as “YRR/YRR/model/models” and thereafter in the end the default model is configured using this ” this.setModel(models.createDeviceModel(), “device”);”

    We need to add one more configuration, for our model with this code: “this.setModel(models.createAppConfigModel(), “AppConfig”);”

    Now, the code will look like this:

    sap.ui.define([
        "sap/ui/core/UIComponent",
        "sap/ui/Device",
        "YRR/YRR/model/models"
    ], function (UIComponent, Device, models) {
        "use strict";
    
        return UIComponent.extend("YRR.YRR.Component", {
    
            metadata: {
                manifest: "json"
            },
    
            /**
             * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
             * @public
             * @override
             */
            init: function () {
                // call the base component's init function
                UIComponent.prototype.init.apply(this, arguments);
    
                // enable routing
                this.getRouter().initialize();
    
                // set the device model
                this.setModel(models.createDeviceModel(), "device");
    
                // set the app Config model
                this.setModel(models.createAppConfigModel(), "AppConfig");
    
            }
        });
    });

    That’s it, and we have a global model now.

    3. Using the model in view or Controller

    Now, we can easily access the model in view and controller. Also, we can manipulate the model from the controller.

    How to fetch and change values of a Global Model in SAP UI5?

    To fetch a global model, we need to call the model configuration with the model name we want to access or modify. Let’s assume you need to access the model “count” whose initial value is set as 0.

    var localCount = this.getOwnerComponent().getModel("AppConfig").getProperty("/count");

    The variable “localCount” will now have the value of 0.

    To change the value, we need to call the model configuration with the model name we want to modify. Let’s assume you need to modify the model “count” with a new value as 90.

    this.getOwnerComponent().getModel("AppConfig").setProperty("/count", 90);
    

    In the above step, we have updated the value of the count in the global model.

    How to use Global Model to send values from one page to another?

    To send values from one page to another, you need to perform these steps:

    1. Create a field in the global model that will be used to transfer data

    2. Update the value of the model on the first page, then navigate to the second page

    3. On the second page, get the value of the model

    All these steps are already discussed above in different sections.

    How to bind the global model directly to View?

    To bind a global model directly to the view, you need to perform the following as per the given use cases:

    1. Bind Global Model to a Button Text

    <Button icon="sap-icon://accept" visible="true" text="{AppConfig>/ButtonText}" 
    type="Accept" class="sapUiTinyMarginEnd" press="onAccept"/>

    In this example, we have assumed that the ButtonText is a field in the model having the text value of Button.

    2. Bind Global Model to the visibility of a button

    <Button visible="{=${AppConfig>/OrderType} === 'PO Release' ? true : false}" text="Okay" press="onReleasePO"/>
    <Button visible="{=${AppConfig>/OrderType} === 'Cancel PO Release' ? true : false}" text="Okay" press="onCancelReleasePO"/>

    In this example, Button 1 gets visible if the OrderType has the value ‘PO Release’, else becomes invisible.
    And Button 2 gets visible if the OrderType has the value ‘Cancel PO Release’, else becomes invisible.
    In this way, we can control the visibility of a button based on OrderType with the help of the Global Model.

    3. Bind Global Model to a table [if Model is JSON]

    It is important to have the Model that is being planned to bind with a table to have a format as below:

    {results: [{<JSON Data>}]};

    It means if your model has just an array of data in this form: [{<JSON Data>}] or {“results”: {JSON Data}}
    in both cases, the model binding will fail.

    Controller Code:

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
    
            },
    
            onBeforeRendering: function () {
                var that = this;
                var val = {
                    country_code: 1,
                    country_text: "India"
                };
                var aData = [];
                aData.push(val);
                that.getOwnerComponent().getModel("AppConfig").setProperty("/tableData", {
                    "results": aData
                });
            }
        });
    });

    View Code:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Table Binding">
                        <content>
                            <Table id="idTable" items="{AppConfig>/tableData/results}">
                                <columns>
                                    <Column><Text text="Country Code"/></Column>
                                    <Column><Text text="Country Text"/></Column>
                                </columns>
                                <items>
                                    <ColumnListItem>
                                        <cells>
                                            <Text text="{AppConfig>country_code}"/>
                                            <Text text="{AppConfig>country_text}"/>
                                        </cells>
                                    </ColumnListItem>
                                </items>
                            </Table>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Output:

    Bind Global Model to a table

    4. Bind Global Model to a drop-down [if Model is JSON]

    This process is very much similar to the table code (in the above step). We will use the same controller code but change the view code.

    Controller Code:

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
    
            },
    
            onBeforeRendering: function () {
                var that = this;
                var val1 = {
                    country_code: 1,
                    country_text: "India"
                };
                var val2 = {
                    country_code: 2,
                    country_text: "Germany"
                };
                var aData = [];
                aData.push(val1);
                aData.push(val2);
                that.getOwnerComponent().getModel("AppConfig").setProperty("/tableData", {
                    "results": aData
                });
            }
        });
    });

     

    View Code:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Select a Drop Down">
                        <content>
                            <Select id="idCountrySelect" width="90%" showSecondaryValues="true" items="{AppConfig>/tableData/results}">
                                <core:ListItem key="{AppConfig>country_code}" text="{AppConfig>country_text}"/>
                            </Select>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    Output:

    Bind Global Model to a drop-down [if Model is JSON]

    5. Bind Global Model to a form [if Model is an Object]

    The right way to bind a model to a form should be JSON Model binding with the form with the help of form ID. In this example, we will be binding directly with the global model.

    Controller:

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
    
            },
    
            onBeforeRendering: function () {
                var val = {
                    fname: "Rudramani",
                    lname: "Pandey",
                    country: "India",
                    phone: "+91-9999099099"
                };
                this.getOwnerComponent().getModel("AppConfig").setProperty("/formData", val);
            }
        });
    });

     

    View:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Form Binding">
                        <content>
                            <f:SimpleForm id="idSFormPlatesOvp" editable="false" layout="ResponsiveGridLayout" labelSpanXL="4" labelSpanL="4" labelSpanM="4"
                                labelSpanS="12" adjustLabelSpan="false" emptySpanXL="0" emptySpanL="0" emptySpanM="0" emptySpanS="0" columnsXL="3" columnsL="1" columnsM="1"
                                singleContainerFullSize="false">
                                <f:content>
                                    <core:Title text="Basic Info"/>
                                    <Label text="First Name"/>
                                    <Text text="{AppConfig>/formData/fname}"/>
                                    <Label text="Last Name"/>
                                    <Text text="{AppConfig>/formData/lname}"/>
                                    <Label text="Country"/>
                                    <Text text="{AppConfig>/formData/country}"/>
                                    <Label text="Mobile"/>
                                    <Text text="{AppConfig>/formData/phone}"/>
                                </f:content>
                            </f:SimpleForm>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

     

    Output:

    Bind Global Model to a form [if Model is an Object]

    6. Bind Global Model to a text [if Model is an Object]

    It will be exactly like the above. In case you are binding directly with a field then binding will be like:

    <Text text="{AppConfig>/phone}"/>

    In case you are binding the text with an object, and then you need to reach up to your field using ‘/’, like:

    <Text text="{AppConfig>/formData/phone}"/>

     

    7. Changing the Visibility of fields using the Global Model

    In this example, you can use Global Model to change the visibility of multiple fields. This example is exactly similar to Example 2.

    We will just add a condition to the above form, within the view:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Form Binding">
                        <content>
                            <f:SimpleForm id="idSFormPlatesOvp" editable="false" layout="ResponsiveGridLayout" labelSpanXL="4" labelSpanL="4" labelSpanM="4"
                                labelSpanS="12" adjustLabelSpan="false" emptySpanXL="0" emptySpanL="0" emptySpanM="0" emptySpanS="0" columnsXL="3" columnsL="1" columnsM="1"
                                singleContainerFullSize="false">
                                <f:content>
                                    <core:Title text="Basic Info"/>
                                    <Label text="First Name"/>
                                    <Text text="{AppConfig>/formData/fname}"/>
                                    <Label text="Last Name"/>
                                    <Text text="{AppConfig>/formData/lname}"/>
                                    <Label text="Country"/>
                                    <Text visible="{=${AppConfig>/visible} === true ? true : false}" text="{AppConfig>/formData/country}"/>
                                    <Label text="Mobile"/>
                                    <Text visible="{=${AppConfig>/visible} === true ? true : false}" text="{AppConfig>/formData/phone}"/>
                                </f:content>
                            </f:SimpleForm>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

    In case we make the global model field “visible” as true, then the form will load as usual:

    Bind Global Model to a form [if Model is an Object]

    In case, we will make it false, as shown below:

    sap.ui.define([
        "sap/ui/model/json/JSONModel",
        "sap/ui/Device"
    ], function (JSONModel, Device) {
        "use strict";
    
        return {
    
            createDeviceModel: function () {
                var oModel = new JSONModel(Device);
                oModel.setDefaultBindingMode("OneWay");
                return oModel;
            }, //app Congiguration model 
            createAppConfigModel: function () {
                var AppConfig = {
                    "editable": false,
                    "count": 0,
                    "formData": {},
                    "tableData": {},
                    "visible": false
                };
                var oModel = new JSONModel(AppConfig);
                return oModel;
            }
    
        };
    });

    Then the visibility of these two fields will be turned off:

    Changing the Visibility of fields using the Global Model

    In order to change the value of the global field “visible”, we will write the following code in the controller:

    this.getOwnerComponent().getModel("AppConfig").setProperty("/vsible", false);

     

    8. Making a form Editable and Non-Editable using the Global Model

    To toggle the form Editable and Non-editable, we add a field “editable” in the model, then change the same in the controller based upon the current state [if true, then change it to false and vice-versa] and thereafter bind the same in the editable field.

    Model File:

    sap.ui.define([
        "sap/ui/model/json/JSONModel",
        "sap/ui/Device"
    ], function (JSONModel, Device) {
        "use strict";
    
        return {
    
            createDeviceModel: function () {
                var oModel = new JSONModel(Device);
                oModel.setDefaultBindingMode("OneWay");
                return oModel;
            }, //app Congiguration model 
            createAppConfigModel: function () {
                var AppConfig = {
                    "editable": false,
                    "count": 0,
                    "formData": {},
                    "tableData": {},
                    "visible": false
                };
                var oModel = new JSONModel(AppConfig);
                return oModel;
            }
    
        };
    });

    Controller File:

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("Test.Test.controller.Main", {
            onInit: function () {
    
            },
    
            onPressToggle: function () {
                var editable = this.getOwnerComponent().getModel("AppConfig").getProperty("/editable");
                if (editable) {
                    this.getOwnerComponent().getModel("AppConfig").setProperty("/editable", false);
                } else {
                    this.getOwnerComponent().getModel("AppConfig").setProperty("/editable", true);
                }
            }
        });
    });

    View File:

    <mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
        xmlns:html="http://www.w3.org/1999/xhtml" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <Page id="page" title="Form Binding">
                        <content>
                            <VBox>
                                <Button text="Toggle Visibilty" press="onPressToggle"/>
                            <f:SimpleForm id="idSFormPlatesOvp" editable="false" layout="ResponsiveGridLayout" labelSpanXL="4" labelSpanL="4" labelSpanM="4"
                                labelSpanS="12" adjustLabelSpan="false" emptySpanXL="0" emptySpanL="0" emptySpanM="0" emptySpanS="0" columnsXL="3" columnsL="1" columnsM="1"
                                singleContainerFullSize="false">
                                <f:content>
                                    <core:Title text="Basic Info"/>
                                    <Label text="First Name"/>
                                    <Input editable="{=${AppConfig>/editable} === true ? true : false}" value="{AppConfig>/formData/fname}"/>
                                    <Label text="Last Name"/>
                                    <Input editable="{=${AppConfig>/editable} === true ? true : false}" value="{AppConfig>/formData/lname}"/>
                                    <Label text="Country"/>
                                    <Input editable="{=${AppConfig>/editable} === true ? true : false}" value="{AppConfig>/formData/country}"/>
                                    <Label text="Mobile"/>
                                    <Input editable="{=${AppConfig>/editable} === true ? true : false}" value="{AppConfig>/formData/phone}"/>
                                </f:content>
                            </f:SimpleForm>
                            </VBox>
                        </content>
                    </Page>
                </pages>
            </App>
        </Shell>
    </mvc:View>

     

  • Using formatter.js in SAP UI5 (In View and Controller)

    Preface – This post is part of the UI5 Programs series.

    What is a formatter in UI5?

    A formatter in UI5 is a model that is created to store functions. Each function is used to format the data into a specific format. Generally, it is used to perform the following:

    • Format Data to a specific type (dd/mm/yyyy or something else)
    • Convert values from single character [‘X’, ”] to [Yes, No]
    • Convert values from single characters to icons
    • Format timestamp and time (DD.MM.YYYY:HH:MM:SS)
    • Format Decimal (from 3 decimals to 2 decimals)
    • Remove Decimal Zero (All zeroes after Decimal)
    • Remove leading zeroes from the number

    Guidelines for using formatter

    Formatter is treated just like another function and thus has the same guidelines that are followed by other functions:

    1. A formatter should always return something back
    2. A formatter should have preconditions to fail-safe the formating
    3. A formatter should not return invalid data that can dump the View binding
    4. A formatter should use i18n for all its hard-coded texts
    5. A formatter should be placed in the Model folder with the name “formatter.js”
    6. A formatter should have comments before every function determining the input parameters and output data information

    A blank formatter looks something like this:

    sap.ui.define([], function() {
        "use strict";
    
        return {
    // All your formatted functions like below
    /**
    * Returns Timestamp 
     * @public
     * @param {string} sValue the number string to be timestamp formatted
    * @returns {string} sValue in DD-MM-YYYY: HH:MM:SS
    */
    timestampUnit: function(sValue) {
                if (!sValue) {
                    return "";
                }
                var timestamp = new Date(sValue.seconds * 1000);
                return timestamp;
    },
    
        };
    
    });

     

    Making formatter Global to the Entire App

    To make your formatter Global to the entire app, you need to add it to the BaseController.js file. This will make it accessible to all other pages.

    Adding formatter in Controller

    To add a formatter to a controller file, you need to add it in the definition part and then make the field formatter global. The code is as below:

    sap.ui.define([
        "sap/ui/core/mvc/Controller",
        "YRR/YRR/model/formatter",
    ], function (Controller, formatter,
        ) {
        "use strict";
    
        return BaseController.extend("YRR.YRR.controller.Main", {
    
            formatter: formatter,
            onInit: function () {
    
                                        }
        });
    });

    In the above code, you can see we defined the formatter and specified the exact location. And then, just above the onInit function, we have reassigned it to a global field.

    Using formatter in Controller

    Formatter functions are just like other functions and can be called or initiated with ‘this’ keywords.

    this.formatter.getLocalTime(<pass your field here>)

    In the above statement, this.formatter will call the formatter file. getLocalTime is the name of the function. <pass your fields here> is the placeholder for all the fields that your function ‘getLocalTime’ requires.

    Using formatter in View

    Passing one value in formatter

    To pass a single value in formatter, we replace the text binding with formatter binding, as shown below:

    <Text text="{ path : 'LineItem', formatter: '.formatter.removeZero' }"/>

    In the above code, the path is the field name that is used for binding. And the formatter has the name of the formatter file followed by the function name.

    Passing multiple values in formatter

    <Text text="{ parts : [{path: 'OrdQty'},{path: 'QtyConversion'}], formatter: '.formatter.calculateMultiply' }"/>
    

    In the above code, we have passed multiple values into our formatter using the object ‘parts’ which itself has multiple objects in the form of {path: ‘<field name>’}

    Examples of Formatter

    1. Get Local Time

    getLocalTime: function(sValue) {
                if (sValue) {
                    var dateString = sValue;
                    var year = +dateString.substring(0, 4);
                    var month = +dateString.substring(4, 6);
                    var day = +dateString.substring(6, 8);
                    var date = new Date(year, month - 1, day);
                    var months = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"];
                    var todate = date.getDate();
                    var tomonth = date.getMonth();
                    var monthText = months[tomonth];
                    var toyear = date.getFullYear();
                    if (month < 10 && month > 0) {
                        month = '0' + month.toString();
                    }
                    if (todate < 10 && todate > 0) {
                        todate = '0' + todate.toString();
                    }
                    var original_date = todate + '.' + month + '.' + toyear;
                    if (original_date == '30.0.1899') {
                        return '';
                    } else {
                        return original_date;
                    }
                } else {
                    return "";
                }
            }

    2. Remove Leading Zeros

    removeZero: function(sValue) {
        if (sValue) {
            sValue = sValue.replace(/^0+/, '');
            return sValue;
        } else {
            return '';
        }
    }

    3. Remove Decimal Zeros

    removedecimalZero: function(sValue) {
        if (sValue) {
            sValue = parseInt(sValue);
            sValue = sValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
            if (sValue == '0') {
                return '0';
            } else {
                return sValue;
            }
    
        } else {
            return '0';
        }
    }

    4. Format Decimal Numbers

    formatDecimal: function(sValue) {
        if (sValue) {
            if (sValue == '0.000') {
                return '';
            } else {
                sValue = parseFloat(sValue).toFixed(2);
                return sValue;
            }
    
        } else {
            return '';
        }
    }

    5. Format Custom Icons

    customIcon: function(sValue) {
        if (sValue === "X") {
            return 'sap-icon://message-success';
        } else {
            return '';
        }
    }

    6. Formatting Currency

    This formatting is for adding commas ‘,’ as per currency type, and adding currency signs with numbers.

    currency: function(sValue) {
        if (sValue) {
            // Create our number formatter.
            var formatter = new Intl.NumberFormat('en-US', {
                style: 'currency',
                currency: 'SAR'
            });
    
            return (formatter.format(sValue)); /* $2,500.00 */
        } else {
            return '';
        }
    },

    7. Rounding a Number

    roundNum: function(sValue) {
            if (sValue) {
                sValue = parseFloat(sValue).toFixed(2);
                sValue = Math.round(sValue);
                sValue = sValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                return sValue;
            } else {
                return '';
            }
        },

     

  • Using i18n.properties in SAP UI5 (View, Controller, Adding comment in i18n)

    Preface – This post is part of the UI5 Programs series.

    What is i18n?

    i18n, which stands for internationalization, are Translatable Texts, all in a single place. It means a developer should keep all the texts of their app within i18n so that, in case it is required to have another version of the app with a different language, then all together, a copy of i18n can be made, and those texts can be converted into another language at once.

    Suppose you have only one version that too in English; then you just need a single i18n file. In case you have multiple languages like English (Britsh and US separate), German and French. Then you will need to have these i18n files:

    • i18n.properties [default]
    • i18n_en.properties [for English – British]
    • i18n_en_US.properties [for English – US]
    • i18n_de.properties [for German]
    • i18n_fr.properties [for French]

    Once you create these files, you need to add them in Manifest as a resource bundle. Then, within a controller, you need to use them as per the language of the browser. You can also provide your own language switcher drop-down like this:

    Language Switcher

    In case the app is deployed over Fiori, and then you can take the language set within Fiori:

    Fiori Language Settings

    Guidelines of writing i18n

    You can write the entire i18n file in the form of key= value as shown below, where the key will be then added overview and controller, and the value will be the one shown over UI.

    title=Admin Panel
    appTitle=Admin Panel
    appDescription=Admin Panel for SAP
    id=User ID
    pass=Password
    version=Ver 2.3.0

    Which will look like this in the code editor:

    i18n sample

    But, SAP UI5 suggests the following as the guidelines for writing i18n in a correct and standardized way:

    1. All the keys should be written in a lowercase
    2. The values of i18n can contain parameters like {0}, {1}, {2}, … [This can be used for special dynamic conditions]
    3. For special characters, use Unicode escape sequences
    4. Add comments using ‘#’ before sets of texts that are for certain category like:
      #XMSG: title of App
      title=Admin App
      appTitle=Admin App
      appDescription=Admin App
      
      #XMSG: App Version for Local Use
      appVersion=Version 2.0.14
      
      #XMSG: Not Found texts
      NotFound=Not Found
      NotFound.text=Sorry, but the requested resource is not available.
      NotFound.description=Please check the URL and try again.
      noDataDescriptiont=No data found. Try adjusting the filter settings or check your service.
      
      #XFLD: Form Texts
      COUNTRY=Country
      ServiceType=Service Type
      InOut=Inbound/Outbound
      GroupID=Group ID
      In=Inbound
      Out=Outbound
      

       

    Adding i18n in Manifest File

    Majorly, i18n is preconfigured within the manifest file. Anyhow, you can configure like shown below [it will be within “sap.ui5” object]:

    "models": {
        "i18n": {
            "type": "sap.ui.model.resource.ResourceModel",
            "settings": {
                "bundleName": "YRR.YRR.i18n.i18n"
            }
        }
    }

     

    Using i18n in View

    To use i18n in UI5 View (once it is already set as above in the manifest file), you need to just specify the value in the i18n file and use it for texts using the named model call, i.e. {i18n>text} where text is the key in i18n file with a value against it, like text = This is a text.

    To understand better, we will specify everything in different sections and showcase the output:

    i18n Content

    title=Admin Panel
    appTitle=YRR
    appDescription=App Description
    id=User ID
    pass=Password
    fieldsMandatory=All the fields are mandatory.
    version=Ver 2.3.0

    View Content

    <tnt:header>
    <tnt:ToolHeader>
    <Button id="sideNavigationToggleButton" icon="sap-icon://menu2" type="Transparent" press="onCollapseExpandPress">
    <layoutData>
    <OverflowToolbarLayoutData priority="NeverOverflow"/>
    </layoutData>
    </Button>
    <ToolbarSpacer/>
    <core:Icon src="sap-icon://vehicle-repair"></core:Icon>
    <Text text="{i18n>title}" wrapping="false">
    <layoutData>
    <OverflowToolbarLayoutData priority="Disappear"/>
    </layoutData>
    </Text>
    <ToolbarSpacer/>
    <Button text="Download User Excel" icon="sap-icon://excel-attachment" type="Transparent" press="onSelectExtendedUser"/>
    <Text text="{i18n>version}" wrapping="false"/>
    <!--<Button icon="sap-icon://bell" press="handleMessagePopoverPress"/>-->
    </tnt:ToolHeader>
    </tnt:header>

    Output

    i18n Example

    As you can see, we have binded the title and version with i18n, but the button text ‘Download Excel’ is hardcoded.

    Using i18n in Controller

    To get i18n data in View, you can use the global model that was specified within the manifest. For Controller too, we fetch the same model. You can either fetch everytime you need it, or make it global for that controller by specifying the following within onInit function:

    // Bundle for i18n 
    this.oBundle = this.getOwnerComponent().getModel("i18n").getResourceBundle();

    Once you have specified the above

    Showing Message from i18n in MessageBox

    Now, we will use the above bundle to fetch a text from our i18n:

    // read msg from i18n model
    sMsg = that.oBundle.getText("fieldsMandatory");
    MessageBox.error(sMsg);

    Now, the MessageBox will load the message from i18n, and you don’t have to hardcode the text within the controller.

    Messagebox message from i18n

     

  • Master Detail with multiple fragments for detail and single controller in SAP UI5

    Preface – This post is part of the UI5 Programs series.

    In this article, we will learn Master Detail with multiple fragments for detail and a single controller in SAP UI5. Visit this page, in case you are looking for Master Detail with multiple views and multiple controllers for detail

    Master Detail with multiple fragments for detail and single controller in SAP UI5

    Main.view.xml

    In this use case, our Application name is YRR. We have used tnt:ToolPage to create Master and Detail sections. Within detail, you will see multiple fragments within ScrollContainer. All the tab names are specified within tnt:Side Navigation. On click of these tabs, their functions are called which navigates the view with the help of Scroll Containers ID.

    <mvc:View xmlns:core="sap.ui.core" controllerName="YRR.YRR.controller.Main" xmlns:mvc="sap.ui.core.mvc" xmlns:tnt="sap.tnt"
        xmlns:html="http://www.w3.org/1999/xhtml" displayBlock="true" xmlns="sap.m"
        xmlns:custom="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1">
        <!--<App id="idAppControl">-->
        <tnt:ToolPage id="toolPage">
            <tnt:header>
                <tnt:ToolHeader>
                    <Button id="sideNavigationToggleButton" icon="sap-icon://menu2" type="Transparent" press="onCollapseExpandPress">
                        <layoutData>
                            <OverflowToolbarLayoutData priority="NeverOverflow"/>
                        </layoutData>
                    </Button>
                    <ToolbarSpacer/>
                    <core:Icon src="sap-icon://vehicle-repair"></core:Icon>
                    <Text text="{i18n>title}" wrapping="false">
                        <layoutData>
                            <OverflowToolbarLayoutData priority="Disappear"/>
                        </layoutData>
                    </Text>
                    <ToolbarSpacer/>
                    <Button text="Download User Excel" icon="sap-icon://excel-attachment" type="Transparent" press="onSelectExtendedUser"/>
                    <Text text="{i18n>version}" wrapping="false"/>
                    <!--<Button icon="sap-icon://bell" press="handleMessagePopoverPress"/>-->
                </tnt:ToolHeader>
            </tnt:header>
            <tnt:sideContent>
                <tnt:SideNavigation expanded="true" selectedKey="root0">
                    <tnt:NavigationList>
                        <tnt:NavigationListItem text="Users" key="root0" icon="sap-icon://account" expanded="true" select="onSelectUser"/>
                        <!--<tnt:NavigationListItem text="Download User Excel" key="root1" icon="sap-icon://excel-attachment" expanded="true"-->
                        <!--	select="onSelectExtendedUser"/>-->
                        <tnt:NavigationListItem text="Insurance" key="root2" icon="sap-icon://insurance-car" expanded="true" select="onSelectInsurance"/>
                        <tnt:NavigationListItem text="Transactions" key="root3" icon="sap-icon://vehicle-repair" expanded="true" select="onSelectTransactions"/>
                        <tnt:NavigationListItem text="Controller &amp; Driver" key="root4" icon="sap-icon://manager" expanded="true" select="onSelectController"/>
                        <tnt:NavigationListItem text="Car Plates" key="root5" icon="sap-icon://add-contact" expanded="true" select="onSelectCarPlates"/>
                        <tnt:NavigationListItem text="Promotion &amp; Rewards" icon="sap-icon://loan" expanded="false">
                            <tnt:NavigationListItem text="Promotion" key="root6" icon="sap-icon://payment-approval" expanded="true" select="onSelectPromotion"/>
                            <tnt:NavigationListItem text="Rewards" key="root7" icon="sap-icon://loan" expanded="true" select="onSelectRewards"/>
                            <tnt:NavigationListItem text="Specific Rewards" key="root7_1" icon="sap-icon://loan" expanded="true" select="onSelectSpecificRewards"/>
                        </tnt:NavigationListItem>
                        <tnt:NavigationListItem text="Notifications" icon="sap-icon://sales-notification" expanded="false">
                            <tnt:NavigationListItem text="App Notification" key="root8" icon="sap-icon://sales-notification" expanded="true"
                                select="onSelectNotification"/>
                            <tnt:NavigationListItem text="Manual Push Notification" key="root8_1" icon="sap-icon://sales-notification" expanded="true"
                                select="onSelectPushNotification"/>
                        </tnt:NavigationListItem>
                        <tnt:NavigationListItem text="Home Images" icon="sap-icon://background" expanded="false">
                            <tnt:NavigationListItem text="Promo Images" key="root9_1" icon="sap-icon://background" expanded="true" select="onSelectPromoImages"/>
                            <tnt:NavigationListItem text="Dashboard Images" key="root9_2" icon="sap-icon://background" expanded="true" select="onSelectDashboardImages"/>
                            <tnt:NavigationListItem text="Dashboard Icons" key="root9_3" icon="sap-icon://background" expanded="true" select="onSelectDashboardIcons"/>
                        </tnt:NavigationListItem>
                        <tnt:NavigationListItem text="Master Data" icon="sap-icon://accounting-document-verification" expanded="false">
                            <tnt:NavigationListItem text="Terms &amp; Conditions" key="root12" icon="sap-icon://activities" expanded="true" select="onSelectTerms"/>
                            <tnt:NavigationListItem text="Car Brands" key="root10" icon="sap-icon://insurance-car" expanded="true" select="onSelectCarBrands"/>
                            <tnt:NavigationListItem text="Organizations" key="root13" icon="sap-icon://insurance-car" expanded="true" select="onSelectOrg"/>
                        </tnt:NavigationListItem>
                        <tnt:NavigationListItem text="Enquiry" key="root11" icon="sap-icon://headset" expanded="true" select="onSelectInquiry"/>
                    </tnt:NavigationList>
                    <tnt:fixedItem>
                        <tnt:NavigationList >
                            <tnt:NavigationListItem text="Log Out" icon="sap-icon://log" select="onSelectLogOut"/>
                        </tnt:NavigationList>
                    </tnt:fixedItem>
                </tnt:SideNavigation>
            </tnt:sideContent>
            <tnt:mainContents>
                <NavContainer id="pageContainer" initialPage="root1">
                    <pages>
                        <ScrollContainer id="root0" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.UserDetails" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.ExtendedUserDetails" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root1_1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.UserOvp" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root2" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.InsuranceDetails" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root2_1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.InsuranceOvp" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root3" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Transaction" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root4" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Controller" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root5" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.CarPlates" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root5_1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.CarPlatesOvp" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root6" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Promotion" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root7" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Rewards" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root7_1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.SpecificRewards" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root8" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Notification" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root8_1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.PushNotification" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root9_1" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.PromoImages" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root9_2" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.HomeImages" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root9_3" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.DashboardIcons" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root10" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.CarDetails" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root11" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Inquiry" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root12" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.TermsConditions" type="XML"/>
                        </ScrollContainer>
                        <ScrollContainer id="root13" horizontal="false" vertical="true" height="100%">
                            <core:Fragment fragmentName="YRR.YRR.fragment.Organizations" type="XML"/>
                        </ScrollContainer>
                    </pages>
                </NavContainer>
            </tnt:mainContents>
        </tnt:ToolPage>
        <!--</App>-->
    </mvc:View>

    Output of tnt:SideNavigation:

    Content of Side Navigation

    Main.controller.js

    // the function used to show the User Fragment
    onSelectUser: function (oEvent) {
    // "pageContainer" is the ID of NavContainer within which all the ScrollContainer are added
    // "root0" is the ID of first ScrollContainer within which we have a fragment called "UserDetails"
                this.byId("pageContainer").to(this.getView().createId("root0"));
        },
    
    
    

    No special navigation handling is required within the Manifest file.

    Fragment: UserDetails.fragment.xml

    This Fragment will open when onSelectUser is clicked.

    <core:FragmentDefinition xmlns="sap.m" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form" xmlns:core="sap.ui.core"
        xmlns:u="sap.ui.unified" xmlns:commons="sap.suite.ui.commons">
        <OverflowToolbar>
            <Title text="User Data ({AppConfig>/UserCount})" level="H2"/>
            <ToolbarSpacer/>
            <Button text="Sort" icon="sap-icon://sort" press="handleUserSort"/>
        </OverflowToolbar>
        <Table id="idUserTable" inset="false" items="{/Users}" sticky="ColumnHeaders,HeaderToolbar" class="sapFDynamicPageAlignContent" width="auto">
            <headerToolbar>
                <OverflowToolbar>
                    <SearchField id="idSearchUserName" placeholder="Search Name" value="" search="onSearchName" width="15rem"/>
                    <SearchField id="idSearchUserPhone" placeholder="Search Phone Number" value="" search="onSearchPhone" width="15rem"/>
                    <SearchField id="idSearchUserEmail" placeholder="Search Email ID" value="" search="onSearchUser" width="15rem"/>
                    <SearchField id="idSearchUserOrg" placeholder="Search Organization" value="" search="onSearchOrg" width="15rem"/>
                </OverflowToolbar>
            </headerToolbar>
            <columns>
                <Column minScreenWidth="Tablet" demandPopin="true">
                    <Text text="User Name"/>
                </Column>
                <Column minScreenWidth="Desktop" demandPopin="true" hAlign="End">
                    <Text text="Email ID"/>
                </Column>
                <Column minScreenWidth="Desktop" demandPopin="true" hAlign="Center">
                    <Text text="Phone Number"/>
                </Column>
                <Column minScreenWidth="Desktop" demandPopin="true" hAlign="Center">
                    <Text text="Date of Birth"/>
                </Column>
                <Column minScreenWidth="Desktop" demandPopin="true" hAlign="Center">
                    <Text text="Organization"/>
                </Column>
            </columns>
            <items>
                <ColumnListItem type="Navigation" press="onUserPress">
                    <customData>
                        <core:CustomData key="idUserTable"/>
                    </customData>
                    <cells>
                        <Text text="{userName}"/>
                        <Text text="{email}"/>
                        <Text text="{mob}"/>
                        <Text text="{ path: 'dob', formatter: '.formatter.dateUnit' }"/>
                        <Text text="{org}"/>
                        <!--<Select id="iduserRole" selectedKey="{userRole}" change="onSelectUserRole">-->
                        <!--	<core:Item key="BASIC" text="BASIC"/>-->
                        <!--	<core:Item key="SG Member" text="SG Member"/>-->
                        <!--	<core:Item key="SGMY Member" text="SGMY Member"/>-->
                        <!--</Select>-->
                    </cells>
                </ColumnListItem>
            </items>
        </Table>
        <Bar design="SubHeader" id="idLoadMore">
            <contentMiddle>
                <VBox height="100%" alignItems="Center">
                    <Button text="Load Next 20 Data >>" press="onMoreUsers"/>
                </VBox>
            </contentMiddle>
            <contentRight>
                <Input type="Number" id="pageNumber" width="50px"></Input>
                <Button id="goToButton" text="Go to" type="Emphasized" press="onHandleGoTo"></Button>
            </contentRight>
        </Bar>
        <VBox id="idLoadSortMore" height="100%" alignItems="Center" visible="false">
            <Button text="Load Next 20 Data >>" press="onMoreSortUsers"/>
        </VBox>
    </core:FragmentDefinition>

    Output of Fragment:

    Content of Fragment

  • Master Detail with multiple views and multiple controllers for detail in SAP UI5

    Preface – This post is part of the UI5 Programs series.

    In this article, we will discuss Master Detail with multiple views and multiple controllers for detail in SAP UI5. Visit this page, in case you are looking for Master Detail with multiple fragments for detail and a single controller.

    Master Detail with multiple views and multiple controllers for detail in SAP UI5

    App.view.xml

    The UI5 App name in our use case is “admin”.

    <mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
        controllerName="admin.admin.controller.App" xmlns:html="http://www.w3.org/1999/xhtml">
        <Shell id="shell">
            <App id="app">
                <pages>
                    <!--Split App to Enable Master Detail Configuration-->
                    <SplitApp id="Splitapp" mode="HideMode"></SplitApp> 
                   // delete mode if you wan't to always show the Master section
                </pages>
            </App>
        </Shell>
    </mvc:View>

    App.controller.js

    Nothing is to be written App.Controller.js file

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("admin.admin.controller.App", {
    
            onInit: function () {
    
            }
        });
    
    });

    Manifest.json

    1. Change the rootView to App

    "rootView": {
                "viewName": "admin.admin.view.App",
                "type": "XML",
                "async": true,
                "id": "app"
            },

    2. Update the Routing configuration

    "routing": {
                "config": {
                    "routerClass": "sap.m.routing.Router",
                    "viewType": "XML",
                    "async": true,
                    "viewPath": "admin.admin.view",
                    "controlId": "app",
                    "clearControlAggregation": false
                },
                "routes": [{
                    "name": "Login",
                    "pattern": "",
                    "target": [
                        "masterTarget",
                        "Login"
                    ]
                }, {
                    "name": "Dashboard",
                    "pattern": "Dashboard",
                    "target": [
                        "masterTarget",
                        "Dashboard"
                    ]
                }, {
                    "name": "Appointments",
                    "pattern": "Appointments",
                    "target": [
                        "masterTarget",
                        "Appointments"
                    ]
                }, {
                    "name": "Doctors",
                    "pattern": "Doctors",
                    "target": [
                        "masterTarget",
                        "Doctors"
                    ]
                }, {
                    "name": "Patient",
                    "pattern": "Patient",
                    "target": [
                        "masterTarget",
                        "Patient"
                    ]
                }, {
                    "name": "Subscription",
                    "pattern": "Subscription",
                    "target": [
                        "masterTarget",
                        "Subscription"
                    ]
                }, {
                    "name": "Symptoms",
                    "pattern": "Symptoms",
                    "target": [
                        "masterTarget",
                        "Symptoms"
                    ]
                }, {
                    "name": "Specialty",
                    "pattern": "Specialty",
                    "target": [
                        "masterTarget",
                        "Specialty"
                    ]
                }, {
                    "name": "Tests",
                    "pattern": "Tests",
                    "target": [
                        "masterTarget",
                        "Tests"
                    ]
                }, {
                    "name": "Support",
                    "pattern": "Support",
                    "target": [
                        "masterTarget",
                        "Support"
                    ]
                }],
                "targets": {
                    "masterTarget": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "masterPages",
                        "viewId": "idMaster",
                        "viewName": "Master",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Login": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "Login",
                        "viewName": "Login",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Dashboard": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idDashboard",
                        "viewName": "Dashboard",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Appointments": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idAppointments",
                        "viewName": "Appointments",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Doctors": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idDoctors",
                        "viewName": "Doctors",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Patient": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idPatient",
                        "viewName": "Patient",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Subscription": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idSubscription",
                        "viewName": "Subscription",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Symptoms": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idSymptoms",
                        "viewName": "Symptoms",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Specialty": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idSpecialty",
                        "viewName": "Specialty",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Tests": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idTests",
                        "viewName": "Tests",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    },
                    "Support": {
                        "viewType": "XML",
                        "transition": "slide",
                        "controlAggregation": "detailPages",
                        "viewId": "idSupport",
                        "viewName": "Support",
                        "viewLevel": 1,
                        "controlId": "Splitapp"
                    }
                }
            }

    As you can see we have multiple detail page, and a common thing among all is “masterTarget”. This is the target for Master Page, i.e. “The left pane where you can have multiple tabs to switch pages”.

    Master Page View:  Master.view.xml

    <mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"  xmlns:tnt="sap.tnt"
        controllerName="admin.admin.controller.Master" xmlns:html="http://www.w3.org/1999/xhtml">
        <Page id="master" title="{i18n>Actions}" backgroundDesign="List" class="sapUiStdPage">
            <!--All Master Pane tabs are maintained here-->
            <tnt:NavigationList id="navigationList" selectedKey="Tab_1" itemSelect="onListItemPress">
                <tnt:NavigationListItem text="Configuration" icon="sap-icon://overview-chart" key="Dashboard"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Appointments" icon="sap-icon://account" key="Appointments"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Doctors" icon="sap-icon://stethoscope" key="Doctors"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Patient" icon="sap-icon://wounds-doc" key="Patient"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Subscription" icon="sap-icon://collections-insight" key="Subscription"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Symptoms" icon="sap-icon://electrocardiogram" key="Symptoms"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Medical Specialty" icon="sap-icon://clinical-order" key="Specialty"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Tests" icon="sap-icon://clinical-tast-tracker" key="Tests"></tnt:NavigationListItem>
                <tnt:NavigationListItem text="Support" icon="sap-icon://headset" key="Support"></tnt:NavigationListItem>
                <!--<tnt:NavigationListItem text="Log Out" icon="sap-icon://log" key="LogOut"></tnt:NavigationListItem>-->
            </tnt:NavigationList>
            <footer>
                <OverflowToolbar>
                    <Text text="{i18n>appVersion}"/>
                    <ToolbarSpacer/>
                </OverflowToolbar>
            </footer>
        </Page>
    </mvc:View>

    Master Controller: Master.controller.js

    sap.ui.define([
        "sap/ui/core/mvc/Controller"
    ], function (Controller) {
        "use strict";
    
        return Controller.extend("admin.admin.controller.Master", {
    
            /**
             * Called when a controller is instantiated and its View controls (if available) are already created.
             * Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
             * @memberOf Healthbridge-admin.Healthbridge-admin.view.Master
             */
            onInit: function () {
                // Get Router Info
                this.oRouter = this.getOwnerComponent().getRouter();
            },
            /**
             * onListItemPress is invoked on click from UI. 
             * Input: Key Maintained in Master View
             * Output: Navigation to the Master Page
             */
            onListItemPress: function (oEvent) {
                var that = this;
                sap.ui.core.BusyIndicator.show();
                // var sTimeOutErrorMsg = this.oBundle.getText("TimeOutError");
                var sError;
                var sToPageId = oEvent.getParameter("item").getKey();
                if (sToPageId) {
                    try {
                        that.oRouter.navTo(sToPageId);
                    } catch (err) {
                        if (err.statusCode === 401) {
                            // sError = sTimeOutErrorMsg;
                            window.location.reload(true);
                            sap.ui.core.BusyIndicator.hide();
                        } else {
                            sError = err.error;
                            sap.m.MessageBox.error(sError);
                            window.location.reload(true);
                            sap.ui.core.BusyIndicator.hide();
                        }
                        // window.location.href = '../logout';
                    }
                } else {
                    window.location.reload(true);
                    sap.ui.core.BusyIndicator.hide();
                }
            }
    
        });
    
    });

    Apart from above, you can simply create your pages and controllers and keep linking them in master page and manifest file.

    Changes in Detail Pages

    In Detail pages, you need to handle a few things:

    • Within On Init or Route Matched section, you need to unhide Master Section, in this use case it is hidden, as first page was Login, and we don’t want to show Master section. The code is as below:
      // By default it is set "HideMode" 
      this.getView().getParent().getParent().setMode("ShowHideMode");
      // This is to hide the Master Button over the master page invisible
      this.getView().getParent().getParent()._oShowMasterBtn.setVisible(false);

      In case, you directly go to Master Detail Section, just delete the mode from App.view.xml

    • You can hide and unhide Master tab/section on click of a button whose code is mentioned below
      We have written the code for button press “onExpandPress”:
      Button code: <Button icon=”sap-icon://full-screen” tooltip=”{i18n>Expand}” press=”onExpandPress”/>
      Controller Code:

      /**
               * onExpandPress is invoked from UI on press of button Expand. 
               * Input: current mode -- Full Screen or Pane Screen
               * Output: opposite mode -- Pane Screen or Full Screen
               */
      
              onExpandPress: function (oEvent) {
                  var navVisible = this.getView().getParent().getParent().getMode();
                  if (navVisible === "ShowHideMode") {
                      this.getView().getParent().getParent().setMode("HideMode");
                      oEvent.getSource().setIcon("sap-icon://exit-full-screen");
                  } else {
                      this.getView().getParent().getParent().setMode("ShowHideMode");
                      oEvent.getSource().setIcon("sap-icon://full-screen");
                  }
                  this.getView().getParent().getParent()._oShowMasterBtn.setVisible(false);
              },

       

  • SAP ABAP RAP Job Description (JD) Sample

    Introduction

    The ABAP RAP RESTful Application Programming Model defines the architectural style for productive end-to-end growth of SAP HANA-optimized OData services. It enables the creation of all forms of Fiori applications along with the publication of Web APIs. It is built on platforms and frameworks like Core Data Services (CDS) for defining semantic information-rich data designs, a service model power grid for generating OData services with OData protocol extensions, and ABAP-based services and applications for custom logic SAPUI5-based user interfaces.

    Job Description and Requirements

    • OData provisioning test cases on various platforms must be defined, documented, and implemented.
    • Describe how automated testing should be carried out.
    • The aspirant has to do the automated test.
    • Layout, create and enable applications to satisfy the requirements of business processes.
    • Make preparations for technical design details in a documented manner for the implementation of requirements.
    • Organize, perform, and document the results of each unit testing.
    • As the initial contact, lead the project aims to design, create, and set up applications.
    • Fix event inquiry and problem resolution paperwork.
    • The candidate has to work on issues requests made by clients and has to ensure assistance needs to meet the Service Level Agreement whenever required.
    • To maintain pace with technology and business necessities, imply improvement opportunities and augmentations to existing systems and interfaces.
    • SAP’s emerging paradigm and applying technologies for both on-premise and cloud offerings must be thoroughly understood.
    • RDBMS knowledge is extensive.
    • RDBMS knowledge is extensive.
    • Expertise with SAP HANA on-premise, SAP HANA as a Service, or SAP HANA Cloud is required.
    • Detailed knowledge of SAP BTP components, facilities, and integration, as well as the ability to suggest solution architecture for continuously develop.
    • Customer-focused personality with strong technical negotiation abilities.
    • Expertise working on large projects in a multicultural environment.
    • Strong growth skills in HANA SQL, HANA AMDP, and Node JS.
    • Outstanding communication abilities.

    Education and Experience

    The aspirants must hold a bachelor’s degree in computer science (CS), information technology (IT), or a similar field. He must have at least 5-6 years of hands-on SAP ABAP experience is required. The candidate must have hands-on experience with SAP FIORI and know the required procedure of enhancement and development. He must have experience with ABAP RESTful, IDOC, Web Service, and OData. Must know about SAP Workflow and Standard Reporting is preferred. He must be capable of working individually and efficiently, also capable of managing deadlines and user expectations and delivering high-quality deliverables. He must know how to do documentation, presentations, and research.

    Work hours and benefits

    The work hours include the routine shift, including 6-8 hours of service. The candidate must be capable of working flexible hours per the project’s needs. Health accommodations will be provided, and some bonus accommodations will be provided, which will be accessible through projects.

    Action

    The candidate has to take necessary actions with the hiring procedures. Start Preparing a resume or CV, adding the required skills and experience, and dropping the same to the company’s official web page or email. Further hiring procedures must be followed for successful results.