This is a test message to test the length of the message box.
Login
ABAP RAP Excel Datei laden
Erstellt von Software-Heroes

RAP - Excel Datei laden

142

In diesem praktischen Beispiel schauen wir uns die Verarbeitung von Excel in ABAP mit den neuen XCO Klassen an und wie wir die Datei in unser RAP Objekt bekommen.

Werbung


In diesem Artikel wollen wir die Verarbeitung der Excel Datei in unsere Anwendung integrieren und verschiedene weitere Schritte implementieren.

 

Einleitung

Für die Verarbeitung von Excel Dateien stellt SAP eine eigene XCO API zur Verfügung, die du zum Lesen und mittlerweile auch zum Schreiben verwenden kannst. Im heutigen Beispiel erweitern wir unsere Report Pattern App um eine Aktion, um die hochgeladene Excel Datei zu lesen, zu parsen und damit die Daten zu aktualisieren. Im Anschluss wollen wir die Datei wieder entfernen, wenn die Verarbeitung so weit erfolgreich war.

 

Erweiterung

Bevor wir mit der Implementierung beginnen, müssen wir die App um eine Aktion erweitern, die wir dann für die Entwicklung verwenden können. Die Aktion soll ein Popup anzeigen, wo wir noch Einstellung vornehmen können, dazu legen wir eine Abstrakte Entität an.

@EndUserText.label: 'Excel Popup'
define abstract entity ZBS_S_DRPExcelPopup
{
  @EndUserText.label: 'Test run'
  TestRun : abap_boolean;
}

 

Im nächsten Schritt ergänzen wir die Aktion in der Verhaltensdefinition "ZBS_R_DRPCurrency". Dabei muss für die Aktion ein Datensatz markiert werden, wir möchten gern vorher ein Popup anzeigen (Parameter) und die Aktion soll eine Instanz von sich selbst zurückgeben, um die Daten nach der Verarbeitung zu aktualisieren.

action LoadExcelContent parameter ZBS_S_DRPExcelPopup result [1] $self;

 

Damit wir dann auch die Aktion in der App auch verwenden können, müssen wir sie in der Projektion "ZBS_C_DRPCurrency" bekannt geben.

use action LoadExcelContent;

 

Zum Abschluss erweitern wir noch die Metadaten "ZBS_C_DRPCurrency", um auf dem UI einen Platz für den Button zu finden. Wir möchten gern den Button auf dem Detailbild des Datensatzes anzeigen, deshalb binden wir diesen an die IDENTIFICATION.

@UI:{
  lineItem: [{ position: 10 }],
  selectionField: [{ position: 10 }],
  identification: [{ type: #FOR_ACTION, dataAction: 'LoadExcelContent', label: 'Load Excel' }]
}
Currency;

 

Der Button sollte nun auf den Detailbildern jedes Datensatzes zu sehen sein. Wenn du ihn anklickst, sollte vor der Verarbeitung auch ein Popup erscheinen, wo der Testlauf abgefragt wird. Damit sind wir mit der Erweiterung durch und können die Aktion ausprägen.

 

Excel

In diesem Abschnitt möchten wir nun das hochgeladene Dokument einlesen und verarbeiten.

 

Datei

In diesem Tutorial werden wir die folgende Datei zum Testen verwenden. Dabei sind mehr Länder enthalten, als eigentlich an einem Datensatz verfügbar sind. Zusätzlich haben wir noch eine weitere Spalte, die wir für Auswertungen heranziehen könnten. Die Datei hat nur ein Arbeitsblatt, wenn wir sie einlesen wollen.

 

Die Excel Datei laden wir in unsere Entität hoch. Für unser Beispiel können wir die Datei nach EUR oder nach AED laden, da wir Datensätze für die beiden Währungen haben.

 

Implementierung

Um nun die Datei verarbeiten zu können, müssen wir die Aktion in RAP implementieren. Beginnen wir im ersten Schritt den aktuellen Datensatz zu lesen und alle zugeordneten Länder, um diese später abzugleichen. Da wir nur einen Datensatz verarbeiten, lesen wir den ersten Schlüssel und den ersten Datensatz, implementieren aber noch ein passendes Fehlerhandling.

READ ENTITIES OF ZBS_R_DRPCurrency IN LOCAL MODE
     ENTITY Currency FIELDS ( Currency ExcelAttachement ) WITH CORRESPONDING #( keys )
     RESULT DATA(lt_attachement)
     ENTITY Currency BY \_Country ALL FIELDS WITH CORRESPONDING #( keys )
     RESULT DATA(lt_countries).

TRY.
    DATA(ls_key) = keys[ 1 ].
    DATA(ls_attachement) = lt_attachement[ 1 ].
  CATCH cx_sy_itab_line_not_found.
    INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                        number   = '003'
                        severity = if_abap_behv_message=>severity-error )
           INTO TABLE reported-%other.
    RETURN.
ENDTRY.

 

Im nächsten Schritt parsen wir die Excel Datei, um an die Daten zu kommen, die wir dann verarbeiten wollen. Dazu lagern wir die Logik in eine eigene Methode aus und erstellen eine eigene Exception, die wir im Fehlerfall direkt an das Log hängen können. Zum Abschluss erzeugen wir noch eine Meldung für den User, wie viele Datensätze wir in der Excel Datei gefunden haben.

TRY.
    DATA(lt_excel) = convert_excel_file_to_table( ls_attachement-excelattachement ).
  CATCH zcx_drp_excel_error INTO DATA(lo_excel_error).
    INSERT lo_excel_error INTO TABLE reported-%other.
    RETURN.
ENDTRY.

INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                    number   = '005'
                    severity = if_abap_behv_message=>severity-success
                    v1       = lines( lt_excel ) )
       INTO TABLE reported-%other.

 

 

