Monday 4 March 2019

Report Creator

Introduction


Oftentimes, access to SE16 or SE16n is not granted to SAP end-users. This program would allow an analyst to configure their own reports by pointing to existing CDS Views, Views or SAP Tables without writing code. They configure their selection screens by importing an Excel spreadsheet. Lastly, create an SAP Transaction code which points to the report and assign certain users’ authorization to the new transaction. This program is suitable for those SAP installs with HANA.

In my previous blog, here…

http://sapabapcentral.blogspot.com/2018/10/dynamic-selection-screen-with-alv-ida.html

…we combined an Excel upload, Dynamic Select Option generation, displayed on a Popup Screen and showed the results in ALV IDA created for HANA. To fully understand this Blog, it is recommended that you read the above Blog, first. However, if you want to skip the details, just go to the “Program Walkthrough” section below, see how it works, then get the code.

In this blog, we will enhance this program from the above blog, to make it re-runnable without re-importing the Excel file each time. We will also add a new column, where you may specify a Transaction Code, to allow the program to dynamically generate the report based on the Transaction Code entered and store many reports in your configuration table.

Software Versions:

◈ S/4HANA (SAP_BASIS 752, SAP_ABA 75C)
◈ SAPGUI Version 750
◈ Eclipse Version: Oxygen.3a Release (4.7.3a)
◈ Microsoft Excel (.xlsx capable)

Program Overview


Original Program Flow Diagram

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

New Program Flow Diagram

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Excel File Format

The Excel file will contain either a Table, View or CDS View with the fields that you’d like to appear as Select-Options on your popup window. As an enhancement to the previous program, we will add a new row for a Transaction Code. This will allow us to execute the report via transaction code, without re-loading an Excel spreadsheet each time. In addition, we can store the configuration settings for many reports and their corresponding transaction codes.

Example Excel file with 3 reports:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Column A will contain 3 labels for each report:

◈ Transaction Code
◈ Table, View or CDS View Name
◈ Selection Fields

Column B contains the actual Transaction Code, Table/View/CDS View name and a list of the fields you want to be included as Select Options on the Popup window.

For example, the first report:

◈ B1 = The Custom SAP Transaction Code
◈ B2 = Table, View or CDS View Name
◈ B3+ = List of fields to be included as Select Options

For the CDS View “S_BOOKINGS”, include the fields CARRIERID, FLIGHTDATE, CUSTOMERID, LOCALCURRENCYAMOUNT on the popup window as Select-Options whenever we execute the custom SAP Transaction code ZBOOKINGS.

The popup window for the above, would look like the following:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

New Enhancements


New Z Table

First, to support these new features, let’s create a new Z Table, which will hold the configuration for the reports. For a single report, our Excel input has the following format:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Let’s flatten out the structure, to create a schema, like the following:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

You could go to SE11 and create the table in the classical manner. In the spirit of utilizing the latest tools, let’s use the Eclipse IDE with the ABAP Development Tools (ADT):

From your project explorer, right-click on the “Dictionary” node and the menu path “New > Database Table”

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Enter the following and click “Finish”:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Note, you may choose a different table name, other than ZREPORT. If so, you can simply update this table name, wherever it is referenced in the code.

We now get a general template for a new table:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Overwrite the above with the following data definition:

@EndUserText.label : 'Instant Report Configuration'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_CHARACTER_NUMERIC
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #LIMITED
define table zreport {
  key mandt           : mandt not null;
  key tcode           : sytcode not null;
  key view_or_table   : ddlname not null;
  key selection_field : fieldname not null;
}

Save and Activate

You can now go to SE11, and view the above table we just created:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

To view the data in our table, we could go to our Eclipse Project Explorer, right-click on the table name and the menu path “Open with > Data Preview”:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Of course, our table is currently empty, but later we can view our imported records here:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

In addition to the above, create a table type named ZTTY_REPORT that contains the above as line type ZREPORT:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

We will use this table type ZTTY_REPORT in our method parameters, for better readability.

