Object Oriented Approach for Reports with multiple Datasource

By | April 14, 2015 | ABAP Objects, OO Design Patterns | 5,341 | 12

Lets checkout the ABAP object oriented approach for reports when you want to get data from different data sources – Database and/or Archive .

Introduction

Almost all clients use archiving to control the primary DB size and to make sure it doesn’t grow too big. If primary DB would be big, it would have its own performance impact. But this not the topic for this article. In this article, I want to give you a pattern which you can follow in your developments where you have more than one data source – Database and Archive.

In this example, we would take PBS as the archive add-on as example. But, in reality you can implement this approach in any multiple data selection.

Report Requirement

This report is very basic report to display data from DB as well as archive. The selection screen has other reporting criteria along with these options:

Multiple_Options

As name suggest, the data can be selected from DB, archive or both

Procedural Design

In simple procedural design, this report selection would be using the IF conditions to restrict the selection based on the selected option. It is not necessarily an issue, but this design can be modified to be more modular, following more design principles, etc.

I’m providing only the part where there is a data selection and also there is different logic.

 
* Block 1 of selection screen
SELECTION-SCREEN BEGIN OF BLOCK block1 WITH FRAME TITLE text-001.
SELECT-OPTIONS : s_vendor   FOR v_vendor.
SELECTION-SCREEN END OF BLOCK block1.
 
* Display Data Retrieval Options
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-049.
 
PARAMETERS: p_rb_all TYPE c RADIOBUTTON GROUP rd2,
            p_rb_arc TYPE c RADIOBUTTON GROUP rd2 ,
            p_rb_db TYPE c RADIOBUTTON GROUP rd2 DEFAULT 'X'.
 
SELECTION-SCREEN END OF BLOCK b2.
 
 
 
START-OF-SELECTION.
 
  IF p_rb_db  = 'X'
  OR p_rb_all = 'X'.
    SELECT       ebeln
                 bukrs
                 bsart
                 lifnr
                 waers
                 submi
            INTO TABLE i_ekko
            FROM ekko
            WHERE lifnr IN s_vendor[].
  ENDIF.
 
 
  IF p_rb_ar  = 'X'
  OR p_rb_all = 'X'.
 
    DATA: tab93 TYPE STANDARD TABLE OF ekko.
    DATA: ls_tab93 LIKE LINE OF tab93.
    DATA: ls_ekko  LIKE LINE OF i_ekko.
 
    CALL FUNCTION '/PBS/SELECT_INTO_TABLE'
      EXPORTING
        archiv     = 'CMM'
        option     = "
        tabname    = 'EKKO'
        clr_itab   = 'X'
        schl1_name = 'LIFNR'
      TABLES
        i_tabelle  = tab93
        schl1_in   = s_vendor[]
      EXCEPTIONS
        eof        = 4
        OTHERS     = 2.
    LOOP AT tab93 INTO ls_tab93.
      MOVE ls_tab93-ebeln TO ls_ekko-ebeln .
      MOVE ls_tab93-bukrs TO ls_ekko-bukrs .
      MOVE ls_tab93-bsart TO ls_ekko-bsart .
      MOVE ls_tab93-lifnr TO ls_ekko-lifnr .
      MOVE ls_tab93-waers TO ls_ekko-waers .
      MOVE ls_tab93-submi TO ls_ekko-submi .
      APPEND ls_ekko TO i_ekko .
    ENDLOOP.
    DESCRIBE TABLE i_ekko LINES sy-tfill.
    IF sy-tfill GT 0. sy-subrc = 0. ENDIF.
 
  ENDIF.
 
  IF p_rb_db  = 'X'
  OR p_rb_all = 'X'.
    SELECT        ekpo~ebeln
                  ekpo~ebelp
                  ekpo~matnr
                  ekpo~bukrs
                  ekpo~werks
                  ekpo~menge
                  ekpo~netwr
                  ekkn~ps_psp_pnr
                  eket~eindt
                  ekpo~mwskz
                  ekpo~loekz
            INTO TABLE i_ekpo
            FROM ekpo
              JOIN ekkn
                ON ( ekpo~ebeln =  ekkn~ebeln
                 AND ekpo~ebelp =  ekkn~ebelp  )
              JOIN eket
                ON  ( ekpo~ebeln =  eket~ebeln
                  AND ekpo~ebelp =  eket~ebelp  )
            FOR ALL ENTRIES IN i_ekko
            WHERE ekpo~ebeln EQ i_ekko-ebeln.
  ENDIF.
 
  IF p_rb_ar  = 'X'
  OR p_rb_all = 'X'.
     "use same PBS FM to get the data from EKPO, EKKN, EKET
  ENDIF.
 
 
  "Vendor name selection
 
 
  "fill up final table
 
 
  "display data in ALV
 
 