Hier findest du die Methode zum Parsen der Datei. Zuerst einmal überprüfen wir, ob ein Stream, also ein Upload, vorhanden ist. Im nächsten Schritt öffnen wir die Datei und laden das erste Arbeitsblatt, sollte dieses nicht vorhanden sein, erzeugen wir eine Fehlermeldung. Im Anschluss versuchen wir die Excel Datei ab Zeile zwei einzulesen und die Überschriften zu sparen.

IF id_stream IS INITIAL.
  RAISE EXCEPTION NEW zcx_drp_excel_error( textid = VALUE #( msgid = 'ZBS_DEMO_RAP_PATTERN'
                                                             msgno = '001' ) ).
ENDIF.

DATA(lo_sheet) = xco_cp_xlsx=>document->for_file_content( id_stream
  )->read_access( )->get_workbook(
  )->worksheet->at_position( 1 ).

IF NOT lo_sheet->exists( ).
  RAISE EXCEPTION NEW zcx_drp_excel_error( textid = VALUE #( msgid = 'ZBS_DEMO_RAP_PATTERN'
                                                             msgno = '002' ) ).
ENDIF.

DATA(lo_pattern) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to(
  )->from_column( xco_cp_xlsx=>coordinate->for_alphabetic_value( 'A' )
  )->from_row( xco_cp_xlsx=>coordinate->for_numeric_value( 2 )
  )->get_pattern( ).

lo_sheet->select( lo_pattern
  )->row_stream(
  )->operation->write_to( REF #( rt_result )
  )->set_value_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
  )->execute( ).

 

Befinden wir uns im Testlauf, dann endet hier die Verarbeitung und wir verlassen die Logik. Dem Anwender geben wir noch eine entsprechende Warnung mit.

IF ls_key-%param-TestRun = abap_true.
  INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                      number   = '004'
                      severity = if_abap_behv_message=>severity-warning )
         INTO TABLE reported-%other.
  RETURN.
ENDIF.

 

Um nun die Änderungen durchführen zu können, bereiten wir drei Tabellen vor, die die verschiedenen Änderungen später dem Entity Manipulation Language (EML) Statement übergeben.

DATA lt_currency_modify  TYPE TABLE FOR UPDATE ZBS_R_DRPCurrencyCurrency.
DATA lt_countries_create TYPE TABLE FOR CREATE ZBS_R_DRPCurrency\_Country.
DATA lt_countries_modify TYPE TABLE FOR UPDATE ZBS_R_DRPCurrencyCountry.

 

Um den Anhang zu entfernen, setzen wir die Felder auf leer. Du solltest auch nicht vergessen, die entsprechenden %CONTROL Strukturen zu aktivieren, damit die Änderungen durchgeführt werden können.

INSERT VALUE #( %tky                      = ls_attachement-%tky
                excelattachement          = ''
                excelmimetype             = ''
                excelfilename             = ''
                %control-excelattachement = if_abap_behv=>mk-on
                %control-excelmimetype    = if_abap_behv=>mk-on
                %control-excelfilename    = if_abap_behv=>mk-on )
       INTO TABLE lt_currency_modify.

 