New Methods and Code

Next, let’s add the additional code required for our program.

First, we’ll need some new select options on the screen to support our new functionality. Our new selection screen will be:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

The options will perform the following:

Run the Report Only: The report will run by reading the existing configuration table entries in ZREPORT for the Transaction Code entered. If selected, we will hide the “Excel SelOpt File” and “Refresh Table (all entries)” parameters.

Update the Table Only: The Excel File will be read, and the table ZREPORT will be updated. If selected, we will hide the “Transaction Code” selection parameter.

Update Table and Run Report: Execute both of the above options – Update the table and run the report for whatever transaction code is entered.

Refresh Table (all entries):

◈ Checked: If the checkbox is enabled, all entries in the ZREPORT table will first be deleted. Next, all entries in the Excel File will be inserted. That is, a complete refresh from the Excel file.
◈ Unchecked: If the checkbox is disabled – If entries in the Excel file don’t yet exist in the ZREPORT table, they will be inserted (i.e. add a new report). If the entries already exist, they will be updated (overwritten) with the corresponding entry.

The New Selection Screen Code is:

REPORT z_instant_report.
TABLES: zreport.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE mn_lbl.
PARAMETERS: rb_run  RADIOBUTTON GROUP gr1 DEFAULT 'X' USER-COMMAND cmd,
            rb_load RADIOBUTTON GROUP gr1,
            rb_both RADIOBUTTON GROUP gr1.
SELECT-OPTIONS: s_tcode FOR zreport-tcode MODIF ID cfg NO INTERVALS NO-EXTENSION.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE fil_lbl.
PARAMETERS: p_refr  AS CHECKBOX MODIF ID lod,
            p_ifile TYPE localfile MODIF ID lod DEFAULT 'c:\1\SeloptFile_ZREPORT.xlsx'.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN END OF BLOCK b2.

In the INITIALIZATION section, add the labels for the new selection screen elements:

INITIALIZATION.
  %_p_ifile_%_app_%-text = 'Excel SelOpt File'.
  fil_lbl = 'Excel Input File'.
  mn_lbl  = 'Program Options'.
  %_rb_run_%_app_%-text  = 'Run the Report Only'.
  %_rb_load_%_app_%-text = 'Update the Table Only'.
  %_rb_both_%_app_%-text = 'Update Table and Run Report'.
  %_p_refr_%_app_%-text  = 'Refresh Table (all entries)'.
  %_s_tcode_%_app_%-text = 'Transaction Code'.

Depending on which radio button we select, let’s hide the selections that are not relevant. After the INITIALIZATION event, add the new event “AT SELECTION-SCREEN OUTPUT” to the program and add the following code:

AT SELECTION-SCREEN OUTPUT.
  IF rb_run = abap_true. "Report Only
    LOOP AT SCREEN.
      IF screen-group1 = 'LOD'.
        screen-active = '0'. "Hide
        MODIFY SCREEN.
      ENDIF.
      IF screen-group1 = 'CFG'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
    ENDLOOP.
  ELSEIF rb_load = abap_true. "Update Table only
    LOOP AT SCREEN.
      IF screen-group1 = 'LOD'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
      IF screen-group1 = 'CFG'.
        screen-active = '0'. "Hide
        MODIFY SCREEN.
      ENDIF.
    ENDLOOP.
  ELSEIF rb_both = abap_true. "Update Table and Run Report
    LOOP AT SCREEN.
      IF screen-group1 = 'LOD'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
      IF screen-group1 = 'CFG'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
    ENDLOOP.
  ENDIF.

In our original program, we simply passed the Excel file and the report was run with the following call:

NEW lcl_dynamic_sel( )->execute( CONV string( p_ifile ) ).

To support our new options, let’s add a new structure that may be passed to the execute method. In the public section of the class, add the following code:

CLASS lcl_dynamic_sel DEFINITION CREATE PUBLIC FINAL.
  PUBLIC SECTION.
    CONSTANTS: c_excel TYPE string VALUE 'Excel files(*.xlsx)|*.xlsx'.
    TYPES: BEGIN OF lty_selopts,
             filename     TYPE string,
             tcode        TYPE sytcode,
             refresh      TYPE boolean,
             run_only     TYPE boolean,
             load_only    TYPE boolean,
             run_and_load TYPE boolean,
           END OF lty_selopts.

Rename the import parameter for the execute method and use this type:

    METHODS:
      execute
        IMPORTING im_selopts type lty_selopts.

Adjust the call to the following for the execute method:

START-OF-SELECTION.
  NEW lcl_dynamic_sel( )->execute( value #( 
      filename     = CONV string( p_ifile )    
      tcode        = s_tcode-low
      refresh      = p_refr
      run_only     = rb_run  
      load_only    = rb_load
      run_and_load = rb_both ) ).

We will have 2 entry points for this class, the EXECUTE method and the EXECUTE_REPORT method.

New EXECUTE Method:

Here is the code for our new execute method:

  METHOD execute. "Called from the Selection Screen...
    IF im_selopts-run_only = abap_true.
      run_report( get_config_table( im_selopts-tcode ) ).
    ELSEIF im_selopts-load_only = abap_true.
      update_config_data( it_config  = get_excel_data( im_selopts-filename )
                          im_refresh = im_selopts-refresh ).
    ELSEIF im_selopts-run_and_load = abap_true.
      update_config_data( it_config  = get_excel_data( im_selopts-filename )
                          im_refresh = im_selopts-refresh ).
      run_report( get_config_table( im_selopts-tcode ) ).
    ENDIF.
  ENDMETHOD. "execute

This method is called when running the program from the regular selection screen (i.e. SE38).

New EXECUTE_REPORT Method:

This method is called whenever a Transaction code is entered by the user. It will then auto-launch the report by reading the config table for that TCode. The code for this method is:

  METHOD execute_report. "Called from a TCode...
    NEW lcl_dynamic_sel( )->execute( VALUE #( tcode    = sy-tcode
                                              run_only = abap_true ) ).
  ENDMETHOD. "execute_report

We simply instantiate the report, but with only the TCode and run_only options.

See the complete program for all other changes, including the following methods:

BUILD_SELECT_OPTIONS: Adjust this method to handle a table, rather than the Excel spreadsheet.

GET_CONFIG_TABLE : A new method to fetch the contents of the configuration table (ZREPORT), to be passed to the updated BUILD_SELECT_OPTIONS method.

EXECUTE_REPORT: A new public class method, which will allow the program to be executed from a Transaction Code. We will walkthrough this setup later.

UPDATE_CONFIG_DATA: A new method to update the ZREPORT configuration table, after reading the Excel input file.

RUN_REPORT: Our original EXECUTE method is renamed to this method. Our new EXECUTE method will evaluate the select options, and execute the various methods, see below.

Program Walkthrough


Initial Setup

The program will give you the ability to setup a transaction code, in order to launch a report that you’ve stored in your ZREPORT configuration table. This enables you to also setup authorizations for that transaction code, assign to certain users, etc. First, let’s setup a new transaction code for each of our 3 reports, as follows. We can create a transaction code, which executes a method within a local class of a program (doesn’t have to be a global class!). Here are the steps:

Execute the transaction SE93 and enter the Transaction ZBOOKINGS and click “Create”:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Enter a description for your report and select the option “Method of a class (OO transaction)” and click Continue:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Uncheck the “OO transaction model”, and a new field will appear, which will allow you to specify a local method in our program. Enter the following:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Notice that since we are simply pointing to our method, we can easily copy the above TCode twice and name them ZMARA and ZFINANCE.