Object Oriented Approach

To avoid the IF conditions and to have separate classes for the different data sources, I use these design. This design is very much dependent on the Decorator Design Pattern. If you are not yet familiar with decorator, I suggest you make yourself familiar with decorator before continue reading here.

The design is based on following idea:

  • Create the class for the primary data selection.
  • Using this class, inherit classes for each data source.
  • At time of instantiating the object, establish the decorator relationship
  • Within the methods which are redefined, call the decorator methods.
  • Get back the data from decorator objects into the primary data object.
UML_OO_report_multiple_Datasource

Here you are not fully using the decorator design pattern. But, you can if you have more than couple different data-sources.

Another problem I’m facing is to make sure same data selection doesn’t get reselected over and over

Redesigned Code Lines

Again, this is smaller version of the original program with only relevant parts. You can create the full blown solution using ABAP Object Oriented Approach for Reports – Redesign

 
*
CLASS zcl_cda_db DEFINITION.
  PUBLIC SECTION.
 
    METHODS:
      constructor
        IMPORTING
          io_next TYPE REF TO zcl_cda_db OPTIONAL.
 
    METHODS:
      get_data.
 
  PROTECTED SECTION.
    TYPES:
      tt_ekko TYPE STANDARD TABLE OF ty_ekko,
      tt_ekpo TYPE STANDARD TABLE OF ty_ekpo.
 
    METHODS:
      select_ekko,
      select_ekpo_ekkn,
      merge_data,
      select_vendor_names,
      fill_final_table.
 
    DATA:
        i_ekko       TYPE tt_ekko,
        i_ekpo            TYPE tt_ekpo.
 
 
    DATA: o_decorator TYPE REF TO zcl_cda_db.
 
ENDCLASS.                    "zcl_cda_db DEFINITION
*
CLASS zcl_cda_arch DEFINITION
  INHERITING FROM zcl_cda_db.
 
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          io_next TYPE REF TO zcl_cda_db OPTIONAL.
 
  PROTECTED SECTION.
    METHODS:
      select_ekko REDEFINITION,
      select_ekpo_ekkn REDEFINITION.
 
ENDCLASS.                    "zcl_cda_arch DEFINITION
 
 
**__SELECTION-SCREEN_____________________________________________________*
 
DATA: v_vendor TYPE ekko-lifnr.
 
* Block 1 of selection screen
SELECTION-SCREEN BEGIN OF BLOCK block1 WITH FRAME TITLE text-001.
SELECT-OPTIONS : s_vendor   FOR v_vendor.
SELECTION-SCREEN END OF BLOCK block1.
 
* Display Data Retrieval Options
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-049.
 
PARAMETERS: p_rb_all TYPE c RADIOBUTTON GROUP rd2,
            p_rb_arc TYPE c RADIOBUTTON GROUP rd2 ,
            p_rb_db TYPE c RADIOBUTTON GROUP rd2 DEFAULT 'X'.
 
SELECTION-SCREEN END OF BLOCK b2.
 
**__START-OF-SELECTION_________________________________________________*
 
START-OF-SELECTION.
 
  DATA: o_data    TYPE REF TO zcl_cda_db.
 
  DATA: lo_data_a  TYPE REF TO zcl_cda_arch.
 
  IF p_rb_db  = 'X'.
    CREATE OBJECT o_data.
  ENDIF.
 
  IF p_rb_arc = 'X'.
    CREATE OBJECT o_data
      TYPE zcl_cda_arch.
  ENDIF.
 
  IF p_rb_all = 'X'.
    CREATE OBJECT lo_data_a.
    CREATE OBJECT o_data
      EXPORTING
        io_next = lo_data_a.
  ENDIF.
 
  o_data->get_data( ).
 