Im nächsten Code-Abschnitt verarbeiten wir alle Datensätze in der Excel Datei, die die gleiche Währung haben, also zu unserem Datensatz passen. Dann prüfen wir gegen die Ländertabelle, die wir zuvor gelesen haben. Ist ein Land bereits vorhanden, aktualisieren wir die zusätzlichen Felder, in diesem Fall das Ranking. Ist ein Laden noch nicht vorhanden, übernehmen wir den neuen Datensatz.

INSERT VALUE #( currency = ls_attachement-Currency )
       INTO TABLE lt_countries_create REFERENCE INTO DATA(lr_new).

LOOP AT lt_excel INTO DATA(ls_excel) WHERE currency = ls_attachement-Currency.
  TRY.
      DATA(ls_country) = lt_countries[ Country = ls_excel-country ].
      INSERT VALUE #( currency                = ls_country-Currency
                      country                 = ls_country-Country
                      countryranking          = ls_excel-ranking
                      %control-countryranking = if_abap_behv=>mk-on )
             INTO TABLE lt_countries_modify.

    CATCH cx_sy_itab_line_not_found.
      INSERT VALUE #( %cid                    = xco_cp=>uuid( )->value
                      currency                = ls_excel-currency
                      country                 = ls_excel-country
                      countryranking          = ls_excel-ranking
                      %control-currency       = if_abap_behv=>mk-on
                      %control-country        = if_abap_behv=>mk-on
                      %control-countryranking = if_abap_behv=>mk-on )
             INTO TABLE lr_new->%target.
  ENDTRY.
ENDLOOP.

 

Nach der Verarbeitung können wir unsere drei Tabellen dem EML Statement übergeben und die Änderungen im transaktionalen Puffer des RAP Objekts registrieren. Der CREATE für Country ist nur über Currency möglich, da wir es im RAP Objekt in der Verhaltensdefinition so definiert haben. Dort ist der Create an der Assoziation aktiviert.

MODIFY ENTITIES OF ZBS_R_DRPCurrency IN LOCAL MODE
       ENTITY Currency UPDATE FROM lt_currency_modify
       ENTITY Country UPDATE FROM lt_countries_modify
       ENTITY Currency CREATE BY \_Country FROM lt_countries_create.

 

Zum Abschluss der Verarbeitung geben wir dem Anwender noch Meldungen mit, wie viele Datensätze neu aufgenommen wurden und wie viele sich geändert haben. Damit wäre die Implementierung der Methode auch soweit fertig.

INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                    number   = '007'
                    severity = if_abap_behv_message=>severity-success
                    v1       = lines( lt_countries_create[ 1 ]-%target ) )
       INTO TABLE reported-%other.

INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                    number   = '006'
                    severity = if_abap_behv_message=>severity-success
                    v1       = lines( lt_countries_modify ) )
       INTO TABLE reported-%other.

 

Test

In diesem Abschnitt wollen wir nun einmal das neue Feature testen. Dazu laden wir die Excel Datei in die Währung EUR. Aktuell haben wir hier auch Deutschland und Dänemark mit einem schlechten Ranking angelegt.

 

Nachdem wir die Aktion ausgeführt haben, erhalten wir eine Erfolgsmeldung, dass zwei Länder neu angelegt wurden und ein Land geändert wurde.

 

Nach der Aktualisierung der Oberfläche sollten nun die Änderungen aktiv sein. Die Datei ist nun verschwunden und die Länderliste ist wieder aktuell.

 

Vollständiges Beispiel

Alle Änderungen findest du wie immer am entsprechenden Commit des GitHub Repositorys. Zusätzlich findest du hier noch die Verhaltensimplementierung, um den aktuellen Stand der Implementierung nachvollziehen zu können.

CLASS lhc_Currency DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.
    TYPES: BEGIN OF ts_excel,
             currency TYPE string,
             country  TYPE string,
             ranking  TYPE string,
             flag     TYPE string,
           END OF ts_excel.

    TYPES tt_excel TYPE STANDARD TABLE OF ts_excel WITH EMPTY KEY.

    METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
      IMPORTING keys REQUEST requested_authorizations FOR Currency RESULT result.

    METHODS loadexcelcontent FOR MODIFY
      IMPORTING keys FOR ACTION currency~loadexcelcontent.

    METHODS convert_excel_file_to_table
      IMPORTING id_stream        TYPE xstring
      RETURNING VALUE(rt_result) TYPE tt_excel
      RAISING   zcx_drp_excel_error.
ENDCLASS.