From SE93, enter the ZBOOKINGS Transaction Code and click the copy button:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Repeat the above for ZFINANCE. That’s it! Nothing to change in these copied TCodes, because the EXECUTE_REPORT method looks at sy-tcode to see which report to run:

  METHOD execute_report. "Called from a TCode...
    NEW lcl_dynamic_sel( )->execute( VALUE #( tcode    = sy-tcode
                                              run_only = abap_true ) ).
  ENDMETHOD. "execute_report

As you may have guessed, if you always run the program from the standard selection screen (i.e. via SE38), you could execute various reports without ever creating an actual TCode in SE93.

Running the Report

Let’s walk through the program and see how it works…

The first screen has the following select options:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

As mentioned earlier, some of the above options will be hidden, depending on which radio button you select. The default will look like the following:

Run the Report Only (Option 1):

The default selection screen will look like the following:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Enter one of our transaction codes from earlier, for example ZBOOKINGS:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Execute the program (F8), and you will get the following pop-up selections:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

These are the 4 select options we specified in the ZREPORT table earlier:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Execute the selection pop-up and see the results of the CDS view:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

The above method of executing the program, enters via the EXECUTE method.

Now, let’s enter the SAP Transaction ZBOOKINGS directly from the TCode box (enter /NZBOOKINGS and hit enter):

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

You will now get the same pop-up and results as above:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

This method of executing the program checks our setup for the TCode in SE93, and calls the EXECUTE_REPORT method in our program:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Try out the ZMARA and ZFINANCE TCodes to see the reports we have setup:

ZMARA:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Selection Screen:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

ZFINANCE:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Selection Screen:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Update the Table Only (Option 2):

When selecting the second radio button, you will get the following screen:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

This screen will enable you to read an Excel file (format discussed earlier), and update the ZREPORT table. The checkbox “Refresh Table (all entries):”, will delete all entries in the ZREPORT table, and replace them will those entries in the Excel spreadsheet. If you leave this unchecked, only entries in the Excel Spreadsheet will be updated (for records that already exist) or inserted (for new records).

When executing with our Excel file from early, you will get the following pop-up message telling you that the 14 entries have been updated in the ZREPORT table:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

If you also selected the “Refresh…” option, an additional pop-up message will tell you the table was completely refreshed.

Update Table and Run Report (Option 3):

When selecting the 3rd radio button, you will get the following screen:

ABAP Development, SAP HANA,  ABAP CDS View, SAP ABAP Learning

Just as it says, it will execute both options, first updating the ZREPORT table, then executing the specified Transaction Code (i.e. ZBOOKINGS).

Complete Program


REPORT z_instant_report.
TABLES: zreport.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE mn_lbl.
PARAMETERS: rb_run  RADIOBUTTON GROUP gr1 DEFAULT 'X' USER-COMMAND cmd,
            rb_load RADIOBUTTON GROUP gr1,
            rb_both RADIOBUTTON GROUP gr1.
SELECT-OPTIONS: s_tcode FOR zreport-tcode MODIF ID cfg NO INTERVALS NO-EXTENSION.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE fil_lbl.
PARAMETERS: p_refr  AS CHECKBOX MODIF ID lod,
            p_ifile TYPE localfile MODIF ID lod DEFAULT 'c:\1\SeloptFile_ZREPORT.xlsx'.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN END OF BLOCK b2.

