Abap alv to excel

A recent discussion amongst the ABAP developers at my site dealt with the topic of how to arrange for a customized ABAP program running as a background job to have its ALV table output sent to an internet email address. During this discussion I learned the easy way to do this, requiring no ABAP programming at all, which simply requires the designation of a Spool recipient when scheduling the background job via transaction SM36:

After pursuing this further I soon found that for programs producing multiple ALV tables of output, each ALV table becomes its own independent output spool request, and the process noted above to have the output sent to a spool list recipient will cause only the last of these multiple output spools to be sent in an email. I began to look for a way to send them all, and this led me to ABAP2XLSX.

ABAP2XLSX

ABAP2XLSX is an open source facility enabling the creation of Excel spreadsheets from within ABAP programs.  According to Tech Target (https://whatis.techtarget.com/fileformat/XLSX-Microsoft-Excel-Open-XML-Document):

  • XLSX is a file extension for an open XML spreadsheet file format used by Microsoft Excel. Microsoft introduced the open XML standard to Microsoft Office in 2007 after a push from business users who saw the value in an open file format for transferring data between applications and other areas of working with the files.

The name ABAP2XLSX perfectly describes what it does, and after recently reading Paul Hardy’s excellent account of it in his book ABAP to the Future, I began exploring it further to see how it might enable converting ALV table output into an Excel spreadsheet. Available for free download from GitHub via https://github.com/ivanfemia/abap2xlsx, I had found that it already was available in the SAP environment at my site. It is provided primarily as a collection of ABAP global classes and interfaces, but it has a multitude of simple report demonstration programs following the naming convention ZDEMO_EXCEL*. Of these, I had found ZDEMO_EXCEL3 provided a good example of how to a) create an Excel spreadsheet from a table used to supply content for an ALV report, and b) send the spreadsheet to an email recipient.

After browsing the code of ZDEMO_EXCEL3 I found that it, and indeed virtually all these demo programs, facilitates sending the table contents via email by using the Business Communication Services, a feature SAP has made available since release 6.40. At this point I began to experiment with a copy of the code to reduce it to its essential elements to facilitate my requirement of sending the spool requests of multiple ALV reports via email. The sequence of steps outlined below shows how I went from knowing nothing about ABAP2XLSX to having it satisfy my requirement to send the output of multiple ALV reports to an internet email address.

Getting started

The first thing we need is a minimal ABAP program that will produce a single ALV report. The SFLIGHT demonstration table will provide the rows for this and an initial selection screen provides a parameter to allow the user to specify only the number of rows to be provided in the report. Here is the starting code:

report.
  types          : row_counter    type n length 02.
  parameters     : rowcount       type row_counter.
start-of-selection.
  perform display_flight_rows using rowcount.
form display_flight_rows using row_count
                                  type row_counter.
    data         : flight_stack   type standard table of sflight
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = flight_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table flight_stack
      from sflight
             up to row_count rows.
    alv_report->display( ).
endform.

Activating and executing this program in foreground will present an ALV report with however many rows from table SFLIGHT the user had specified on the initial selection screen. Pressing Back, Exit or Cancel on this ALV report will return to the initial selection screen.

Including another ALV report in the program

Now that we have a program producing a single ALV report, let’s expand this to one that will provide two ALV reports, adding a report to show rows from the SCARR table. Here is the updated code:

report.
  types          : row_counter    type n length 02.
  parameters     : rowcount       type row_counter.
start-of-selection.
  perform display_flight_rows using rowcount.
  perform display_carrier_rows using rowcount.
form display_flight_rows using row_count
                                  type row_counter.
    data         : flight_stack   type standard table of sflight
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = flight_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table flight_stack
      from sflight
             up to row_count rows.
    alv_report->display( ).
endform.
form display_carrier_rows using row_count
                                  type row_counter.
    data         : carrier_stack  type standard table of scarr
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = carrier_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table carrier_stack
      from scarr
             up to row_count rows.
    alv_report->display( ).
endform.

The difference between this and the first version of the program is that we now have a new subroutine display_carrier_rows appearing at the end, modelled after the subroutine display_flight_rows, but defined to retrieve and present rows from the SCARR table. Also, we’ve included a perform statement in the start-of-selection event block to invoke this new subroutine after invoking the subroutine display_flight_rows.

Activating and executing this program in foreground again will present an ALV report with however many rows from table SFLIGHT the user had specified on the initial selection screen, but pressing Back, Exit or Cancel will present the second ALV report, the one with rows from the SCARR table. Pressing Back, Exit or Cancel from this second ALV report will return to the initial selection screen.

Including yet another ALV report in the program

Now that we have a program producing two ALV reports, let’s expand this to one that will provide three ALV reports, adding a report to show rows from the SBOOK table. Here is the updated code:

report.
  types          : row_counter    type n length 02.
  parameters     : rowcount       type row_counter.
start-of-selection.
  perform display_flight_rows using rowcount.
  perform display_carrier_rows using rowcount.
  perform display_booking_rows using rowcount.
form display_flight_rows using row_count
                                  type row_counter.
    data         : flight_stack   type standard table of sflight
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = flight_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table flight_stack
      from sflight
             up to row_count rows.
    alv_report->display( ).
endform.
form display_carrier_rows using row_count
                                  type row_counter.
    data         : carrier_stack  type standard table of scarr
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = carrier_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table carrier_stack
      from scarr
             up to row_count rows.
    alv_report->display( ).
endform.
form display_booking_rows using row_count
                                  type row_counter.
    data         : booking_stack  type standard table of sbook
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = booking_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table booking_stack
      from sbook
             up to row_count rows.
    alv_report->display( ).
endform.

The difference between this and the second version of the program is that we now have a new subroutine display_booking_rows appearing at the end, also modelled after the subroutine display_flight_rows,but defined to retrieve and present rows from the SBOOK table. Also, we’ve included a perform statement in the start-of-selection event block to invoke this new subroutine after invoking the subroutine display_booking_rows.

Activating and executing this program in foreground again will present an ALV report with however many rows from table SFLIGHT the user had specified on the initial selection screen, then pressing Back, Exit or Cancel will present the second ALV report, the one with rows from the SCARR table, then pressing Back, Exit or Cancel will present the third ALV report, the one with rows from the SBOOK table. Pressing Back, Exit or Cancel from this third ALV report will return to the initial selection screen.

Running in background

At this point we have a simple program capable of displaying three separate ALV reports in succession when run in foreground. If we were to run this in background we would get three separate spool requests. Try it and see:

  • Designate to run the program immediately in background.
  • Invoke transaction SM37, then press Execute to get the Job Overview screen.
  • Select the job and press the Spool icon, which presents the Step List Overview.

When a job has multiple associated spool requests, then the All Spool Requests icon should also appear on this display to the right of the Spool icon:

Placing the cursor on the job step entry and pressing this All Spool Lists button will show all spool requests associated with the job step:

Notice that there are three spool requests associated with this execution. Notice also that the spool request identifiers (Spool no.) do not necessarily appear in their numeric sequence. Had we defined this as a scheduled job and indicated a Spool List Recipient, then the recipient would receive only the last spool request created by this program – the one with the highest spool number.

Using ABAP2XLSX to capture and email as Excel spreadsheet content of multiple ALV reports

Now, using the features of ABAP2XLSX, we’re going to supercharge this simple program and provide it with the capability the collect all the ALV report output into a single Excel spreadsheet and to send the spreadsheet to an internet email address. In our case, we’ll create a single Excel spreadsheet which will contain three separate worksheets, with each worksheet containing the content of one of the ALV reports, and then send this Excel spreadsheet as an email attachment to our own email address.

Including the capability to capture ALV report content in an Excel spreadsheet

We’ll do this in two stages. The first is to provide the capability to capture the content from each of our ALV reports as a separate worksheet of an Excel spreadsheet. To do this we now introduce the use of the capabilities provided by ABAP2XLSX. We need a data statement to declare a variable to be used as a reference to an instance of class zcl_excel:

  data : excel type ref to zcl_excel.

Place this immediately ahead of the parameters statement defining rowcount. A syntax check should still pass. Next, we need a new subroutine that can accept both a standard table of ALV report content and a description for it, and to use these to create a new Excel worksheet. Here is the code to do this:

form copy_table_to_excel_worksheet using source_stack
                                           type standard table
                                         source_description
                                           type string
                                 raising zcx_excel.
    constants    : first_column   type char1     value 'A'
                 .
    data         : worksheet      type ref to zcl_excel_worksheet
                 , worksheet_title
                                  type zexcel_sheet_title
                 , table_settings type zexcel_s_table_settings
                 .
    table_settings-table_style    = zcl_excel_table=>builtinstyle_medium2.
    table_settings-show_row_stripes
                                  = abap_true.
    table_settings-nofilters      = abap_true.
    table_settings-top_left_column
                                  = first_column.
    table_settings-top_left_row   = 01.
    if excel is not bound.
      create object excel.
      worksheet                   = excel->get_active_worksheet( ).
    else.
      worksheet                   = excel->add_new_worksheet( ).
    endif.
    worksheet_title               = source_description.
    worksheet->set_title( worksheet_title ).
    worksheet->bind_table(
      ip_table                    = source_stack
      is_table_settings           = table_settings
      ).
endform.

Place this new subroutine at the end of the program. A syntax check should still pass. Finally, we need to invoke this new subroutine from each of our three ALV reporting subroutines, so place each of these statements as the final statements in subroutines of display_flight_rows, display_carrier_rows and display_booking_rows, respectively:

  perform copy_table_to_excel_worksheet using flight_stack ‘Flights’.

  perform copy_table_to_excel_worksheet using carrier_stack ‘Carriers’.

  perform copy_table_to_excel_worksheet using booking_stack ‘Bookings’.

At this point a syntax check still will pass, but an Extended Syntax Check will issue errors indicating that we are not handling exception zcx_excel in any of the three ALV reporting subroutines invoking the new subroutine, which indicates that it can raise this exception. Accordingly, add the statement

  raising zcx_excel

to the signature of each of the form definitions for the ALV reporting subroutines. Rerun the Extended Syntax Check, including the checkmark to select Programming Guidelines, and now the errors are gone but we get a warning that field excel is declared globally. Yes, we know this, so let’s apply the ##NEEDED pragrma to its definition to indicate that we wish not to see this warning anymore:

  data : excel type ref to zcl_excel ##NEEDED.

Now an extended syntax check including the checkmark to select Programming Guidelines gives us a clean bill of health.

Including the capability to email an Excel spreadsheet

The program now builds an Excel spreadsheet containing three worksheets but does nothing with it. Let’s include some code to have this Excel spreadsheet mailed to our own email address. Here is the new subroutine to do this, which was modelled after the subroutine send_mail of class lcl_ouput defined in object ZDEMO_EXCEL_OUTPUTOPT_INCL:

form send_excel_via_email using recipient type email_recipient.
    constants    : excel_file_type
                                 type string value '.xlsx'
                 , file_name_parameter
                                  type string value '&SO_FILENAME='
                 .
    data         : excel_writer   type ref to zif_excel_writer
                 , excel_as_xstring
                                  type xstring
                 , excel_as_xstring_bytecount
                                  type i
                 , excel_as_solix_stack
                                  type solix_tab
                 , mail_send_request
                                  type ref to cl_bcs
                 , mail_message   type ref to cl_document_bcs
                 , any_bcs_exception
                                  type ref to cx_bcs
                 , diagnostic     type string
                 , mail_title     type so_obj_des
                 , mail_text_stack
                                  type soli_tab
                 , mail_text_entry
                                  like line
                                    of mail_text_stack
                 , mail_attachment_subject
                                  type sood-objdes
                 , mail_attachment_bytecount
                                  type sood-objlen
                 , mail_attachment_header_stack
                                  type soli_tab
                 , mail_attachment_header_entry
                                  like line of mail_attachment_header_stack
                 , internet_email_recipient
                                  type ref to if_recipient_bcs
                 , successful_send
                                  type abap_bool
                 , file_name      type string
                 .
    " Much of the code here was lifted from method send_mail of
    " class lcl_ouput, defined in object ZDEMO_EXCEL_OUTPUTOPT_INCL:
    concatenate sy-repid          " this report name
                sy-datum          " current date
                sy-uzeit          " current time
                excel_file_type   " excel file extension
           into file_name.
    mail_title                    = file_name.
    mail_attachment_subject       = file_name.
    mail_text_entry               = 'See attachment'.
    append mail_text_entry
        to mail_text_stack.
    concatenate file_name_parameter
                file_name
           into mail_attachment_header_entry.
    append mail_attachment_header_entry
        to mail_attachment_header_stack.
    create object excel_writer type zcl_excel_writer_2007.
    excel_as_xstring              = excel_writer->write_file( excel ).
    excel_as_solix_stack          = cl_bcs_convert=>xstring_to_solix( iv_xstring = excel_as_xstring ).
    excel_as_xstring_bytecount    = xstrlen( excel_as_xstring ).
    mail_attachment_bytecount     = excel_as_xstring_bytecount.
    try.
      mail_message                = cl_document_bcs=>create_document(
                                      i_type    = 'RAW' "#EC NOTEXT
                                      i_text    = mail_text_stack
                                      i_subject = mail_title
                                      ).
      mail_message->add_attachment(
        i_attachment_type         = 'XLS' "#EC NOTEXT
        i_attachment_subject      = mail_attachment_subject
        i_attachment_size         = mail_attachment_bytecount
        i_att_content_hex         = excel_as_solix_stack
        i_attachment_header       = mail_attachment_header_stack
        ).
      mail_send_request           = cl_bcs=>create_persistent( ).
      mail_send_request->set_document( mail_message ).
      internet_email_recipient    = cl_cam_address_bcs=>create_internet_address( recipient ).
      mail_send_request->add_recipient( internet_email_recipient ).
      successful_send             = mail_send_request->send( ).
      commit work.
      if successful_send eq abap_false.
        message i500(sbcoms) with recipient.
      else.
        message s022(so).
        message 'Document ready to be sent - Check SOST' type 'I'.
      endif.
    catch cx_bcs into any_bcs_exception.
      diagnostic                  = any_bcs_exception->if_message~get_text( ).
      message diagnostic type 'I'.
    endtry.
endform.

Place this at the end of the program. Then adjust the code between the report statement and the start-of-selection statement to include:

  • a types statement defining an email_recipient
  • a parameters statement defining a recipient parameter using the new email_recipient type
  • an initialization event block to automatically populate this new parameters field

Afterward, the first few lines code should look like this:

report.
  types          : row_counter    type n length 02.
  types          : email_recipient
                                  type adr6-smtp_addr.
  data           : excel          type ref to zcl_excel ##NEEDED.
  parameters     : rowcount       type row_counter.
  parameters     : recipien       type email_recipient.
initialization.
  select single smtp_addr
    into recipien
    from adr6 ##WARN_OK
           inner join
         usr21 on usr21~persnumber eq adr6~persnumber
   where usr21~bname              eq sy-uname.
start-of-selection.

A syntax check should still pass. Finally, include a new perform statement at the end of the start-of-selection event to invoke the new subroutine:

  perform send_excel_via_email using recipien.

A syntax check should still pass and an extended syntax check including the checkmark to select Programming Guidelines should find no violations. The final image should look like this:

report.
  types          : row_counter    type n length 02.
  types          : email_recipient
                                  type adr6-smtp_addr.
  data           : excel          type ref to zcl_excel ##NEEDED.
  parameters     : rowcount       type row_counter.
  parameters     : recipien       type email_recipient.
initialization.
  select single smtp_addr
    into recipien
    from adr6 ##WARN_OK
           inner join
         usr21 on usr21~persnumber eq adr6~persnumber
   where usr21~bname              eq sy-uname.
start-of-selection.
  perform display_flight_rows using rowcount.
  perform display_carrier_rows using rowcount.
  perform display_booking_rows using rowcount.
  perform send_excel_via_email using recipien.
form display_flight_rows using row_count
                                  type row_counter
                       raising zcx_excel.
    data         : flight_stack   type standard table of sflight
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = flight_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table flight_stack
      from sflight
             up to row_count rows.
    alv_report->display( ).
    perform copy_table_to_excel_worksheet using flight_stack 'Flights'.
endform.
form display_carrier_rows using row_count
                                  type row_counter
                        raising zcx_excel.
    data         : carrier_stack  type standard table of scarr
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = carrier_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table carrier_stack
      from scarr
             up to row_count rows.
    alv_report->display( ).
    perform copy_table_to_excel_worksheet using carrier_stack 'Carriers'.
endform.
form display_booking_rows using row_count
                                  type row_counter
                        raising zcx_excel.
    data         : booking_stack  type standard table of sbook
                 , alv_report     type ref to cl_salv_table
                 .
    try.
      call method cl_salv_table=>factory
        importing
          r_salv_table            = alv_report
        changing
          t_table                 = booking_stack.
    catch cx_salv_msg.
      return.
    endtry.
    select *
      into table booking_stack
      from sbook
             up to row_count rows.
    alv_report->display( ).
    perform copy_table_to_excel_worksheet using booking_stack 'Bookings'.
endform.
form copy_table_to_excel_worksheet using source_stack
                                           type standard table
                                         source_description
                                           type string
                                 raising zcx_excel.
    constants    : first_column   type char1     value 'A'
                 .
    data         : worksheet      type ref to zcl_excel_worksheet
                 , worksheet_title
                                  type zexcel_sheet_title
                 , table_settings type zexcel_s_table_settings
                 .
    table_settings-table_style    = zcl_excel_table=>builtinstyle_medium2.
    table_settings-show_row_stripes
                                  = abap_true.
    table_settings-nofilters      = abap_true.
    table_settings-top_left_column
                                  = first_column.
    table_settings-top_left_row   = 01.
    if excel is not bound.
      create object excel.
      worksheet                   = excel->get_active_worksheet( ).
    else.
      worksheet                   = excel->add_new_worksheet( ).
    endif.
    worksheet_title               = source_description.
    worksheet->set_title( worksheet_title ).
    worksheet->bind_table(
      ip_table                    = source_stack
      is_table_settings           = table_settings
      ).
endform.
form send_excel_via_email using recipient type email_recipient.
    constants    : excel_file_type
                                 type string value '.xlsx'
                 , file_name_parameter
                                  type string value '&SO_FILENAME='
                 .
    data         : excel_writer   type ref to zif_excel_writer
                 , excel_as_xstring
                                  type xstring
                 , excel_as_xstring_bytecount
                                  type i
                 , excel_as_solix_stack
                                  type solix_tab
                 , mail_send_request
                                  type ref to cl_bcs
                 , mail_message   type ref to cl_document_bcs
                 , any_bcs_exception
                                  type ref to cx_bcs
                 , diagnostic     type string
                 , mail_title     type so_obj_des
                 , mail_text_stack
                                  type soli_tab
                 , mail_text_entry
                                  like line
                                    of mail_text_stack
                 , mail_attachment_subject
                                  type sood-objdes
                 , mail_attachment_bytecount
                                  type sood-objlen
                 , mail_attachment_header_stack
                                  type soli_tab
                 , mail_attachment_header_entry
                                  like line of mail_attachment_header_stack
                 , internet_email_recipient
                                  type ref to if_recipient_bcs
                 , successful_send
                                  type abap_bool
                 , file_name      type string
                 .
    " Much of the code here was lifted from method send_mail of
    " class lcl_ouput, defined in object ZDEMO_EXCEL_OUTPUTOPT_INCL:
    concatenate sy-repid          " this report name
                sy-datum          " current date
                sy-uzeit          " current time
                excel_file_type   " excel file extension
           into file_name.
    mail_title                    = file_name.
    mail_attachment_subject       = file_name.
    mail_text_entry               = 'See attachment'.
    append mail_text_entry
        to mail_text_stack.
    concatenate file_name_parameter
                file_name
           into mail_attachment_header_entry.
    append mail_attachment_header_entry
        to mail_attachment_header_stack.
    create object excel_writer type zcl_excel_writer_2007.
    excel_as_xstring              = excel_writer->write_file( excel ).
    excel_as_solix_stack          = cl_bcs_convert=>xstring_to_solix( iv_xstring = excel_as_xstring ).
    excel_as_xstring_bytecount    = xstrlen( excel_as_xstring ).
    mail_attachment_bytecount     = excel_as_xstring_bytecount.
    try.
      mail_message                = cl_document_bcs=>create_document(
                                      i_type    = 'RAW' "#EC NOTEXT
                                      i_text    = mail_text_stack
                                      i_subject = mail_title
                                      ).
      mail_message->add_attachment(
        i_attachment_type         = 'XLS' "#EC NOTEXT
        i_attachment_subject      = mail_attachment_subject
        i_attachment_size         = mail_attachment_bytecount
        i_att_content_hex         = excel_as_solix_stack
        i_attachment_header       = mail_attachment_header_stack
        ).
      mail_send_request           = cl_bcs=>create_persistent( ).
      mail_send_request->set_document( mail_message ).
      internet_email_recipient    = cl_cam_address_bcs=>create_internet_address( recipient ).
      mail_send_request->add_recipient( internet_email_recipient ).
      successful_send             = mail_send_request->send( ).
      commit work.
      if successful_send eq abap_false.
        message i500(sbcoms) with recipient.
      else.
        message s022(so).
        message 'Document ready to be sent - Check SOST' type 'I'.
      endif.
    catch cx_bcs into any_bcs_exception.
      diagnostic                  = any_bcs_exception->if_message~get_text( ).
      message diagnostic type 'I'.
    endtry.
endform.

Now execute the program and you should see that it not only produces the 3 ALV reports but also results in an Excel spreadsheet created and mailed to the recipient email address, both in foreground and in background executions.

Insuring the email gets dispatched

Some SAP environments have a periodic job scheduled to regularly sweep output destined for transport via internet email. To be certain the email created by this program is dispatched, invoke transaction SOST, which will show all pending send requests. If you see your new email message in the queue in a waiting status, select the row(s) to be dispatched, then from the menu select the command: Send Request > Start Send Process for Selection. The selected row(s) disappear from the queue and moments later a corresponding email message will appear in your internet email inbox.

Summary

Designing a program like the one above based on the demonstration programs accompanying ABAP2XLSX provided me with a prototype to solve my problem of being able to send all ALV report output to an email recipient. Furthermore, since the content of the ALV report arrives in the recipient’s inbox as an Excel spreadsheet, and not as a flat text file representation of the ALV report as is the case with the Spool Recipient List technique, it enables the user to perform sorting, filtering, and all the other table manipulation features provided by the Excel application.

Perhaps others can find this investigation useful.

CLASS lcl_alv_wrapper DEFINITION.

  PUBLIC SECTION.

    INTERFACES if_alv_rm_grid_friend .

    METHODS:

      constructor,

      get_alv_instance

        RETURNING VALUE(ro_alv) TYPE REF TO cl_gui_alv_grid,

      export_to_excel

        IMPORTING

          VALUE(it_data) TYPE ANY TABLE,

      create_fcat

        IMPORTING

                  it_data           TYPE ANY TABLE

                  it_exclude_fields TYPE tc_field_tab OPTIONAL

        RETURNING VALUE(rt_fcat)    TYPE lvc_t_fcat,

      free.

  PRIVATE SECTION.

    DATA mo_dummy_container TYPE REF TO cl_gui_custom_container.

    DATA mo_alv TYPE REF TO cl_gui_alv_grid.

ENDCLASS.

CLASS lcl_alv_wrapper IMPLEMENTATION.

*———————————————————————*

* CONSTRUCTOR

*———————————————————————*

* Конструктор

*———————————————————————*

  METHOD constructor.

    «Создаем фиктивный контейнер (т.к. ALV не будет нигде отображаться)

    CREATE OBJECT mo_dummy_container

      EXPORTING

        container_name              = space

      EXCEPTIONS

        cntl_error                  = 1

        cntl_system_error           = 2

        create_error                = 3

        lifetime_error              = 4

        lifetime_dynpro_dynpro_link = 5

        OTHERS                      = 6.

    ASSERT sysubrc = 0.

    mo_alv = NEW #( i_parent = mo_dummy_container ).

    ASSERT mo_alv IS BOUND.

  ENDMETHOD.

*———————————————————————*

* GET_ALV_INSTANCE

*———————————————————————*

* Вернуть instance ALV

*———————————————————————*

  METHOD get_alv_instance.

    «Возвращаем

    ro_alv = mo_alv.

  ENDMETHOD.

*———————————————————————*

* EXPORT_TO_EXCEL

*———————————————————————*

* Выгрузка в Excel

*———————————————————————*

  METHOD export_to_excel.

    «Выполнение команды

    mo_alv>execute_fcode(

      EXPORTING

        i_ucomm = cl_gui_alv_grid=>mc_fc_call_xxl

    ).

  ENDMETHOD.

*———————————————————————*

* CREATE_FCAT

*———————————————————————*

* Формирование каталога полей

*———————————————————————*

  METHOD create_fcat.

    «Создаем таблицу входящего типа

    DATA lo_table TYPE REF TO data.

    TRY.

        CREATE DATA lo_table LIKE it_data.

        ASSIGN lo_table>* TO FIELDSYMBOL(<lt_table>).

        cl_salv_table=>factory( IMPORTING

                                  r_salv_table   = DATA(lo_salv_table)

                                CHANGING

                                  t_table        = <lt_table>  ).

        «Забираем каталог полей

        rt_fcat = cl_salv_controller_metadata=>get_lvc_fieldcatalog(

            r_columns      = lo_salv_table>get_columns( )

            r_aggregations = lo_salv_table>get_aggregations( )

        ).

      CATCH cx_root.

        RETURN.

    ENDTRY.

  ENDMETHOD.

*———————————————————————*

* FREE

*———————————————————————*

* Зачистка атрибутов

*———————————————————————*

  METHOD free.

    «Зачистка атрибутов

    FREE mo_alv.

    FREE mo_dummy_container.

  ENDMETHOD.

ENDCLASS.

Despite you are speaking about an ALV List Tree, which is a very primitive and outdated, I will show the way how to do it using modern SALV_ALV_TREE control.

The idea was borrowed from here so all the credits go to Juwin, I just adapted and created friendly sample.

CLASS lcl_tree DEFINITION.
  PUBLIC SECTION.
    CLASS-DATA: go_alv_tree  TYPE REF TO cl_salv_tree,
                gt_empty_tab TYPE STANDARD TABLE OF spfli,
                gt_full_tab  TYPE STANDARD TABLE OF spfli.
    CLASS-METHODS: create_tree,
                   setup,
                   export_tree,
                   on_user_command FOR EVENT added_function OF cl_salv_events IMPORTING e_salv_function.
ENDCLASS.

CLASS lcl_tree IMPLEMENTATION.
  METHOD export_tree.
    DATA: lr_data  TYPE REF TO data,
          lt_spfli TYPE STANDARD TABLE OF spfli,
          levels   TYPE TABLE OF rsplf_srv_p.

    DATA: lr_zip         TYPE REF TO cl_abap_zip,
          lr_xlnode      TYPE REF TO if_ixml_node,
          lr_xldimension TYPE REF TO if_ixml_node,
          lr_file        TYPE REF TO cl_xml_document,
          lr_xlrows      TYPE REF TO if_ixml_node_list,
          lr_xlrow       TYPE REF TO if_ixml_element,
          lr_xlformat    TYPE REF TO if_ixml_element,
          lr_xlworksheet TYPE REF TO if_ixml_element.

    FIELD-SYMBOLS: <spfli> TYPE spfli.

    DATA(lt_nodes) = go_alv_tree->get_nodes( )->get_all_nodes( ).
    LOOP AT lt_nodes INTO DATA(ls_node).
      DATA(lr_node) = ls_node-node.
      DATA(lv_level) = 0.
      DO.
        TRY.
            lr_node = lr_node->get_parent( ).
            lv_level = lv_level + 1.
          CATCH cx_salv_msg.
            EXIT.
        ENDTRY.
      ENDDO.
      APPEND VALUE rsplf_srv_p( indx = sy-tabix value = lv_level ) TO levels.
      lr_data = ls_node-node->get_data_row( ).
      ASSIGN lr_data->* TO <spfli>.
      APPEND <spfli> TO lt_spfli.
    ENDLOOP.

    cl_salv_table=>factory(
      IMPORTING
        r_salv_table = DATA(lr_table)
      CHANGING
        t_table = lt_spfli ).

    DATA(lv_xlsx) = lr_table->to_xml( if_salv_bs_xml=>c_type_xlsx ).
    CREATE OBJECT lr_zip.
    lr_zip->load( lv_xlsx ).
    lr_zip->get( EXPORTING name = 'xl/worksheets/sheet1.xml' IMPORTING content = DATA(lv_file) ).

    CREATE OBJECT lr_file.
    lr_file->parse_xstring( lv_file ).
* Row elements are under SheetData
    lr_xlnode = lr_file->find_node( 'sheetData' ).
    lr_xlrows = lr_xlnode->get_children( ).

    DO lr_xlrows->get_length( ) TIMES.
      lr_xlrow ?= lr_xlrows->get_item( sy-index - 1 ).
      READ TABLE lt_nodes INTO ls_node INDEX sy-index - 1. "find this row in tree
      IF sy-subrc = 0.
        READ TABLE levels ASSIGNING FIELD-SYMBOL(<line_level>) INDEX sy-index.
* Find the level of the node
        CHECK <line_level>-value - 1 NE 0.
* Assign the level to row
        lr_xlrow->set_attribute( name = 'outlineLevel' value = condense( CONV string( <line_level>-value - 1 ) ) ).
        lr_xlrow->set_attribute( name = 'hidden' value = 'true' ).
      ENDIF.
    ENDDO.

* Create new element in the XML file
    lr_xlworksheet ?= lr_file->find_node( 'worksheet' ).
    DATA(lr_xlsheetpr)   = cl_ixml=>create( )->create_document( )->create_element( name = 'sheetPr' ).
    DATA(lr_xloutlinepr) = cl_ixml=>create( )->create_document( )->create_element( name = 'outlinePr' ).
    lr_xlsheetpr->if_ixml_node~append_child( lr_xloutlinepr ).
    lr_xloutlinepr->set_attribute( name = 'summaryBelow' value = 'false' ).
    lr_xldimension ?= lr_file->find_node( 'dimension' ).
    lr_xlworksheet->if_ixml_node~insert_child( new_child = lr_xlsheetpr ref_child = lr_xldimension ).
* Create xstring and move it to XLSX
    lr_file->render_2_xstring( IMPORTING stream = lv_file ).
    lr_zip->delete( EXPORTING name = 'xl/worksheets/sheet1.xml' ).
    lr_zip->add( EXPORTING name = 'xl/worksheets/sheet1.xml' content = lv_file ).
    lv_xlsx = lr_zip->save( ).

    DATA lv_size   TYPE i.
    DATA lt_bintab TYPE solix_tab.

    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
      EXPORTING
        buffer        = lv_xlsx
      IMPORTING
        output_length = lv_size
      TABLES
        binary_tab    = lt_bintab.

    CHECK lt_bintab IS NOT INITIAL.
    DATA(p_file) = cl_openxml_helper=>browse_local_file_open( iv_title = 'Save to XLSX File' iv_filename = '' iv_extpattern = 'All files(*.*)|*.*' ).
    cl_gui_frontend_services=>gui_download( EXPORTING bin_filesize = lv_size
                                                      filename    = p_file && `.xlsx`
                                                      filetype      = 'BIN'
                                            CHANGING  data_tab   = lt_bintab ).
  ENDMETHOD.

  METHOD create_tree.
    TRY.
        cl_salv_tree=>factory(
          IMPORTING
            r_salv_tree = go_alv_tree
          CHANGING
            t_table     = gt_empty_tab ).
      CATCH cx_salv_error.
        MESSAGE 'ALV creation error' TYPE 'E'.
    ENDTRY.

    DATA(lo_settings) = go_alv_tree->get_tree_settings( ).
    lo_settings->set_hierarchy_size( 50 ).
    lo_settings->set_hierarchy_icon( CONV salv_de_tree_image( icon_tree ) ).
    DATA(lo_nodes) = go_alv_tree->get_nodes( ).

    SELECT * FROM spfli INTO TABLE gt_full_tab ORDER BY carrid.
    LOOP AT gt_full_tab ASSIGNING FIELD-SYMBOL(<fs_line>).
      TRY.
          AT NEW carrid.
            DATA(lo_node) = lo_nodes->add_node( related_node   = ''
                                                relationship   = cl_gui_column_tree=>relat_last_child
                                                data_row       = <fs_line>
                                                row_style      = if_salv_c_tree_style=>emphasized_a
                                                text           = 'Parent node' ).
            DATA(lv_carrid_key) = lo_node->get_key( ).
          ENDAT.
          AT NEW connid.
            lo_node = lo_nodes->add_node( related_node   = lv_carrid_key
                                          relationship   = cl_gui_column_tree=>relat_last_child
                                          data_row       = <fs_line>
                                          row_style      = if_salv_c_tree_style=>emphasized_negative
                                          text           = 'Child node' ).
          ENDAT.
        CATCH cx_salv_msg.
      ENDTRY.
    ENDLOOP.
  ENDMETHOD.                    "create_nodes

  METHOD setup.
    go_alv_tree->set_screen_status( pfstatus  = 'STANDARD_FULLSCREEN' report = 'SAPLSLVC_FULLSCREEN' set_functions =  go_alv_tree->c_functions_all ).
    DATA(lr_functions) = go_alv_tree->get_functions( ).
    lr_functions->set_all( abap_true ).
    DATA(lo_columns) = go_alv_tree->get_columns( ).
    lo_columns->set_optimize( abap_true ).
    DATA(lo_events) = go_alv_tree->get_event( ).
    SET HANDLER on_user_command FOR lo_events.
  ENDMETHOD.

  METHOD on_user_command.
    CASE e_salv_function.
      WHEN '&VEXCEL'.
        export_tree( ).
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

The sample constructs the tree using SPFLI table, then converts the SALV_ALV_TREE into CL_SALV_TABLE and captures the nodes in OpenXML format, then constructing XLSX.

Adding levels/aggregations is done manually intervening into XLSX ZIP-archive files and changing their properties: outlineLevel and others.

More about OpenXML structure can be found here.

After recreating the class on your system you can test it like this

START-OF-SELECTION.

 lcl_tree=>create_tree( ).
 lcl_tree=>setup( ).
 lcl_tree=>go_alv_tree->display( ).

The export is done via Excel button on the standard toolbar:

enter image description here

The result of the export is this native Excel tree

enter image description here

type-pools: slis, KKBLO.

data: lv_repid type SY-REPID.
data: lvc_t_fcat type LVC_T_FCAT,
lv_user_command type SLIS_FORMNAME.

DATA lv_table_text type DD02T-DDTEXT.
DATA lvc_grid_title type lvc_title.

parameters: p_tabnam type tabname matchcode object DD_DBTB,
p_rows type i default 5000.

DATA dref TYPE REF TO data.

field-symbols: type standard table.

translate p_tabnam to upper case.
* Get table title
select single DDTEXT from DD02T
into (lv_table_text) where tabname = p_tabnam
and DDLANGUAGE = sy-langu.
if sy-subrc eq 0.
lvc_grid_title = lv_table_text.
else.
message ‘No table with such name was found’ type ‘E’.
endif.

TRY.
CREATE DATA dref TYPE STANDARD TABLE OF (p_tabnam)
WITH NON-UNIQUE DEFAULT KEY.
ASSIGN dref->* TO .
endtry.
check is assigned.

select * from (p_tabnam)
into table
up to p_rows rows.

if sy-subrc ne 0.
message ‘No records was selected.’ type ‘S’.
exit.
endif.

perform prepare_fieldcat tables lvc_t_fcat.
lv_repid = sy-repid.
lv_user_command = ‘ALV_USER_COMMAND’.

data: gt_event_exit type SLIS_T_EVENT_EXIT,
gs_event_exit type SLIS_EVENT_EXIT.

gs_event_exit-ucomm = ‘&VEXCEL’.
gs_event_exit-before = ‘X’.
append gs_event_exit to gt_event_exit.

CALL FUNCTION ‘REUSE_ALV_GRID_DISPLAY_LVC’
EXPORTING
I_CALLBACK_PROGRAM = lv_repid
I_CALLBACK_USER_COMMAND = lv_user_command
I_GRID_TITLE = lvc_grid_title
IT_FIELDCAT_LVC = lvc_t_fcat
IT_EVENT_EXIT = gt_event_exit
TABLES
T_OUTTAB =
EXCEPTIONS
PROGRAM_ERROR = 1
OTHERS = 2
.
*&———————————————————————*
*& Form PREPARE_FIELDCAT
*&———————————————————————*
* text
*———————————————————————-*
* —>P_LVC_T_FCAT text
*———————————————————————-*
FORM PREPARE_FIELDCAT TABLES T_LVC_FCAT STRUCTURE LVC_S_FCAT.
data: g_structure type DD02L-TABNAME,
lt_fcat type lvc_t_fcat.

g_structure = p_tabnam.
CALL FUNCTION ‘LVC_FIELDCATALOG_MERGE’
EXPORTING
I_STRUCTURE_NAME = g_structure
CHANGING
CT_FIELDCAT = lt_fcat.
T_LVC_FCAT[] = lt_fcat[].

data: lr_alv_grid type ref to cl_gui_alv_grid.
case p_ucomm.
when ‘&VEXCEL’.
CALL FUNCTION ‘ZXXA_EXPORT_TABLE_TO_EXCEL’
TABLES
IT_DATA =
IT_FIELDCAT = lvc_t_fcat.
CALL FUNCTION ‘GET_GLOBALS_FROM_SLVC_FULLSCR’
IMPORTING
E_GRID = lr_alv_grid.
CALL METHOD LR_ALV_GRID->SET_USER_COMMAND
EXPORTING
I_UCOMM = ».
endcase.
ENDFORM. » ALV_USER_COMMAND

FUNCTION ZXXA_EXPORT_TABLE_TO_EXCEL.
*»———————————————————————-
*»*»Локальный интерфейс:
*» IMPORTING
*» REFERENCE(I_ROW) TYPE I DEFAULT 1
*» REFERENCE(I_COLUMN) TYPE I DEFAULT 1
*» REFERENCE(WITH_HEADER) TYPE BOOLEAN DEFAULT ‘X’
*» REFERENCE(TECH_NAMES) TYPE BOOLEAN DEFAULT »
*» REFERENCE(FIT_WIDEST) TYPE BOOLEAN DEFAULT ‘X’
*» REFERENCE(NO_FORMAT) TYPE BOOLEAN OPTIONAL
*» EXPORTING
*» REFERENCE(E_DOCUMENT_PROXY) TYPE REF TO I_OI_DOCUMENT_PROXY
*» REFERENCE(E_SPREADSHEET) TYPE REF TO I_OI_SPREADSHEET
*» REFERENCE(E_ERROR) TYPE REF TO I_OI_ERROR
*» REFERENCE(E_RETCODE)
*» TABLES
*» IT_DATA TYPE TABLE
*» IT_FIELDCAT TYPE LVC_T_FCAT
*»———————————————————————-

types: ty_range_name type char20.

constants: datatable_range_name type ty_range_name value ‘DataTable’,
header_range_name type ty_range_name value ‘Header’,
wholetable_range_name type ty_range_name value ‘WholeTable’,
lines_per_range type i value 9999. » 9999 — maximum

data: lf_range_name type ty_range_name.
data: wa_fieldcat type lvc_s_fcat,
lt_fieldcat type sorted table of lvc_s_fcat
with unique key col_pos,
lf_fieldname type char060.

data: lf_lines type i,
lf_columns type i.

data: cursor_row type i,
cursor_column type i.

data: num_of_ranges type i,
lf_tmp type i,
current_range type i,
current_row type i,
current_column type i,
index type i,
lf_rows type i,
lf_current_cycle type i.

data: n(2) type n. » temporary variable

data: lt_ranges type soi_range_list,
ls_ranges type soi_range_item,
lt_content type soi_generic_table,
ls_content type soi_generic_item.

DATA: spreadsheet TYPE REF TO i_oi_spreadsheet,
document_proxy type ref to i_oi_document_proxy.
data: is_available type i,
ret_value type i.

data: lf_percent type p decimals 2.

field-symbols: type any,
type any.

if gr_control is initial.
CALL METHOD c_oi_container_control_creator=>get_container_control
IMPORTING control = gr_control
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
endif.
if gr_container is INITIAL.
CREATE OBJECT gr_container EXPORTING container_name = ‘CC_EXCEL’.
CALL METHOD gr_control->init_control
EXPORTING r3_application_name = ‘Excel Document Container’
* inplace_enabled = ‘X’
parent = gr_container
register_on_close_event = ‘X’
IMPORTING retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
endif.

CALL METHOD gr_control->get_document_proxy
EXPORTING document_type = ‘Excel.Sheet.8’
register_container = ‘X’
IMPORTING document_proxy = document_proxy
retcode = retcode
error = error.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.

SET HANDLER gcl_xls_handler=>close_event FOR document_proxy.
e_document_proxy = document_proxy.

CALL METHOD document_proxy->create_document
EXPORTING open_inplace = »
document_title = ‘Выгрузка в Excel’
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.

* Get spreadsheet interface
CALL METHOD document_proxy->get_spreadsheet_interface
IMPORTING sheet_interface = spreadsheet
error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
e_spreadsheet = spreadsheet.

* Define number of lines of the table
describe table it_data lines lf_lines.

* Define number of columns of the table
lt_fieldcat[] = it_fieldcat[].
delete lt_fieldcat where no_out eq ‘X’ or tech eq ‘X’.
describe table lt_fieldcat lines lf_columns.

* Set cursor to the left top corner of the table.
cursor_row = i_row.
cursor_column = i_column.
CALL METHOD spreadsheet->set_selection
EXPORTING top = cursor_row
left = cursor_column
rows = 1
columns = 1
* updating = 0
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.

* Handling of header
if with_header eq ‘X’.
* Insert range for the table header
CALL METHOD spreadsheet->insert_range
EXPORTING name = header_range_name
rows = 1
columns = lf_columns
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Insert range for the whole table header
lf_rows = lf_lines + 1.
CALL METHOD spreadsheet->insert_range
EXPORTING name = wholetable_range_name
rows = lf_rows
columns = lf_columns
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
index = 0.
loop at lt_fieldcat into wa_fieldcat. «where no_out eq space.
index = index + 1.
clear ls_content.
ls_content-column = index.
ls_content-row = 1.
if tech_names eq ‘X’.
ls_content-value = wa_fieldcat-FIELDNAME.
else.
ls_content-value = wa_fieldcat-SCRTEXT_L.
endif.
append ls_content to lt_content.
endloop.
ls_ranges-name = header_range_name.
ls_ranges-rows = 1.
ls_ranges-columns = index.
append ls_ranges to lt_ranges.
* Set the data from the table into the range
call method spreadsheet->set_ranges_data
exporting ranges = lt_ranges
contents = lt_content.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Set the cursor to the line next after the last one
cursor_row = cursor_row + 1.
CALL METHOD spreadsheet->set_selection
EXPORTING top = cursor_row
left = cursor_column
rows = 1
columns = 1
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Set range name to fit wide of columns
lf_range_name = wholetable_range_name.
else.
lf_range_name = datatable_range_name.
endif.

* Insert range for the data table
CALL METHOD spreadsheet->insert_range
EXPORTING name = datatable_range_name
rows = lf_lines
columns = lf_columns
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.

* There are only 9999 records can be tranferred in a range, becase ROW field of
* SOI_RANGE_ITEM structure has length of 4 symbols. So it is neccessary to split the range.
num_of_ranges = lf_lines div lines_per_range.
lf_tmp = num_of_ranges * lines_per_range.
* check if remainder of dividing is not equal 0
if lf_lines gt lf_tmp.
num_of_ranges = num_of_ranges + 1.
endif.

index = 1. «cursor of data table
* The main cycle — insert ranges with records
do num_of_ranges times.
current_range = sy-index.
refresh: lt_ranges, lt_content.
* lf_percent = ( current_range — 1 ) * lines_per_range / lf_lines * 100.
* CALL FUNCTION ‘SAPGUI_PROGRESS_INDICATOR’
* EXPORTING
* PERCENTAGE = lf_percent
* TEXT = ‘Выгрузка в Excel’.

* Loop at the data table using cursor
loop at it_data assigning from index.
lf_current_cycle = sy-tabix. «current line of data table
* get current row of the current range
* (splitted by steps to avoid strange calculating error..)
current_row = current_range — 1.
current_row = current_row * lines_per_range.
current_row = lf_current_cycle — current_row.
* Filling the LS_CONTENT structure for each cell of data table
* Warning: the maximum length of any field of data table shouldn’t be grater than 256!
do lf_columns times.
current_column = sy-index.
read table lt_fieldcat into wa_fieldcat
index current_column transporting FIELDNAME inttype.
check sy-subrc eq 0.
ls_content-column = current_column.
ls_content-row = current_row.
concatenate ‘ -‘ wa_fieldcat-FIELDNAME into lf_fieldname.
assign (lf_fieldname) to .
check is assigned.
if wa_fieldcat-inttype eq ‘D’.
write to ls_content-value DD/MM/YYYY .
else.
ls_content-value = .
endif.
append ls_content to lt_content.
enddo.
if current_row eq lines_per_range.
index = current_row * current_range + 1.
exit.
endif.
endloop.
n = current_range.
concatenate ‘Range’ n into ls_ranges-name.
ls_ranges-rows = current_row.
ls_ranges-columns = lf_columns.
* ls_ranges-code = e_spreadsheet->SPREADSHEET_INSERTALL.
append ls_ranges to lt_ranges.
* Insert range for a current part of data table
CALL METHOD spreadsheet->insert_range
EXPORTING name = ls_ranges-name
rows = current_row
columns = lf_columns
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Set the data from the table into the range
call method spreadsheet->set_ranges_data
exporting ranges = lt_ranges
contents = lt_content
updating = 0.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Set the cursor to the line next after the last one
cursor_row = cursor_row + current_row.
CALL METHOD spreadsheet->set_selection
EXPORTING top = cursor_row
left = cursor_column
rows = 1
columns = 1
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
enddo.

* Formatting
if no_format eq space.
* Set frame of table
CALL METHOD spreadsheet->set_frame
EXPORTING rangename = wholetable_range_name
typ = 127
color = 1
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Set bold font of header
CALL METHOD spreadsheet->set_font
EXPORTING rangename = header_range_name
family = ‘-1’
size = ‘-1’
bold = ‘1’
italic = ‘-1’
align = ‘-1’
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Set color of header
CALL METHOD spreadsheet->set_color
EXPORTING rangename = header_range_name
front = ‘-1’
back = ‘6’
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
endif.
* Set left-justification align
CALL METHOD spreadsheet->set_font
EXPORTING rangename = wholetable_range_name
family = ‘-1’
size = ‘-1’
bold = ‘-1’
italic = ‘-1’
align = ‘0’
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
* Fit optimal width
if fit_widest eq ‘X’.
CALL METHOD spreadsheet->fit_widest
EXPORTING name = lf_range_name
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
endif.
* Finally, update screen with handled table
CALL METHOD spreadsheet->screen_update
EXPORTING updating = ‘X’
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.

FUNCTION-POOL ZXXA_TEST_TOOLS. «MESSAGE-ID ..

data: retcode type SOI_RET_STRING,
error type ref to I_OI_ERROR.

CLASS gcl_xls_handler DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
close_event FOR EVENT ON_CLOSE_DOCUMENT OF I_OI_DOCUMENT_PROXY
IMPORTING DOCUMENT_PROXY Has_changed,
custom_event FOR EVENT ON_CUSTOM_EVENT OF I_OI_DOCUMENT_PROXY.
* IMPORTING (. )
ENDCLASS.

CLASS gcl_xls_handler IMPLEMENTATION.
METHOD close_event.
CALL METHOD document_proxy->close_document
IMPORTING error = error
retcode = retcode .
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
CALL METHOD document_proxy->release_document
IMPORTING error = error
retcode = retcode.
CALL METHOD c_oi_errors=>show_message EXPORTING type = ‘E’.
free document_proxy.

METHOD custom_event.
ENDMETHOD.

DATA gr_control type ref to I_OI_CONTAINER_CONTROL.
DATA gr_container type ref to cl_gui_custom_container.

Источник

Adblock
detector

One of the most requested abilities for an report is the possibility to run it as a job and send the output to a given user. However, the spool output of most ALV reports is unusable as is. To solve this problem, I’ll show a simple class that takes an internal table, a fieldcatalog and a user email to create a xml excel file from the field catalog with the contents of the internal table and forward it to the email supplied.
I should warn that the excel output isn’t something fancy. It’s just a simple table. The class can be greatly enhanced.


1 — Create a class:

2 — Create the class atributes:







3 — Create the class methods:

4 — Create the method parameters:







5 — Insert the appropriate code in each method:

Like this post? Please share to your friends:
  • A word приложение купить
  • A word without you слова
  • A word without clothes
  • A word with you today
  • A word with you ministries