CLASS lhc_Currency IMPLEMENTATION.
  METHOD get_instance_authorizations.
  ENDMETHOD.


  METHOD LoadExcelContent.
    DATA lt_currency_modify  TYPE TABLE FOR UPDATE ZBS_R_DRPCurrencyCurrency.
    DATA lt_countries_create TYPE TABLE FOR CREATE ZBS_R_DRPCurrency\_Country.
    DATA lt_countries_modify TYPE TABLE FOR UPDATE ZBS_R_DRPCurrencyCountry.

    READ ENTITIES OF ZBS_R_DRPCurrency IN LOCAL MODE
         ENTITY Currency FIELDS ( Currency ExcelAttachement ) WITH CORRESPONDING #( keys )
         RESULT DATA(lt_attachement)
         ENTITY Currency BY \_Country ALL FIELDS WITH CORRESPONDING #( keys )
         RESULT DATA(lt_countries).

    TRY.
        DATA(ls_key) = keys[ 1 ].
        DATA(ls_attachement) = lt_attachement[ 1 ].
      CATCH cx_sy_itab_line_not_found.
        INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                            number   = '003'
                            severity = if_abap_behv_message=>severity-error )
               INTO TABLE reported-%other.
        RETURN.
    ENDTRY.

    TRY.
        DATA(lt_excel) = convert_excel_file_to_table( ls_attachement-excelattachement ).
      CATCH zcx_drp_excel_error INTO DATA(lo_excel_error).
        INSERT lo_excel_error INTO TABLE reported-%other.
        RETURN.
    ENDTRY.

    INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                        number   = '005'
                        severity = if_abap_behv_message=>severity-success
                        v1       = lines( lt_excel ) )
           INTO TABLE reported-%other.

    IF ls_key-%param-TestRun = abap_true.
      INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                          number   = '004'
                          severity = if_abap_behv_message=>severity-warning )
             INTO TABLE reported-%other.
      RETURN.
    ENDIF.

    INSERT VALUE #( %tky                      = ls_attachement-%tky
                    excelattachement          = ''
                    excelmimetype             = ''
                    excelfilename             = ''
                    %control-excelattachement = if_abap_behv=>mk-on
                    %control-excelmimetype    = if_abap_behv=>mk-on
                    %control-excelfilename    = if_abap_behv=>mk-on )
           INTO TABLE lt_currency_modify.

    INSERT VALUE #( currency = ls_attachement-Currency )
           INTO TABLE lt_countries_create REFERENCE INTO DATA(lr_new).

    LOOP AT lt_excel INTO DATA(ls_excel) WHERE currency = ls_attachement-Currency.
      TRY.
          DATA(ls_country) = lt_countries[ Country = ls_excel-country ].
          INSERT VALUE #( currency                = ls_country-Currency
                          country                 = ls_country-Country
                          countryranking          = ls_excel-ranking
                          %control-countryranking = if_abap_behv=>mk-on )
                 INTO TABLE lt_countries_modify.

        CATCH cx_sy_itab_line_not_found.
          INSERT VALUE #( %cid                    = xco_cp=>uuid( )->value
                          currency                = ls_excel-currency
                          country                 = ls_excel-country
                          countryranking          = ls_excel-ranking
                          %control-currency       = if_abap_behv=>mk-on
                          %control-country        = if_abap_behv=>mk-on
                          %control-countryranking = if_abap_behv=>mk-on )
                 INTO TABLE lr_new->%target.
      ENDTRY.
    ENDLOOP.

    MODIFY ENTITIES OF ZBS_R_DRPCurrency IN LOCAL MODE
           ENTITY Currency UPDATE FROM lt_currency_modify
           ENTITY Country UPDATE FROM lt_countries_modify
           ENTITY Currency CREATE BY \_Country FROM lt_countries_create.

    INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                        number   = '007'
                        severity = if_abap_behv_message=>severity-success
                        v1       = lines( lt_countries_create[ 1 ]-%target ) )
           INTO TABLE reported-%other.

    INSERT new_message( id       = 'ZBS_DEMO_RAP_PATTERN'
                        number   = '006'
                        severity = if_abap_behv_message=>severity-success
                        v1       = lines( lt_countries_modify ) )
           INTO TABLE reported-%other.
  ENDMETHOD.


  METHOD convert_excel_file_to_table.
    IF id_stream IS INITIAL.
      RAISE EXCEPTION NEW zcx_drp_excel_error( textid = VALUE #( msgid = 'ZBS_DEMO_RAP_PATTERN'
                                                                 msgno = '001' ) ).
    ENDIF.

    DATA(lo_sheet) = xco_cp_xlsx=>document->for_file_content( id_stream
      )->read_access( )->get_workbook(
      )->worksheet->at_position( 1 ).

    IF NOT lo_sheet->exists( ).
      RAISE EXCEPTION NEW zcx_drp_excel_error( textid = VALUE #( msgid = 'ZBS_DEMO_RAP_PATTERN'
                                                                 msgno = '002' ) ).
    ENDIF.

    DATA(lo_pattern) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to(
      )->from_column( xco_cp_xlsx=>coordinate->for_alphabetic_value( 'A' )
      )->from_row( xco_cp_xlsx=>coordinate->for_numeric_value( 2 )
      )->get_pattern( ).

    lo_sheet->select( lo_pattern
      )->row_stream(
      )->operation->write_to( REF #( rt_result )
      )->set_value_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
      )->execute( ).
  ENDMETHOD.