CLASS lcl_dynamic_sel DEFINITION CREATE PUBLIC FINAL.
  PUBLIC SECTION.
    CONSTANTS: c_excel TYPE string VALUE 'Excel files(*.xlsx)|*.xlsx'.
    TYPES: BEGIN OF lty_selopts,
             filename     TYPE string,
             tcode        TYPE sytcode,
             refresh      TYPE boolean,
             run_only     TYPE boolean,
             load_only    TYPE boolean,
             run_and_load TYPE boolean,
           END OF lty_selopts,
           BEGIN OF lty_flabel,
             name TYPE fieldname,
             text TYPE rstxtmd,
           END OF lty_flabel,
           ltty_flabel_tab TYPE SORTED TABLE OF lty_flabel WITH UNIQUE KEY name,
           BEGIN OF lty_selopt,
             name          TYPE string,
             text          TYPE rstxtmd,
             select_option TYPE sci_refdat,
           END OF lty_selopt,
           ltty_selopt TYPE STANDARD TABLE OF lty_selopt.
    CLASS-METHODS:
      select_file
        IMPORTING i_filename     TYPE string
                  i_type         TYPE string
        RETURNING VALUE(re_file) TYPE localfile,
      execute_report.
    METHODS:
      execute
        IMPORTING im_selopts TYPE lty_selopts.
  PRIVATE SECTION.
    METHODS:
      get_excel_data
        IMPORTING im_file         TYPE string
        RETURNING VALUE(rt_table) TYPE ztty_report,
      get_field_labels
        IMPORTING im_tabview      TYPE string
        EXPORTING et_field_labels TYPE ltty_flabel_tab
                  e_cds_view      TYPE boolean,
      build_select_options
        IMPORTING it_config       TYPE ztty_report
        EXPORTING e_cds_view_name TYPE ddlname
                  et_selopts      TYPE ltty_selopt
                  e_cds_view      TYPE boolean,
      update_config_data
        IMPORTING it_config  TYPE ztty_report
                  im_refresh TYPE boolean,
      get_config_table
        IMPORTING im_tcode        TYPE sytcode
        RETURNING VALUE(rt_table) TYPE ztty_report,
      run_report
        IMPORTING it_config TYPE ztty_report.
ENDCLASS. "lcl_dynamic_sel