*
CLASS zcl_cda_db IMPLEMENTATION.
*
  METHOD constructor.
    o_decorator = io_next.
  ENDMETHOD.                    "constructor
*
  METHOD get_data.
 
    " data from data source
    me->select_ekko(  ).
    me->select_ekpo_ekkn( ).
 
    " merge data from decorator objects into here
    me->merge_data( ).
 
    "Always from primary data source
    me->select_vendor_names( ).
 
    "fill up the final table
    me->fill_final_table( ).
 
  ENDMETHOD.                    "get_Data
*
  METHOD select_ekko.
 
    SELECT       ebeln
                 bukrs
                 bsart
                 lifnr
                 waers
                 submi
            INTO TABLE me->i_ekko
            FROM ekko
            WHERE lifnr IN s_vendor[].
 
    CHECK o_decorator IS BOUND.
    o_decorator->select_ekko( ).
 
 
  ENDMETHOD.                    "select_ekko
*
  METHOD select_ekpo_ekkn.
 
 
    SELECT        ekpo~ebeln
                  ekpo~ebelp
                  ekpo~matnr
                  ekpo~bukrs
                  ekpo~werks
                  ekpo~menge
                  ekpo~netwr
                  ekkn~ps_psp_pnr
                  eket~eindt
                  ekpo~mwskz
                  ekpo~loekz
            INTO TABLE me->i_ekpo
            FROM ekpo
              JOIN ekkn
                ON ( ekpo~ebeln =  ekkn~ebeln
                 AND ekpo~ebelp =  ekkn~ebelp  )
              JOIN eket
                ON  ( ekpo~ebeln =  eket~ebeln
                  AND ekpo~ebelp =  eket~ebelp  )
            FOR ALL ENTRIES IN i_ekko
            WHERE ekpo~ebeln EQ i_ekko-ebeln.
 
    CHECK o_decorator IS BOUND.
    o_decorator->select_ekpo_ekkn(  ).
 
  ENDMETHOD.                    "select_ekpo_ekkn
*
  METHOD merge_data.
 
    CHECK o_decorator IS BOUND.
    APPEND LINES OF: o_decorator->i_ekko TO me->i_ekko,
                     o_decorator->i_ekpo TO me->i_ekpo.
 
  ENDMETHOD.                    "merge_data
*
  method select_vendor_names.
    "get NAME1 from LFA1 for all entries in I_EKKO
  ENDMETHOD.
*
  method fill_final_Table.
    "move data from all tables into final table for display
  ENDMETHOD.
ENDCLASS.                    "zcl_cda_db IMPLEMENTATION
*
CLASS zcl_cda_arch IMPLEMENTATION.
*
  METHOD constructor.
    super->constructor( io_next ).
  ENDMETHOD.                    "constructor
*
  METHOD select_ekko.
 
    DATA: tab93 TYPE STANDARD TABLE OF ekko.
    DATA: ls_tab93 LIKE LINE OF tab93.
    DATA: ls_ekko  LIKE LINE OF me->i_ekko.
 
    CALL FUNCTION '/PBS/SELECT_INTO_TABLE'
      EXPORTING
        archiv     = 'CMM'
        option     = "
        tabname    = 'EKKO'
        clr_itab   = 'X'
        schl1_name = 'LIFNR'
      TABLES
        i_tabelle  = tab93
        schl1_in   = s_vendor[]
      EXCEPTIONS
        eof        = 4
        OTHERS     = 2.
    LOOP AT tab93 INTO ls_tab93.
      MOVE ls_tab93-ebeln TO ls_ekko-ebeln .
      MOVE ls_tab93-bukrs TO ls_ekko-bukrs .
      MOVE ls_tab93-bsart TO ls_ekko-bsart .
      MOVE ls_tab93-lifnr TO ls_ekko-lifnr .
      MOVE ls_tab93-waers TO ls_ekko-waers .
      MOVE ls_tab93-submi TO ls_ekko-submi .
      APPEND ls_ekko TO me->i_ekko .
    ENDLOOP.
    DESCRIBE TABLE me->i_ekko LINES sy-tfill.
    IF sy-tfill GT 0. sy-subrc = 0. ENDIF.
 
  ENDMETHOD.                    "select_ekko
 
  METHOD select_ekpo_ekkn.
 
    "similarly select the data from PBS
    "for the tables EKPO, EKET, EKKN
 
  ENDMETHOD.                    "select_ekpo_ekkn
 