ENDCLASS.


CLASS lsc_ZBS_R_DRPCURRENCY DEFINITION INHERITING FROM cl_abap_behavior_saver.
  PROTECTED SECTION.
    METHODS
      save_modified REDEFINITION.

    METHODS
      cleanup_finalize REDEFINITION.

ENDCLASS.


CLASS lsc_ZBS_R_DRPCURRENCY IMPLEMENTATION.
  METHOD save_modified.
    LOOP AT update-currency INTO DATA(ls_new_currency).
      DATA(ls_modify_currency) = CORRESPONDING zbs_drp_addcurr( ls_new_currency MAPPING FROM ENTITY ).
      ls_modify_currency-last_editor = cl_abap_context_info=>get_user_technical_name( ).
      MODIFY zbs_drp_addcurr FROM @ls_modify_currency.
    ENDLOOP.

    LOOP AT create-country INTO DATA(ls_create_country).
      INSERT zbs_drp_country FROM @( CORRESPONDING zbs_drp_country( ls_create_country MAPPING FROM ENTITY ) ).
    ENDLOOP.

    LOOP AT update-country INTO DATA(ls_update_country).
      UPDATE zbs_drp_country FROM @( CORRESPONDING zbs_drp_country( ls_update_country MAPPING FROM ENTITY ) ).
    ENDLOOP.

    LOOP AT delete-country INTO DATA(ls_delete_country).
      DELETE zbs_drp_country FROM @( CORRESPONDING zbs_drp_country( ls_delete_country MAPPING FROM ENTITY ) ).
    ENDLOOP.
  ENDMETHOD.


  METHOD cleanup_finalize.
  ENDMETHOD.
ENDCLASS.

 

Upload von Dateien

Die Methode der Attachements eignet sich aktuell gut für die Ablage von kleinen Dateien, die direkt für den Anwender zur Verfügung stehen sollen. Möchtest du den Upload allerdings nur nutzen, um damit die aktuelle Entität zu versorgen und eigentlich brauchst du danach die Datei nicht mehr, dann empfiehlt sich eine Aktion, in der du direkt die Datei mitgeben kannst. Hier gibt es bereits Open Source Projekte, wie zum Beispiel den Spreadsheet Importer, um so eine Funktion zu implementieren.

 

Fazit

Mit der neuen API kannst du auch einfache Excel Dokumente lesen und verarbeiten. Wie du die API richtig nutzt, haben wir dir in diesem Artikel nähergebracht.


Enthaltene Themen:
RAPBTPExcelDatei
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


RAP - Popup Defaultwerte

Kategorie - ABAP

Wie kannst du im Popup einer Aktion in RAP dem User Defaultwerte zur Verfügung stellen? In diesem Artikel erweitern wir unsere Anwendung.

21.01.2025

RAP - Popup Pflichtfelder

Kategorie - ABAP

Wie kannst du eigentlich Pflichtfelder für ein Popup in RAP definieren? In diesem Artikel werden wir etwas genauer auf die Details eingehen.

14.01.2025

RAP - Deep Table Action

Kategorie - ABAP

Ist die Übergabe von Tabellen an Aktionen in RAP aktuell möglich? Dieser Artikel soll einen besseren Einblick in das Thema gewähren.

07.01.2025

ABAP Cloud - Programmiermodell

Kategorie - ABAP

Welches Programmiermodell kommt mit ABAP Cloud zum Einsatz und was können wir aus dem Vorgänger lernen? Mehr Details im Artikel.

03.01.2025

RAP - Side Effects

Kategorie - ABAP

Wie kannst du Teile der Fiori UI aktualisieren, ohne einen kompletten Refresh zu machen? Mit Side Effects ist das in ABAP und RAP ganz leicht möglich.

27.12.2024