CLASS lcl_dynamic_sel IMPLEMENTATION.
  METHOD execute_report. "Called from a TCode...
    NEW lcl_dynamic_sel( )->execute( VALUE #( tcode    = sy-tcode
                                              run_only = abap_true ) ).
  ENDMETHOD. "execute_report

  METHOD execute. "Called from the Selection Screen...
    IF im_selopts-run_only = abap_true.
      run_report( get_config_table( im_selopts-tcode ) ).
    ELSEIF im_selopts-load_only = abap_true.
      update_config_data( it_config  = get_excel_data( im_selopts-filename )
                          im_refresh = im_selopts-refresh ).
    ELSEIF im_selopts-run_and_load = abap_true.
      update_config_data( it_config  = get_excel_data( im_selopts-filename )
                          im_refresh = im_selopts-refresh ).
      run_report( get_config_table( im_selopts-tcode ) ).
    ENDIF.
  ENDMETHOD. "execute

  METHOD get_config_table.
    IF im_tcode IS INITIAL. RETURN. ENDIF.
    SELECT * INTO TABLE rt_table FROM zreport WHERE tcode = im_tcode.
    IF rt_table[] IS INITIAL.
      MESSAGE |No entries found in ZREPORT table for TCode { im_tcode }.| TYPE 'I'.
    ENDIF.
  ENDMETHOD. "get_config_table

  METHOD update_config_data.
    IF im_refresh = abap_true.
      SELECT * INTO TABLE @DATA(lt_delete) FROM zreport.
      DELETE zreport FROM TABLE lt_delete.
      COMMIT WORK AND WAIT.
      MESSAGE |ZREPORT config table was refreshed (all entries deleted).| TYPE 'I'.
    ELSE.
      DELETE zreport FROM TABLE it_config.
      COMMIT WORK AND WAIT.
    ENDIF.
    INSERT zreport FROM TABLE it_config.
    COMMIT WORK AND WAIT.
    SELECT COUNT( * ) INTO @DATA(lv_count) FROM zreport.
    MESSAGE |{ lv_count } Records loaded to the ZREPORT config table.| TYPE 'I'.
  ENDMETHOD. "update_config_table

  METHOD run_report.
    DATA: lt_popup_selections TYPE sci_atttab.
    IF it_config[] IS INITIAL. RETURN. ENDIF.
    build_select_options( EXPORTING it_config       = it_config
                          IMPORTING e_cds_view_name = DATA(lv_cds_view_name)
                                    et_selopts      = DATA(lt_select_options)
                                    e_cds_view      = DATA(lv_is_cds_view) ).
    IF lv_cds_view_name IS INITIAL. RETURN. ENDIF.
    IF lt_select_options[] IS INITIAL.
      MESSAGE |No selection fields specified for '{ lv_cds_view_name }'.| TYPE 'I'.
      RETURN.
    ENDIF.
    LOOP AT lt_select_options ASSIGNING FIELD-SYMBOL().
      APPEND VALUE #( ref  = -select_option
                      kind = 'S'
                      text = -text )
                      TO lt_popup_selections.
    ENDLOOP.
    DATA(lv_result) = cl_ci_query_attributes=>generic(
      EXPORTING
        p_name       = CONV #( sy-repid )
        p_title      = 'Enter Field Selections'
        p_attributes = lt_popup_selections
        p_display    = abap_false    " General Flag
    ).
    IF lv_result = 'X'. RETURN. ENDIF.

    IF lv_is_cds_view = abap_true.
      DATA(lo_alv_cds) = cl_salv_gui_table_ida=>create_for_cds_view( iv_cds_view_name = CONV dbtabl( lv_cds_view_name ) ).
    ELSE.
      DATA(lo_alv) = cl_salv_gui_table_ida=>create( iv_table_name = CONV dbtabl( lv_cds_view_name ) ).
    ENDIF.
    DATA(lo_collector) = NEW cl_salv_range_tab_collector( ).
    LOOP AT lt_select_options INTO DATA(lw_sel).
      ASSIGN lw_sel-select_option->* TO FIELD-SYMBOL().
      IF  IS NOT INITIAL.
        lo_collector->add_ranges_for_name( iv_name = lw_sel-name it_ranges =  ).
      ENDIF.
      UNASSIGN .
    ENDLOOP.
    lo_collector->get_collected_ranges( IMPORTING et_named_ranges = DATA(lt_name_range_pairs) ).
    IF lv_is_cds_view = abap_true.
      lo_alv_cds->set_select_options( it_ranges = lt_name_range_pairs ) .
      lo_alv_cds->fullscreen( )->display( ) .
    ELSE.
      lo_alv->set_select_options( it_ranges = lt_name_range_pairs ) .
      lo_alv->fullscreen( )->display( ) .
    ENDIF.
  ENDMETHOD. "run_report

  METHOD select_file.
    re_file = cl_openxml_helper=>browse_local_file_open(
      iv_title      = 'Select File'
      iv_filename   = i_filename
      iv_extpattern = i_type ).
  ENDMETHOD.                    "select_file

  METHOD get_excel_data.
    DATA: lt_xtab   TYPE cpt_x255,
          lv_size   TYPE i,
          lw_record TYPE zreport.
    FIELD-SYMBOLS:  TYPE table.
    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename   = im_file
        filetype   = 'BIN'
      IMPORTING
        filelength = lv_size
      CHANGING
        data_tab   = lt_xtab
      EXCEPTIONS
        OTHERS     = 1.
    IF sy-subrc NE 0.
      MESSAGE |Invalid File { im_file }| TYPE 'I'.
      RETURN.
    ENDIF.
    cl_scp_change_db=>xtab_to_xstr( EXPORTING im_xtab    = lt_xtab
                                              im_size    = lv_size
                                    IMPORTING ex_xstring = DATA(lv_xstring) ).
    DATA(lo_excel) = NEW cl_fdt_xl_spreadsheet( document_name = im_file
                                                xdocument     = lv_xstring ).
    lo_excel->if_fdt_doc_spreadsheet~get_worksheet_names(
      IMPORTING worksheet_names = DATA(lt_worksheets) ).
    DATA(lo_table) = lo_excel->if_fdt_doc_spreadsheet~get_itab_from_worksheet( lt_worksheets[ 1 ] ).
    ASSIGN lo_table->* TO .
    LOOP AT  ASSIGNING FIELD-SYMBOL().
      ASSIGN COMPONENT 1 OF STRUCTURE  TO FIELD-SYMBOL().
      ASSIGN COMPONENT 2 OF STRUCTURE  TO FIELD-SYMBOL().
      IF  IS INITIAL. EXIT. ENDIF.
      CASE .
        WHEN 'Transaction Code:'.
          CLEAR lw_record.
          lw_record-tcode = .
        WHEN 'CDS View/View/Table Name:'.
          lw_record-view_or_table = .
        WHEN 'Selection Fields:' OR ''.
          lw_record-selection_field = .
          APPEND lw_record TO rt_table.
      ENDCASE.
    ENDLOOP.
  ENDMETHOD. "get_excel_data

  METHOD get_field_labels.
    DATA: lw_dtel  TYPE rsddtel.
    SELECT l~fieldname, l~rollname INTO TABLE @DATA(lt_elements) FROM dd03l AS l
      JOIN  ddldependency AS d ON l~tabname = d~objectname
      WHERE d~ddlname = @im_tabview AND d~state = 'A' AND d~objecttype = 'VIEW'.
    IF sy-subrc <> 0.
      SELECT fieldname rollname INTO TABLE lt_elements FROM dd03l
        WHERE tabname = im_tabview.
    ELSE.
      e_cds_view = abap_true.
    ENDIF.
    LOOP AT lt_elements INTO DATA(lw_elem).
      CLEAR lw_dtel.
      CALL FUNCTION 'RSD_DTEL_GET'
        EXPORTING
          i_dtelnm       = lw_elem-rollname
        IMPORTING
          e_s_dtel       = lw_dtel
        EXCEPTIONS
          dtel_not_found = 1
          doma_not_found = 2
          illegal_input  = 3
          OTHERS         = 4.
      IF sy-subrc <> 0. CONTINUE. ENDIF.
      INSERT VALUE lty_flabel( name = lw_elem-fieldname
                               text = lw_dtel-txtmd ) INTO TABLE et_field_labels.
    ENDLOOP.
  ENDMETHOD. "get_field_labels

  METHOD build_select_options.
    DATA: lo_cds_data    TYPE REF TO data,
          lr_structdescr TYPE REF TO cl_abap_structdescr,
          lr_tabledescr  TYPE REF TO cl_abap_tabledescr,
          lr_datadescr   TYPE REF TO cl_abap_datadescr,
          lr_typedescr   TYPE REF TO cl_abap_typedescr,
          lt_selopts     TYPE abap_component_tab,
          lw_component   TYPE abap_componentdescr,
          lo_wa          TYPE REF TO data,
          lo_tab         TYPE REF TO data.
    FIELD-SYMBOLS:   TYPE any.
    IF it_config[] IS INITIAL. RETURN. ENDIF.
    DATA(lv_cds_view) = it_config[ 1 ]-view_or_table.
    get_field_labels( EXPORTING im_tabview      = CONV #( lv_cds_view )
                      IMPORTING et_field_labels = DATA(lt_fdesc)
                                e_cds_view      = e_cds_view ).
    IF lt_fdesc[] IS INITIAL.
      MESSAGE |Invalid CDS View, Table or View Name '{ lv_cds_view }'.| TYPE 'I'.
      RETURN.
    ENDIF.
    CREATE DATA lo_cds_data TYPE (lv_cds_view).
    ASSIGN lo_cds_data->* TO .
    DATA(lt_components) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( lv_cds_view ) )->components.
    LOOP AT it_config ASSIGNING FIELD-SYMBOL().
      ASSIGN COMPONENT 'SELECTION_FIELD' OF STRUCTURE  TO FIELD-SYMBOL().
      IF line_exists( lt_components[ name =  ] ).
        CLEAR: lr_structdescr, lr_tabledescr, lr_datadescr, lr_typedescr,
               lt_selopts[], lw_component, lo_wa, lo_tab.
        lw_component-name = 'SIGN'.
        lw_component-type ?= cl_abap_elemdescr=>get_c( p_length = 1 ).
        INSERT lw_component INTO TABLE lt_selopts.
        CLEAR lw_component.
        lw_component-name = 'OPTION'.
        lw_component-type ?= cl_abap_elemdescr=>get_c( p_length = 2 ).
        INSERT lw_component INTO TABLE lt_selopts.
        CLEAR lw_component.
        lw_component-name = 'LOW'.
        lw_component-type ?= cl_abap_elemdescr=>describe_by_name( |{ lv_cds_view }-{  }| ).
        INSERT lw_component INTO TABLE lt_selopts.
        CLEAR lw_component-name.
        lw_component-name = 'HIGH'.
        lw_component-type ?= cl_abap_elemdescr=>describe_by_name( |{ lv_cds_view }-{  }| ).
        INSERT lw_component INTO TABLE lt_selopts.
        lr_structdescr ?= cl_abap_structdescr=>create( lt_selopts ).
        CREATE DATA lo_wa TYPE HANDLE lr_structdescr.
        ASSIGN lo_wa->* TO FIELD-SYMBOL().
        lr_datadescr ?= lr_structdescr.
        lr_tabledescr ?= cl_abap_tabledescr=>create( lr_datadescr ).
        CREATE DATA lo_tab TYPE HANDLE lr_tabledescr.
        ASSIGN lo_tab->* TO FIELD-SYMBOL().
        APPEND VALUE #( name          = 
                        text          = lt_fdesc[ name =  ]-text
                        select_option = REF #(  ) )
                        TO et_selopts.
      ELSE.
        MESSAGE |Invalid field {  }| TYPE 'I'.
      ENDIF.
      UNASSIGN: , , .
    ENDLOOP.
    e_cds_view_name = lv_cds_view.
  ENDMETHOD. "build_select_options