ENDCLASS.                    "zcl_cda_arch IMPLEMENTATION
 

When RB_ALL is selected and primary DB object is being instantiated

Program_Debug_1

When method SELECT_EKKO is being called

Program_Debug_2

Do let me know your thoughts in the comments.

Further Reading

Explore all other Design patterns..

Like It? Share!!

Don't miss an Update

Get notified of the new post, right into your inbox

Naimesh Patel{273 articles}

I'm SAP ABAP Consultant for more than a decade. I like to experiment with ABAP especially OO. I have been SDN Top Contributor.
Follow :

Explore all of his 273 articles.

Load comments

12 Comments

  • Mohinder

    Awesome presentation as always. Thanks for sharing.

    Regards
    Mohinder

  • Mohinder

    Awesome presentation as always. Thanks for sharing.

    Regards
    Mohinder

  • José Jaimes

    Hi Naimesh.

    Thx for the info.

    I would like to know how do you use the Function “‘/PBS/SELECT_INTO_TABLE”. Maybe do you install an extra software to available that function?

    I’ll appreciate your comments about it.

  • Hello Jose,

    PBS is archiving add-on for SAP. You can find more on it at – PBS Add on SAP

    Thanks.

  • Clemens Li

    Hi Naimesh,

    excellent as almost always.
    Your motivation and energy appreciated.
    Now my 2 cents: Not 100 % in line with oo design and reuse idea is the direct use of selection screen values as parameters and select-option ranges inside local class methods.

    OK, I know the effort to create setter and getter methods just for them is not justified at all.
    Just to ensure modularity and have qick generation times I create my classes as global dictionary classes.
    For access to selection-screen values I use the dynamic assign. SAP warns since almost 20 years (probably since R/3 and ABAP) not to use it as it may be changed incompatible at any time.
    I expect no change before the end of the world, later I don’t care.

    Now see my methods to access parameters and select-option range tables:

    selection screen access Class definition

     
      methods GET_PARAMETER_VALUE
        importing
          !IV_PARAMETER_NAME type FELD-NAME
        returning
          value(RV_VALUE) type STRING .
      methods GET_SELECT_OPTION_TABLE
        importing
          !IV_SELECT_OPTION type FELD-NAME
        returning
          value(RT_RANGE) type RSIS_T_RANGE .
      methods SET_PARAMETER_VALUE
        importing
          !IV_PARAMETER_NAME type FELD-NAME
          !IV_VALUE type STRING .
      methods SET_SELECT_OPTION_TABLE
        importing
          !IV_SELECT_OPTION type FELD-NAME
          !IT_RANGE type RSIS_T_RANGE .
     

    selection screen access Class implementation

     
    * ---------------------------------------------------------------------------------------+
    * | Instance Private Method ZCL_ZJL_EIF_MENGEN_SONDER->GET_PARAMETER_VALUE
    * +-------------------------------------------------------------------------------------------------+
    * | [--->] IV_PARAMETER_NAME              TYPE        FELD-NAME
    * | [<-()] RV_VALUE                       TYPE        STRING
    * +-------------------------------------------------------------------------------------
    METHOD GET_PARAMETER_VALUE.
      DATA:
        lv_assign TYPE string.
      FIELD-SYMBOLS:
             TYPE any.
      lv_assign = '(' && sy-cprog && ')' && iv_parameter_name.
      ASSIGN (lv_assign) TO .
      ASSERT sy-subrc = 0.
      rv_value = .
    ENDMETHOD.
    * ---------------------------------------------------------------------------------------+
    * | Instance Private Method ZCL_ZJL_EIF_MENGEN_SONDER->GET_SELECT_OPTION_TABLE
    * +-------------------------------------------------------------------------------------------------+
    * | [--->] IV_SELECT_OPTION               TYPE        FELD-NAME
    * | [<-()] RT_RANGE                       TYPE        RSIS_T_RANGE
    * +-------------------------------------------------------------------------------------
    METHOD GET_SELECT_OPTION_TABLE.
      DATA:
        lv_assign TYPE string.
      FIELD-SYMBOLS:
             TYPE table,
             TYPE any,
                 TYPE any,
               TYPE any,
                  TYPE any,
                 TYPE any,
              TYPE LINE OF rsis_t_range.
      lv_assign = '(' && sy-cprog && ')' && iv_select_option && '[]'.
      ASSIGN (lv_assign) TO .
      ASSERT sy-subrc = 0.
      LOOP AT  ASSIGNING .
        APPEND INITIAL LINE TO rt_range ASSIGNING .
        ASSIGN COMPONENT 'SIGN'   OF STRUCTURE   TO .
        ASSIGN COMPONENT 'OPTION' OF STRUCTURE   TO .
        ASSIGN COMPONENT 'LOW'    OF STRUCTURE   TO .
        ASSIGN COMPONENT 'HIGH'   OF STRUCTURE   TO .
        -sign   = .
        -option = .
        -low    = .
        -high   = .
      ENDLOOP.
    ENDMETHOD.
    * ---------------------------------------------------------------------------------------+
    * | Instance Private Method ZCL_ZJL_EIF_MENGEN_SONDER->SET_PARAMETER_VALUE
    * +-------------------------------------------------------------------------------------------------+
    * | [--->] IV_PARAMETER_NAME              TYPE        FELD-NAME
    * | [--->] IV_VALUE                       TYPE        STRING
    * +-------------------------------------------------------------------------------------
    METHOD SET_PARAMETER_VALUE.
      DATA:
        lv_assign TYPE string.
      FIELD-SYMBOLS:
             TYPE any.
      lv_assign = '(' && sy-cprog && ')' && iv_parameter_name.
      ASSIGN (lv_assign) TO .
      ASSERT sy-subrc = 0.
       = iv_value.
    ENDMETHOD.
    * ---------------------------------------------------------------------------------------+
    * | Instance Private Method ZCL_ZJL_EIF_MENGEN_SONDER->SET_SELECT_OPTION_TABLE
    * +-------------------------------------------------------------------------------------------------+
    * | [--->] IV_SELECT_OPTION               TYPE        FELD-NAME
    * | [--->] IT_RANGE                       TYPE        RSIS_T_RANGE
    * +-------------------------------------------------------------------------------------
    METHOD set_select_option_table.
      DATA:
        lv_assign TYPE string.
      FIELD-SYMBOLS:
             TYPE table,
                TYPE LINE OF rsis_t_range,
             TYPE any,
                 TYPE any,
               TYPE any,
                  TYPE any,
                 TYPE any,
              TYPE LINE OF rsis_t_range.
      lv_assign = '(' && sy-cprog && ')' && iv_select_option && '[]'.
      ASSIGN (lv_assign) TO .
      ASSERT sy-subrc = 0.
      CLEAR .
      LOOP AT it_range ASSIGNING .
        APPEND INITIAL LINE TO  ASSIGNING .
        ASSIGN COMPONENT 'SIGN'   OF STRUCTURE   TO .
        ASSIGN COMPONENT 'OPTION' OF STRUCTURE   TO .
        ASSIGN COMPONENT 'LOW'    OF STRUCTURE   TO .
        ASSIGN COMPONENT 'HIGH'   OF STRUCTURE   TO .
            = -sign.
          = -option.
             = -low.
            = -high.
      ENDLOOP.
    ENDMETHOD.
     

    The GET methods are used whenever values from selection screen are used. The SET methods are useful for INITIALIZATION methods called in INITIALIZATION event of report.

    Here some code samples of how the methods may be used.

    implementation samples

     
    * This is used in industry solution media, you may adapt to your needs...
    * ---------------------------------------------------------------------------------------+
    * | Instance Private Method ZCL_ZVZU_ABR_EXTRACT->SELECT_JVTLFNG
    * +-------------------------------------------------------------------------------------------------+
    * +-------------------------------------------------------------------------------------
    METHOD select_jvtlfng.
      DATA:
        lt_r_bezirk             TYPE rsis_t_range,
        lt_r_bezrun             TYPE rsis_t_range,
        lt_r_erschd             TYPE rsis_t_range,
        lt_r_gprech             TYPE rsis_t_range,
        lt_r_gp_ers             TYPE rsis_t_range,
        lt_r_hauptp             TYPE rsis_t_range,
        lt_r_herkun             TYPE rsis_t_range,
        lt_r_kalsm              TYPE rsis_t_range,
        lt_r_normmn             TYPE rsis_t_range,
        lt_r_objekt             TYPE rsis_t_range,
        lt_r_pernr              TYPE rsis_t_range,
        lt_r_pvatat             TYPE rsis_t_range,
        lt_r_vsg                TYPE rsis_t_range,
        lt_r_zustel             TYPE rsis_t_range.
      field-symbols:
              type ZVZU_ABR_EXTRACT.
      lt_r_herkun = get_select_option_table( 'S_HERKUN' ).
    * Herkunft selektiert?
      CHECK MC_HERKUNFT_JVTLFNG IN lt_r_herkun.
     
      lt_r_bezirk  = get_select_option_table( 'S_BEZIRK' ).
      lt_r_bezrun  = get_select_option_table( 'S_BEZRUN' ).
      lt_r_erschd  = get_select_option_table( 'S_ERSCHD' ).
      lt_r_gprech  = get_select_option_table( 'S_GPRECH' ).
      lt_r_gp_ers  = get_select_option_table( 'S_GP_ERS' ).
      lt_r_hauptp  = get_select_option_table( 'S_HAUPTP' ).
      lt_r_herkun  = get_select_option_table( 'S_HERKUN' ).
      lt_r_kalsm   = get_select_option_table( 'S_KALSM ' ).
      lt_r_normmn  = get_select_option_table( 'S_NORMMN' ).
      lt_r_objekt  = get_select_option_table( 'S_OBJEKT' ).
      lt_r_pernr   = get_select_option_table( 'S_PERNR ' ).
      lt_r_pvatat  = get_select_option_table( 'S_PVATAT' ).
      lt_r_vsg     = get_select_option_table( 'S_VSG   ' ).
      lt_r_zustel  = get_select_option_table( 'S_ZUSTEL' ).
     
      select *
        appending corresponding fields of table mt_ZVZU_ABR_EXTRACT
          from JVTLFNG
          where erschdat          IN lt_r_erschd
            and bezirktat         IN lt_r_bezirk
            and bezrundtat        IN lt_r_bezrun
            and pvatat            IN lt_r_pvatat
            and objektgruppe      IN lt_r_objekt
            and zusteller         IN lt_r_zustel
            and gp_ers            IN lt_r_gp_ers
            and vsg               IN lt_r_vsg
            and kalsm             IN lt_r_kalsm
            and pernr             IN lt_r_pernr
            and gprech            IN lt_r_gprech
    *        and hauptplz          IN lt_r_hauptp
            and normmngizu        IN lt_r_normmn ##TOO_MANY_ITAB_FIELDS.
    ENDMETHOD.
    * ---------------------------------------------------------------------------------------+
    * | Instance Public Method ZCL_ZJL_EIF_MENGEN_SONDER->INITIALIZATION
    * +-------------------------------------------------------------------------------------------------+
    * +-------------------------------------------------------------------------------------
    METHOD initialization.
      DATA:
        lt_range         TYPE rsis_t_range.
      FIELD-SYMBOLS:
           TYPE rsis_s_range.
    * Bezirk selection pre-set with pattern BEZ99*
      APPEND INITIAL LINE TO lt_range ASSIGNING .
       = 'ICP'.
      -low = 'BZ99*'.
      set_select_option_table(
        iv_select_option = 'S_BEZIRK'
        it_range         = lt_range ).
    ENDMETHOD.
     

    The calling report has just the parameters and select-options and the events initialization and start-of-selection.
    In initialization I have a CREATE OBJECT and a ->initialization( ).
    start-of-selection has the method call ->start_of_selection( ).

    I’d like to hear what you think about this approach.

    Thank you and best regards, Clemens

  • Clemens Li

    Hi folks,

    sorry the code formatter crunched my field-symbols. They are obvously confued with html tags. So the code is not syntactically correct and hard to understand. When I know the solution, I will post the code in human and machine-readable form.
    Regards, Clemens

  • Kesav

    Hi Clemens,

    Hope your are doing great :-)

    I feel that Naimesh purposefully didn’t handle the selection option here because the sole intention was to explain about fetching data from multiple data sources using OO pattern, There are few posts already in his blogs which explains the way of handling the selection screen variables in OO.

    By the way, I use a different method of handling the selection screen values, in a separate screen handler class I use the function RS_REFRESH_FROM_SELECTOPTIONS and build the values internally, then at later point access those values using public methods. For simplicity, I always pass the screen values via constructor and store it in attributes of class.

    BR
    Kesav

  • Hello Kesav,

    I’ll take the liberty to reply to your comment.

    Yes, you are right that I deliberately used the select options in the classes as my main idea was to show the different data source selection. As you have pointed out the selection screen related class based design can be found in ABAP Object Oriented Approach for Reports – Redesign.

    I would love to see your design using the FM and see how it in action.

    Thanks,
    Naimesh Patel

  • Jani80k

    Here is my implementation using the Function Module Kesav mentioned. I do not use get and set-methods because the select-options are set class-internally and can be gotten as read only attributes.

     
    CLASS lcl_selopts DEFINITION FINAL.
     
      PUBLIC SECTION.
     
        DATA gt_selopts TYPE STANDARD TABLE OF rsparams WITH KEY selname READ-ONLY.
     
        DATA gt_banfn TYPE RANGE OF banfn READ-ONLY.
     
        DATA gt_ernam TYPE RANGE OF ernam READ-ONLY.
     
        DATA gt_badat TYPE RANGE OF badat READ-ONLY.
     
        DATA gt_erdat TYPE RANGE OF erdat READ-ONLY.
     
        DATA gt_afnam TYPE RANGE OF afnam READ-ONLY.
     
        DATA gv_frrel TYPE mmpur_bool READ-ONLY.
     
        DATA gv_frpoc TYPE mmpur_bool READ-ONLY.
     
        DATA gv_frrej TYPE mmpur_bool READ-ONLY.
     
        METHODS constructor RAISING lcx_abs_exception.
     
        METHODS refresh RAISING lcx_abs_exception.
     
      PRIVATE SECTION.
     
        METHODS get_selopts RAISING lcx_abs_exception.
     
        METHODS set_defaults.
     
    ENDCLASS.                    "lcl_selopts DEFINITION
     
    *----------------------------------------------------------------------*
    *       CLASS lcl_selopts IMPLEMENTATION
    *----------------------------------------------------------------------*
    *
    *----------------------------------------------------------------------*
    CLASS lcl_selopts IMPLEMENTATION.
     
      METHOD constructor.
        me->get_selopts( ).
        me->set_defaults( ).
      ENDMETHOD.                    "constructor
     
      METHOD get_selopts.
        CALL FUNCTION 'RS_REFRESH_FROM_SELECTOPTIONS'
          EXPORTING
            curr_report     = sy-repid
          TABLES
            selection_table = gt_selopts
          EXCEPTIONS
            not_found       = 1
            no_report       = 2
            OTHERS          = 3.
        IF sy-subrc  0.
          RAISE EXCEPTION TYPE lcx_exception EXPORTING im_message = 'No Select Options.'(902).
        ENDIF.
     
        DATA lr_selopt TYPE REF TO rsparams.
     
        FIELD-SYMBOLS  LIKE LINE OF gt_banfn.
        FIELD-SYMBOLS  LIKE LINE OF gt_ernam.
        FIELD-SYMBOLS  LIKE LINE OF gt_badat.
        FIELD-SYMBOLS  LIKE LINE OF gt_erdat.
        FIELD-SYMBOLS  LIKE LINE OF gt_afnam.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'S_BANFN' REFERENCE INTO lr_selopt.
     
        IF sy-subrc EQ 0 AND lr_selopt->option IS NOT INITIAL.
          APPEND INITIAL LINE TO gt_banfn ASSIGNING .
          MOVE-CORRESPONDING lr_selopt->* TO .
        ENDIF.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'S_ERNAM' REFERENCE INTO lr_selopt.
     
        IF sy-subrc EQ 0 AND lr_selopt->option IS NOT INITIAL.
          APPEND INITIAL LINE TO gt_ernam ASSIGNING .
          MOVE-CORRESPONDING lr_selopt->* TO .
        ENDIF.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'S_BADAT' REFERENCE INTO lr_selopt.
     
        IF sy-subrc EQ 0 AND lr_selopt->option IS NOT INITIAL.
          APPEND INITIAL LINE TO gt_badat ASSIGNING .
          MOVE-CORRESPONDING lr_selopt->* TO .
        ENDIF.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'S_ERDAT' REFERENCE INTO lr_selopt.
     
        IF sy-subrc EQ 0 AND lr_selopt->option IS NOT INITIAL.
          APPEND INITIAL LINE TO gt_erdat ASSIGNING .
          MOVE-CORRESPONDING lr_selopt->* TO .
        ENDIF.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'S_AFNAM' REFERENCE INTO lr_selopt.
     
        IF sy-subrc EQ 0 AND lr_selopt->option IS NOT INITIAL.
          APPEND INITIAL LINE TO gt_afnam ASSIGNING .
          MOVE-CORRESPONDING lr_selopt->* TO .
        ENDIF.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'P_FRREL' REFERENCE INTO lr_selopt.
        gv_frrel = lr_selopt->low.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'P_FRREJ' REFERENCE INTO lr_selopt.
        gv_frrej = lr_selopt->low.
     
        READ TABLE gt_selopts WITH TABLE KEY selname = 'P_FRPOC' REFERENCE INTO lr_selopt.
        gv_frpoc = lr_selopt->low.
      ENDMETHOD.                    "get_selopts
     
      METHOD set_defaults.
        FIELD-SYMBOLS  LIKE LINE OF gt_ernam.
        APPEND INITIAL LINE TO gt_ernam ASSIGNING .
        -sign   = 'I'.
        -option = 'EQ'.
        -low = sy-uname.
     
        FIELD-SYMBOLS  LIKE LINE OF gt_erdat.
        APPEND INITIAL LINE TO gt_erdat ASSIGNING .
        -low    = sy-datum - 7.
        -high   = sy-datum.
        -sign   = 'I'.
        -option = 'BT'.
      ENDMETHOD.                    "set_defaults
     
      METHOD refresh.
        CLEAR: gt_selopts, gt_banfn, gt_ernam, gt_badat,gt_erdat, gt_afnam, gv_frrel,gv_frpoc, gv_frrej.
        get_selopts( ).
      ENDMETHOD.                    "refresh
    ENDCLASS.                    "lcl_selopts IMPLEMENTATION
     
  • Hello Jani80K,

    Apologies for Field Symbol is being disappeared from this comment and thanks for providing your code lines.

    The implementation looks promising. I would try to publish as separate code lines so the FS are not removed.

    Thanks,
    Naimesh Patel

  • […] to Clemens Li for sharing this utility class in his comment on the article Object Oriented Approach for Reports with multiple […]

  • […] object. Keshav and Jani80k has suggested that we also can use the FM RS_REFRESH_FROM_SELECTOPTIONS. Jani80K provided the implementation as well in the article Object Oriented Approach for Reports with […]

Comments on this Post are now closed. If you have something important to share, you can always contact me.

You seem to be new here. Subscribe to stay connected.