• How To Use Memory ID (ABAP Memory)

    We can use memory id technique to export/import data to/from ABAP memory. ABAP memory is a memory area in SAP where all ABAP programs within the same session/LUW can has access. We can access/write the ABAP memory using the statement EXPORT and IMPORT.

    Please find below an example on how to export and import data to/from the ABAP memory:

    REPORT  zmemoryid_demo.
    
    *Constants:
    CONSTANTS:
      lc_memidcprog           TYPE char11   VALUE \'ZMEMIDCPROG\'.
    
    *Variables:
    DATA:
      lv_cprog                TYPE sy-cprog,
      lv_cprog_imported       TYPE sy-cprog.
    
    *Assigning the program name for demo purposes.
    lv_cprog = sy-cprog.
    
    *Free the memory ID data before usage.
    FREE MEMORY ID lc_memidcprog.
    
    *Exporting the program name via memory id.
    *Please note that \'LV_DUMMY_CPROG\' is just
    *a dummy field, no need to declare it.
    EXPORT lv_dummy_cprog FROM lv_cprog
    TO MEMORY ID lc_memidcprog.
    
    *For demo purposes, we will import the variable
    *in the same program.
    IMPORT lv_dummy_cprog TO lv_cprog_imported
    FROM MEMORY ID lc_memidcprog.
    
    IF sy-subrc EQ 0.
    
    * If the import was successful, write the
    * importing program name.
      WRITE lv_cprog_imported.
    
    * Its good to free the memory ID data
    * after usage.
      FREE MEMORY ID lc_memidcprog.
    
    ENDIF.

    In the example code above, we have export the program name to memory id and the memory is then imported. The value imported is then display.

    After executing the program above, we can noticed that the name of the program imported via memory id is being displayed on the report:

    \"ABAP
  • Spool Columns Not Display Properly in a Background Job

     

    If we are printing data in spool via background job and the data are not displayed properly, it must be because of the printer specifications format set in the background job.

     

    To make columns appears correctly in the spool, we will have to choose the appropriate format (please refer to below screenshot) for the output device being used.

    \"Format\"

     

    Steps to change the format:

    Step 1: When creating the step of the job in transaction SM36, please click on the button ‘Print Specifications’.

    \"Transaction

     

    Step 2: On the next screen, please enter the appropriate output device, in this case we will used ‘LOCL’ and click on the button ‘Properties’.

    \"Background

    Step 3: On the next screen, double click ‘Format’ (please refer to below screenshot) and change the format to the required size.

    \"Spool

     

    The following format will be available, based on the data to be displayed, choose the appropriate one.

    \"Format\"
  • Smartform Graphics (or Logo) Appearing In Reverse

     

    There is an issue which arises in SAP Smart forms where graphics (or logo) used on smart forms appears in reverse (upside down) when printed on some HP Deskjets.

     

    Issue:

    This issue is because we are using the specific SAP driver ‘SAPWIN’ on HP Deskjets printers. The issue was described in the OSS note 683605.

     

    Solution:

    The solution is to install and use the appropriate HP printer drivers in SAP.

    If the output device ‘LOCL’ is attached to an HP Printer, then the HP driver must be installed. To view which driver is installed on the system, go to transaction SPAD, enter the output driver and press ‘Enter’. On the below screenshot, we can noticed that the driver (device type) is ‘SAPWIN’.

    \"Spool

     

    If an HP Deskjet printer is attached to the output device ‘LOCL’, then graphics used on smart form will appear in reverse. We will have to install the specific HP Deskjet printer driver and assign it to the output device.

    The following steps will explain how to install and assign an HP printer driver ‘ZHPP3005’ to the output device.

     

    Installation and assignment of printer driver in SAP:

    Step 1: Download Driver (Device Type):

    Please download the driver (or Device Type) for the printer being used from HP website. Note that ‘Driver’ is also referred as ‘Device Type’ in SAP.

     

    Step 2: Install the Driver in SAP:

    In transaction SPAD, please go to ‘For devices types > Import’:

    \"Transaction

     

    On the next screen, please selects ‘Device Type’, enter the name of the driver, set the mode to ‘IMPORT’ and execute the program.

    \"Driver

     

    The program will then prompts for the driver downloaded in step 1, please select the downloaded driver.

    The following screen will appears showing that the driver was successfully imported in SAP.

    \"Output\"

     

    Step 3: Assign the driver to the Device Type:

    Once we have installed the driver (in step 2) we will have to assign it to the appropriate output device (printer) in transaction SPAD.

    In transaction SPAD, please enter the output device (for example LOCL) and click on the button display.

    \"Spool

     

     

     

     

     

     

     

     

     

     

     

     

    On the next screen, please select the driver (or Device Type) we have installed in step 2 and save the changes.

    \"Spool

     

    After installing and assigning the new driver, the reverse graphics/logo issue must be solved if you are using an HP Deskject printer.

  • The Function Module \’READ_TEXT\’

    The function module \’READ_TEXT\’ can be used to retrieve different long text values (or text objects) in different SAP document. All long text in SAP can be retrieved using this function module.

     

    Getting the TEXT ID in a sales document:

    • Sales order long text can be viewed in VA03 through the menu ‘Goto > Header’.
    • Select one of the text and click on the icon  \"image003\" (found at the bottom of the text) or please refer to this tutorial how to find these values via debugging.
    • On the next window, we will get the appropriate information to pass to the function module ‘READ_TEXT’ to retrieve the appropriate text.

    Note: Text can be edited using the transaction SO10 and all the text are available in the tables STXH (header) and STXL (item for the text).

     

    Function Module Documentation:

    • CLIENT : Text modules are client-dependent. The client is therefore part of the key. Valid values for this field are defined in table T000.
    • ID : The text ID defines a further subdivision of the texts for a text object. Valid values for the text ID are defined in table TTXID.
    • LANGUAGE : Text modules or layout sets can exist in several languages. The language is therefore part of the key. Valid values for this field are defined in table T002.
    • NAME : The text name can be up to 70 characters long. The structure depends on the text object used. All characters except for \’*\’ and \’&\’ are valid.
    • OBJECT : The text object is part of the text key and assigns the text module to a specific application object. Valid text objects are defined in table TTXOB.
    • HEADER : The text header contains information which describes a text module, for example short text, user who created the text, user who last changed it, etc. The structure of the header is defined in table THEAD.
    • LINES : The table contains all text lines belonging to a text module. The line structure is defined in table TLINE. The line contents are stored in ITF format.

     

    Example:

    The following code logic will be used to retrieve the long text in an accounting document. We will retrieve the long text for the item ‘001’ of the accounting document ‘0123456789’.

    \"Long

     

    Sample Code:

    *Internal tables and structures:
    DATA:
      lt_text               TYPE STANDARD TABLE OF tline.
    
    *Local Variables:
     DATA:
       lv_tdname_partly     TYPE thead-tdname,
       lv_tdname            TYPE thead-tdname.
    
    *Local Constants:
     CONSTANTS:
       lc_id                TYPE thead-tdid       VALUE \'0001\',
       lc_object            TYPE thead-tdobject   VALUE \'DOC_ITEM\'.
    
    *Local Field Symbols:
     FIELD-SYMBOLS:
       <fs_text>            TYPE tline.
    
    *Refreshing internal tables.
     REFRESH:
       lt_text.
    
    *Clearing of variables.
     CLEAR:
       lv_tdname_partly,
       lv_tdname.
    
    * Concatenate FI Document Number, Fiscal Year and the Item Number
    * without space. Please note that the item number is the line item
    
    * number.
      lv_tdname_partly = \'01234567892015001\'.
    
    * Concatenate the Company Code and (FI Document Number, Fiscal Year and the Item Number)
    * seperated by space.
      CONCATENATE \'123\'             \" Company Code
                  lv_tdname_partly  \" Concatenated Number of \'FI Document Number\', \'Fiscal Year\' and \'Line Item\' (without space).
             INTO lv_tdname         \" Fully concatenated number
     SEPARATED BY space.            \" Seperated by space.
    
    
    
    *---------------------------------------*
    *READ TEXT FUNCTION MODULE              *
    *---------------------------------------*
    *This function module will retreive the value of the long text
    *from appropriate database tables. Please note that when retrieving
    *the text, the connection language(SY-LANGU) was used. Thus, if a user
    *logs in \'French\', the long text value might be different for a user
    *which logs in \'English\'.
     CALL FUNCTION \'READ_TEXT\'
       EXPORTING
         client                  = sy-mandt     \"Client Number
         id                      = lc_id        \"Line Item of the FI document in which the text is stored
         language                = sy-langu     \"Language
         name                    = lv_tdname    \"For FI: Concatenation of the company code document and the year
         object                  = lc_object    \"Document item
       TABLES
         lines                   = lt_text      \"The long text will be returned in the following internal table
       EXCEPTIONS
         id                      = 1
         language                = 2
         name                    = 3
         not_found               = 4
         object                  = 5
         reference_check         = 6
         wrong_access_to_archive = 7
         OTHERS                  = 8.
    
    *If value found, proceed with populating the column.
     IF sy-subrc EQ 0.
    
    *  Read the first line of the internal table return
    *  by the function module. This internal table will
    *  contains the appropriate text.
       READ TABLE lt_text
       ASSIGNING <fs_text>
       INDEX 1.
    
       IF sy-subrc EQ 0.
    
    *   Write the long text.
        WRITE <fs_text>-tdline.
    
       ENDIF.
    
     ENDIF.
    

     

    Observed Results:

    \"Output\"

     

  • The Difference Between SY-TABIX and SY-INDEX

    Please below an explanation of the system variables SY-TABIX and SY-INDEX:

     

    SY-TABIX:

    • SY-TABIX contains the current line in an internal table. That is, it will contain the position of the record we are accessing in an internal table.

    SY-TABIX in different scenarios:

    • Statement ‘APPEND’ will set SY-TABIX to the position of the last table row
    • Statement ‘COLLECT’ will set SY-TABIX to the position of the appended table row
    • Statement ‘LOOP’ will set SY-TABIX to the position of the record we are accessing (or current loop record)
    • Statement ‘READ’ will set SY-TABIX to the position of the record we are reading
    • Statement ‘SEARCH’ will set SY-TABIX to the position of the table row in which the search string was found

    Note: SY-TABIX is set to 0 with hashed tables.

     

    SY-INDEX:

    • SY-INDEX contains the number of loop passes in DO and WHILE loop.

    Code demonstrating different between SY-TABIX and SY-INDEX:

    *&--------------------------------------------------------------------&*
    *& Program Description:                                               &*
    *& -----------------------                                            &*
    *& This demo program will demonstrate the difference between SY-TABIX &*
    *& and SY-INDEX.                                                      &*
    *&                                                                    &*
    *& Author:  ABAPCOOKBOOK                                              &*
    *& Website: www.abapcookbook.com                                      &*
    ************************************************************************
    
    REPORT ZDEMOSYINDEXTABIX.
    
     *Internal tables and structures:
    DATA:
      lt_bkpf     TYPE STANDARD TABLE OF bkpf,
      lt_bseg     TYPE STANDARD TABLE OF bseg,
      lst_bkpf    TYPE bkpf,
      lst_bseg    TYPE bseg.
    
    *---------------------------------------*
    *DUMMY RETRIEVAL:                       *
    *---------------------------------------*
    *Dummy retrieval for demo purposes.
    *Data at header level.
    SELECT *
      FROM bkpf
      INTO TABLE lt_bkpf
     UP TO 10 ROWS.
    
    IF sy-subrc EQ 0.
    
    * Sort and delete adjacent duplicates not necessary as
    * we are sorting and deleting by primary keys. However, we
    * will leave like that to remember that its a best practice
    * to sort and delete adjacents duplicates when using for
    * all entries.
      SORT lt_bkpf BY bukrs belnr gjahr.
      DELETE ADJACENT DUPLICATES FROM lt_bkpf COMPARING bukrs belnr gjahr.
    
    * Data at item level.
      SELECT *
        FROM bseg
        INTO TABLE lt_bseg
     FOR ALL ENTRIES IN lt_bkpf
       WHERE bukrs EQ lt_bkpf-bukrs
         AND belnr EQ lt_bkpf-belnr
         AND gjahr EQ lt_bkpf-gjahr.
    
      IF sy-subrc EQ 0.
    
    *   Sorting not required but its just for
    *   information purposes.
        SORT lt_bseg BY bukrs belnr gjahr.
    
      ENDIF.
    
    ENDIF.
    
    *---------------------------------------*
    *SY-TABIX (LOOP):                       *
    *---------------------------------------*
    LOOP AT lt_bkpf INTO lst_bkpf.
    
    * Displaying the SY-TABIX when use
    * inside a loop.
      WRITE: /1 sy-vline,
             2(40) \'SY-TABIX (LOOP BKPF):\',
             41 sy-vline,
             50(10) sy-tabix,
             61 sy-vline.
    
      WRITE:/1(61) sy-uline.
    
    ENDLOOP.
    
    WRITE:/1 sy-uline.
    
    *---------------------------------------*
    *SY-TABIX (READ STATEMENT):             *
    *---------------------------------------*
    LOOP AT lt_bkpf INTO lst_bkpf.
    
      READ TABLE lt_bseg
      TRANSPORTING NO FIELDS
      WITH KEY bukrs = lst_bkpf-bukrs
               belnr = lst_bkpf-belnr
               gjahr = lst_bkpf-gjahr
               BINARY SEARCH.
    
      IF sy-subrc EQ 0.
    
    *   SY-TABIX will returns the position of record
    *   found in the \'LT_BSEG\'.
        WRITE: /1 sy-vline,
               2(40) \'SY-TABIX (READ BSEG):\',
               41 sy-vline,
               50(10) sy-tabix,
               61 sy-vline.
    
        WRITE:/1(61) sy-uline.
    
      ENDIF.
    
    * Clearing necessary items.
      CLEAR:
        lst_bkpf.
    
    ENDLOOP.
    
    WRITE:/1 sy-uline.
    
    *---------------------------------------*
    *SY-INDEX (DO-ENDDO or WHILE-ENDWHILE): *
    *---------------------------------------*
    DO 5 TIMES.
    
    * Displaying the SY-INDEX when use
    * inside a DO loop, same results is 
    * expected inside a WHILE loop.
      WRITE: /1 sy-vline,
             2(40) \'SY-INDEX (DO LOOP):\',
             41 sy-vline,
             50(10) sy-index,
             61 sy-vline.
    
      WRITE:/1(61) sy-uline.
    
    ENDDO.
    
    

    The results:

    \"image002\"

     

  • Index Looping in SAP

    In SAP, for better performance, instead of using nested loops, we can use the index looping technique.

     

    The following sample code explains the usage of index looping and shows the difference between nested loops and index looping:

    *&--------------------------------------------------------------------&*
    *& Program Description:                                               &*
    *& -----------------------                                            &*
    *& This demo program will demonstrate the use of index looping.       &*
    *&                                                                    &*
    *&                                                                    &*
    *& Author:  ABAPCOOKBOOK                                              &*
    *& Website: www.abapcookbook.com                                      &*
    ************************************************************************
    
    REPORT ZDEMOINDEXLOOPING.
    
    *Internal tables and structures:
    DATA:
      lt_bkpf     TYPE STANDARD TABLE OF bkpf,
      lt_bseg     TYPE STANDARD TABLE OF bseg,
      lst_bkpf    TYPE bkpf,
      lst_bseg    TYPE bseg.
    
    *Variables:
    DATA:
      gv_stime    TYPE i,         \"Start Time
      gv_etime    TYPE i,         \"End Time
      gv_tdiff    TYPE i,         \"Time Difference
      gv_counter  TYPE i,         \"Record Counter
      gv_tabix    TYPE sy-tabix.  \"Tabix Position
    
    
    *------------------------------------*
    *DUMMY RETRIEVAL:                    *
    *------------------------------------*
    *Dummy retrieval for demo purposes.
    *Data at header level.
    SELECT *
      FROM bkpf
      INTO TABLE lt_bkpf
     UP TO 10 ROWS.
    
    IF sy-subrc EQ 0.
    
    * Sort and delete adjacent duplicates not necessary as
    * we are sorting and deleting by primary keys. However, we
    * will leave like that to remember that its a best practice
    * to sort and delete adjacents duplicates when using for
    * all entries.
      SORT lt_bkpf BY bukrs belnr gjahr.
      DELETE ADJACENT DUPLICATES FROM lt_bkpf COMPARING bukrs belnr gjahr.
    
    ENDIF.
    
    *If the table is not empty, proceed. Please note that
    *this is necessary when doing for all entries because
    *if the table \'LT_BKPF\' is empty, the following retrieval
    *will retrieve all the entries from table BSEG.
    IF lt_bkpf[] IS NOT INITIAL.
    
    * Data at item level.
      SELECT *
        FROM bseg
        INTO TABLE lt_bseg
     FOR ALL ENTRIES IN lt_bkpf
       WHERE bukrs EQ lt_bkpf-bukrs
         AND belnr EQ lt_bkpf-belnr
         AND gjahr EQ lt_bkpf-gjahr.
    
      IF sy-subrc EQ 0.
    
    *     Sorting not required but its just for
    *     information purposes.
        SORT lt_bseg BY bukrs belnr gjahr.
    
      ENDIF.
    
    ENDIF.
    
    
    *------------------------------------*
    *NESTED LOOPS:                       *
    *------------------------------------*
    *Get the starting time.
    GET RUN TIME FIELD gv_stime.
    
    *Nested Loops:
    *Loop at header level.
    LOOP AT lt_bkpf INTO lst_bkpf.
    
    * Loop at item level.
      LOOP AT lt_bseg INTO lst_bseg
      WHERE bukrs EQ lst_bkpf-bukrs
        AND belnr EQ lst_bkpf-belnr
        AND gjahr EQ lst_bkpf-gjahr.
    
    *   Do some processing.
        gv_counter = gv_counter + 1.
    
      ENDLOOP.
    
    ENDLOOP.
    
    *Get the ending time.
    GET RUN TIME FIELD gv_etime.
    
    *Get the time difference, which will be the execution time
    *the code was executed.
    gv_tdiff = gv_etime - gv_stime.
    
    *Output the time difference.
    WRITE:/1(61) sy-uline.
    WRITE: /1 sy-vline, 2(40) \'Taking Taken Using Nested Loops:\', gv_tdiff,
                        41 sy-vline,
                        50(10) gv_tdiff,
                        61 sy-vline.
    
    *------------------------------------*
    *INDEX LOOPING:                      *
    *------------------------------------*
    CLEAR:
      gv_counter.
    
    *Get the starting time.
    GET RUN TIME FIELD gv_stime.
    
    *Nested Loops:
    *Loop at header level.
    LOOP AT lt_bkpf INTO lst_bkpf.
    
    * We will check if we have the header record
    * at item level.
      READ TABLE lt_bseg
      TRANSPORTING NO FIELDS
      WITH KEY bukrs = lst_bkpf-bukrs
               belnr = lst_bkpf-belnr
               gjahr = lst_bkpf-gjahr
               BINARY SEARCH.
    
    * If we have a match, get the tabix position
    * at which we found the header level record in
    * the item level table.
      IF sy-subrc EQ 0.
    
    *   Get the tabix position of the line found
    *   in \'LT_BSEG\'. The tabix position will be
    *   used to start the next loop at that position.
        gv_tabix = sy-tabix.
    
    *   Loop at item level.
    *   Here, we will start looping in the table \'LT_BSEG\'
    *   using the tabix position found above.
        LOOP AT lt_bseg INTO lst_bseg
        FROM gv_tabix.
    
    *     Here, we will check if the current item level
    *     record still match the header level record. If not,
    *     means that we can exit the loop and take the next
    *     header level record.
          IF lst_bkpf-bukrs NE lst_bseg-bukrs
          OR lst_bkpf-belnr NE lst_bseg-belnr
          OR lst_bkpf-gjahr NE lst_bseg-gjahr.
    
    *       Clearing necessary items.
            CLEAR:
              gv_tabix,
              lst_bseg.
    
    *       Okay, go out of the loop.
            EXIT.
    
          ENDIF.
    
    *     If the IF statement above has failed, means that
    *     that line at header level matches the line at item
    *     level, do some processing.
    *     Do some processing.
          gv_counter = gv_counter + 1.
    
    *     Clearing necessary items.
          CLEAR:
            lst_bseg.
    
        ENDLOOP.
    
      ENDIF.
    
    * Clearing necessary items.
      CLEAR:
        lst_bkpf.
    
    ENDLOOP.
    
    *Get the ending time.
    GET RUN TIME FIELD gv_etime.
    
    *Get the time difference, which will be the execution time
    *the code was executed.
    gv_tdiff = gv_etime - gv_stime.
    
    *Output the time difference.
    WRITE:/1(61) sy-uline.
    WRITE: /1 sy-vline, 2(40) \'Taking Taken Using Index Looping:\', gv_tdiff,
                        41 sy-vline,
                        50(10) gv_tdiff,
                        61 sy-vline.
    
    WRITE:/1(61) sy-uline.

    The results clearly shows that index looping is much better than nested loops.

    \"image001\"

     

  • Collect Data in an Internal Table

    In ABAP, the statement ‘COLLECT’ is used to add all numeric values of a work area into an internal table.

    For example: In the example below, we will explain and demonstrate how to we will collect the data in an internal table.

     

    Step 1: Internal table which will be collected:

    MATNR WERKS OMENG
    MAT1 AB 10
    MAT1 AB 5
    MAT1 AB 10
    MAT2 AB 30
    MAT2 CD 20
    MAT3 DE 40

     

    Step 2: When the above internal table is collected, all numerical field of similar non-numerical field will be added together.

    MATNR     WERKS      OMENG
    MAT1  AB 10 + 5 + 10
    MAT1 AB 5
    MAT1 AB 10
    MAT2 AB 30 + 20
    MAT2 AB 20
    MAT3 DE 40

     

    Results: The results will be as follows:

    MATNR WERKS  OMENG
    MAT1 AB 25
    MAT2 AB 50
    MAT3 DE 40

     

    We can use the following code to achieve the above results:

    *Types:
    TYPES:
    BEGIN OF gxs_vbbe ,
    matnr TYPE vbbe-matnr,
    werks TYPE vbbe-werks,
    omeng TYPE vbbe-omeng,
    END OF gxs_vbbe.
    
    *Internal tables and structures:
    DATA:
    lt_vbbe TYPE STANDARD TABLE OF gxs_vbbe,
    lt_vbbe_collected TYPE STANDARD TABLE OF gxs_vbbe,
    lst_vbbe TYPE gxs_vbbe.
    
    * Dummy retrieval for demo purposes.
    SELECT matnr \" Material Number
    werks \" Plant
    omeng \" Open Qty
    FROM vbbe
    INTO TABLE lt_vbbe
    UP TO 10 ROWS.
    
    * Looping on the internal table to be collected.
    LOOP AT lt_vbbe INTO lst_vbbe.
    
    * Collecting all numeric values into the
    * internal table \'LT_VBBE_COLLECTED\'.
    COLLECT lst_vbbe INTO lt_vbbe_collected.
    
    ENDLOOP.

     

    Please note: In the above example, the program will check if MATNR and WERKS are similar, if they are similar, then we will add/collect the numerical fields together.

    In case you want to collect only when the MATNR is similar, then clear the value of the field LST_VBBE-WERKS before the collect statement. The loop will look as follows:

    * Looping on the internal table to be collected.
    LOOP AT lt_vbbe INTO lst_vbbe.
    
    * Clearing the plant(WERKS) as we want only
    * to collect for similar material number (MATNR).
    CLEAR lst_vbbe-werks.
    
    * Collecting all numeric values into the
    * internal table \'LT_VBBE_COLLECTED\'.
    COLLECT lst_vbbe INTO lt_vbbe_collected.
    
    ENDLOOP.

     

    Another way to collect without clearing the variable is to move the fields we want to collect into a different structure. We will then use the different structure to do the collect. This can be useful in case we want to collect different values in the same loop. The code will look as follows:

    *Types:
    TYPES:
      BEGIN OF  gxs_vbbe,
        matnr TYPE vbbe-matnr,
        werks TYPE vbbe-werks,
        omeng TYPE vbbe-omeng,
      END OF gxs_vbbe,
    
      BEGIN OF  gxs_vbbe_col_mat,
        matnr TYPE vbbe-matnr,
        omeng TYPE vbbe-omeng,
      END OF gxs_vbbe_col_mat.
    
    *Internal tables and structures:
    DATA:
      lt_vbbe           TYPE STANDARD TABLE OF gxs_vbbe,
      lt_vbbe_collected TYPE STANDARD TABLE OF gxs_vbbe,
      lst_vbbe          TYPE gxs_vbbe,
      lt_vbbe_col_mat   TYPE STANDARD TABLE OF gxs_vbbe_col_mat,
      lst_vbbe_col_mat  TYPE gxs_vbbe_col_mat.
    
    
    * Dummy retrieval for demo purposes.
      SELECT matnr  \" Material Number
             werks  \" Plant
             omeng  \" Open Qty
        FROM vbbe
        INTO TABLE lt_vbbe
       UP TO 10 ROWS.
    
    * Looping on the internal table to be collected.
      LOOP AT lt_vbbe INTO lst_vbbe.
    
    *   Move MATNR and OMENG to a different structure,
    *   we will use the different structure to do the
    *   collect.
        MOVE lst_vbbe-matnr TO lst_vbbe_col_mat-matnr.
        MOVE lst_vbbe-omeng TO lst_vbbe_col_mat-omeng.
    
    *   Collecting all numeric values into the
    *   internal table \'LT_VBBE_COLLECTED\'.
        COLLECT lst_vbbe_col_mat INTO lt_vbbe_col_mat.
    
      ENDLOOP.
    

     

  • Using BAL Log for Application Logging

    In this tutorial, we will explain how to implement a BAL log or application log in an ABAP program.

    The following function modules will be used when implementing BAL Log:

    • BAL_LOG_CREATE : To create and initialize the BAL log
    • BAL_LOG_MSG_ADD : To add message to the BAL log
    • BAL_DSP_LOG_DISPLAY : To display the BAL log

     

    Step 1 – Creating BAL Log:

    The first step is to create/setup the BAL log.

    The following code logic will be used to create the BAL log:

    *----------------------------------------------------------------------*
    * Sub routine to create the application log for error logging          *
    * purposes.                                                            *
    *----------------------------------------------------------------------*
    FORM f_create_log.
    *----------------------------------------------------------------------*
    * Local data declarations.
    * Structures:
      DATA:
        lst_log TYPE bal_s_log.
    
    * Defining some header data of the application log.
      lst_log-extnumber = text-006.   \" Text: \'Program Log\'.
      lst_log-aluser    = sy-uname.
      lst_log-alprog    = sy-repid.
    
    * Creationg the application log.
      CALL FUNCTION \'BAL_LOG_CREATE\'
        EXPORTING
          i_s_log = lst_log
        EXCEPTIONS
          OTHERS  = 1.
      IF sy-subrc NE 0.
    
    *   Display error message.
        MESSAGE ID sy-msgid TYPE gc_i NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 DISPLAY LIKE gc_e.
    
      ENDIF.
    
    ENDFORM.                    \" F_CREATE_LOG

     

    Step 2 – Adding Message to the BAL Log:

    Once the BAL log has been created, we will have to add logging message to it which will later be used to display to the user. To add message to the BAL log, we will use the function module ‘BAL_LOG_MSG_ADD’.

    The following code logic will be used to add messages to the BAL log:

    *----------------------------------------------------------------------*
    * Sub routine to add a message to the processing log.                  *
    *----------------------------------------------------------------------*
    *      -->PI_PROBCLASS  Problem Class.                                 *
    *----------------------------------------------------------------------*
    FORM f_add_msg_to_log USING pi_probclass TYPE bal_s_msg-probclass.
    *----------------------------------------------------------------------*
    * Local data declarations.
    * Structures:
      DATA:
        lst_msg TYPE bal_s_msg.
    
    * Defininig data of message for the application log.
      lst_msg-msgty     = sy-msgty.
      lst_msg-msgid     = sy-msgid.
      lst_msg-msgno     = sy-msgno.
      lst_msg-msgv1     = sy-msgv1.
      lst_msg-msgv2     = sy-msgv2.
      lst_msg-msgv3     = sy-msgv3.
      lst_msg-msgv4     = sy-msgv4.
      lst_msg-probclass = pi_probclass.
    
    * Adding this message to log file.
      CALL FUNCTION \'BAL_LOG_MSG_ADD\'
        EXPORTING
          i_s_msg       = lst_msg
        EXCEPTIONS
          log_not_found = 0
          OTHERS        = 1.
      IF sy-subrc NE 0.
    
    *   Display error message.
        MESSAGE ID sy-msgid TYPE gc_i NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 DISPLAY LIKE gc_e.
    
    *   Stop processing and go to end of selection.
        STOP.
    
      ENDIF.
    
    ENDFORM.                    \"f_add_msg_to_log

     

    Note: The above sub routine must be called as follows:

    *Add the message to the log.
    PERFORM f_add_msg_to_log USING gc_probclass_none.

     

    Where the constant ‘GC_PROBCLASS_NONE’ is declared as follows:

    CONSTANTS:    
         gc_probclass_none     TYPE bal_s_msg-probclass VALUE \' \'.

     

    We can also pass the following value to the field ‘LST_MSG-PROBCLASS’ for different type of message error type.

    CONSTANTS:
      gc_probclass_medium   TYPE bal_s_msg-probclass    VALUE \'3\',
      gc_probclass_low      TYPE bal_s_msg-probclass    VALUE \'4\'.
    

     

    Step 3 – Displaying the BAL Log:

    Once log messages have been added to the BAL log, we can display the BAL log using the function module ‘BAL_DSP_LOG_DISPLAY’. Normally, we display in the event ‘END-OF-SELECTION’.

    The following code logic will be used to display the BAL log:

    *----------------------------------------------------------------------*
    * Sub routine to display the error log.                                *
    *----------------------------------------------------------------------*
    FORM f_display_log.
    *----------------------------------------------------------------------*
    
    * Function module to display the processing log.
      CALL FUNCTION \'BAL_DSP_LOG_DISPLAY\'
        EXPORTING
    *     Sort logs by Timestamp (\'X\') or Log Number (SPACE).
          i_srt_by_timstmp     = space
        EXCEPTIONS
          profile_inconsistent = 1
          internal_error       = 2
          no_data_available    = 3
          no_authority         = 4.
      IF sy-subrc NE 0.
    
    *   Display error message.
        MESSAGE ID sy-msgid TYPE gc_i NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 DISPLAY LIKE gc_e.
    
      ENDIF.
    
    ENDFORM.                    \" F_DISPLAY_LOG
    
    

     

    Screenshot of a BAL log:

    \"image001\"

    To find more standard SAP BAL log demo, type ‘SBAL_DEMO_*’ in SE38 and press F4.

  • Function Module To Split a Long Text into Smaller Segments

    The function module ‘RKD_WORD_WRAP’ can be used to split a long text into smaller segments of specific length. The smaller segments will be available in an internal table.

    Code:

    *Types:
    TYPES:
    BEGIN OF gxs_text_split,
    text_split(5) TYPE c,
    END OF gxs_text_split.
    
    *Internal Tables:
    DATA:
    lt_text_split TYPE STANDARD TABLE OF gxs_text_split.
    
    *Variables:
    DATA:
    lv_text_full(45) TYPE c.
    
    lv_text_full = \'The quick brown fox jumps over the lazy dog.\'.
    
    *The following function module will split the text above into
    *5 characters.
    CALL FUNCTION \'RKD_WORD_WRAP\'
    EXPORTING
    textline = lv_text_full \" Variable which will be splitted.
    outputlen = 5 \" Split into segments of 5 characters.
    TABLES
    out_lines = lt_text_split \" Internal table containing lines, each line will contains 5 characters max.
    EXCEPTIONS
    outputlen_too_large = 1
    OTHERS = 2.

     

    The output of the spitted texts in the internal table ‘LT_TEXT_SPLIT’:

    \"\"