ENDCLASS. "lcl_dynamic_sel

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_ifile.
  p_ifile = lcl_dynamic_sel=>select_file( i_filename = CONV string( p_ifile )
                                          i_type     = lcl_dynamic_sel=>c_excel ).

INITIALIZATION.
  %_p_ifile_%_app_%-text = 'Excel SelOpt File'.
  fil_lbl = 'Excel Input File'.
  mn_lbl  = 'Program Options'.
  %_rb_run_%_app_%-text  = 'Run the Report Only'.
  %_rb_load_%_app_%-text = 'Update the Table Only'.
  %_rb_both_%_app_%-text = 'Update Table and Run Report'.
  %_p_refr_%_app_%-text  = 'Refresh Table (all entries)'.
  %_s_tcode_%_app_%-text = 'Transaction Code'.

AT SELECTION-SCREEN OUTPUT.
  IF rb_run = abap_true. "Report Only
    LOOP AT SCREEN.
      IF screen-group1 = 'LOD'.
        screen-active = '0'. "Hide
        MODIFY SCREEN.
      ENDIF.
      IF screen-group1 = 'CFG'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
    ENDLOOP.
  ELSEIF rb_load = abap_true. "Update Table only
    LOOP AT SCREEN.
      IF screen-group1 = 'LOD'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
      IF screen-group1 = 'CFG'.
        screen-active = '0'. "Hide
        MODIFY SCREEN.
      ENDIF.
    ENDLOOP.
  ELSEIF rb_both = abap_true. "Update Table and Run Report
    LOOP AT SCREEN.
      IF screen-group1 = 'LOD'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
      IF screen-group1 = 'CFG'.
        screen-active = '1'. "Show
        MODIFY SCREEN.
      ENDIF.
    ENDLOOP.
  ENDIF.

START-OF-SELECTION.
  NEW lcl_dynamic_sel( )->execute( VALUE #(
      filename     = CONV string( p_ifile )
      tcode        = s_tcode-low
      refresh      = p_refr
      run_only     = rb_run
      load_only    = rb_load
      run_and_load = rb_both ) ).

No comments:

Post a Comment