[ABAP] Dynamisches Selektionsbild-Popup erzeugen

CLASS lcl_dynamic_popup DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS
      show
        RETURNING VALUE(rv_ok) TYPE abap_bool.
ENDCLASS.

CLASS lcl_dynamic_popup IMPLEMENTATION.
  METHOD show.

    rv_ok = abap_true.

* Werte für Selektionbild definieren
    DATA: p_carrid TYPE s_carr_id.
    DATA: so_werks TYPE gds_selrange_werks_tab.
    DATA: p_werks_no TYPE werks.
    DATA: p_check  TYPE xfeld.
    DATA: rb_1 TYPE xfeld.
    DATA: rb_2 TYPE xfeld.
    DATA: lb_language TYPE spras.

    lb_language = sy-langu.

* Popup: Selektionsbildelemente
    DATA(it_attr) = VALUE sci_atttab(
* Group1 für die folgenden Felder
                                      (
                                        kind = 'G'
                                        text = 'Gruppe1'
                                        ref  = REF #( sy-index )
                                      )
* Parameter
                                      (
                                          kind       = 'S'
                                          text       = 'Carrid'
                                          obligatory = 'Y'
                                          ref        = REF #( p_carrid )
                                      )
* SELECT-OPTIONS
                                      (
                                          kind       = 'S'
                                          text       = 'Werk'
                                          ref        = REF #( so_werks )
                                      )
* SELECT-OPTIONS NO INTERVALS
                                      (
                                          kind       = 'T'
                                          text       = 'Werk2'
                                          ref        = REF #( p_werks_no )
                                      )
* Group2 für die folgenden Felder
                                      (
                                        kind = 'G'
                                        text = 'Gruppe2'
                                        ref  = REF #( sy-index )
                                      )
* Checkbox
                                      (
                                          kind       = 'C'
                                          text       = 'Check'
                                          ref        = REF #( p_check )
                                      )
* Radiobuttons mit Group
                                      (
                                          kind         = 'R'
                                          text         = 'Radiobutton1'
                                          button_group = 'GR1'
                                          ref          = REF #( rb_1 )
                                      )
                                      (
                                          kind         = 'R'
                                          text         = 'Radiobutton2'
                                          button_group = 'GR1'
                                          ref          = REF #( rb_2 )
                                      )
* Listbox
                                      (
                                          kind = 'L'
                                          text = 'Sprache'
                                          ref  = REF #( lb_language )
                                      )
                                    ).

* Selektionsbild erzeugen und Popup anzeigen
    IF abap_true = cl_ci_query_attributes=>generic( p_name       = CONV #( sy-repid )
                                                    p_title      = 'Dynamisches Popup'
                                                    p_display    = abap_false " abap_true: Anzeige im READONLY-Modus
                                                    p_attributes = it_attr ).
      rv_ok = abap_false.
    ENDIF.

* Werte ausgeben
    WRITE: / 'CARRID:', p_carrid.
    WRITE: / 'WERKS:', COND string( WHEN lines( so_werks ) > 0 THEN so_werks[ 1 ]-low ELSE '' ).
    WRITE: / 'WERKS2:', p_werks_no.
    WRITE: / 'Check:', p_check.
    WRITE: / 'RB1:', rb_1.
    WRITE: / 'RB2:', rb_2.
    WRITE: / 'LANGUAGE:', lb_language.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  IF abap_true = lcl_dynamic_popup=>show( ).
    WRITE: / 'Ok.'.
  ELSE.
    WRITE: / 'Abbruch.'.
  ENDIF.

[ABAP] Debuggen in Popup-Fenstern

  1. Text-Datei auf dem Desktop erstellen mit folgendem Inhalt
    [FUNCTION]
    Command=/H
    Title=Debugger
    Type=SystemCommand
    
  2. zu debuggendes ABAP-Programm ausführen und wenn das zu debuggende Popup hoch kommt -> per Drag&Drop die Text-Datei auf das Popupfenster ziehen

Links

[ABAP] Message-Klasse über Interface if_t100_dyn_msg definieren

* https://blogs.sap.com/2015/11/12/abap-news-for-release-750-converting-messages-into-exceptions/
CLASS lcl_msg_class DEFINITION.
  PUBLIC SECTION.
    INTERFACES if_t100_dyn_msg.

    ALIASES: t100_key FOR if_t100_message~t100key.
    ALIASES: msgty    FOR if_t100_dyn_msg~msgty.
    METHODS
      constructor
        IMPORTING
          msgid TYPE symsgid
          msgno TYPE symsgno
          msgty TYPE symsgty.
ENDCLASS.

CLASS lcl_msg_class IMPLEMENTATION.
  METHOD constructor.
    me->t100_key-msgid = msgid.
    me->t100_key-msgno = msgno.
    me->msgty          = msgty.
  ENDMETHOD.

  METHOD if_message~get_text.
    result = cl_message_helper=>get_text_for_message( me ).
  ENDMETHOD.

  METHOD if_message~get_longtext.
    result = cl_message_helper=>get_longtext_for_message( me ).
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  MESSAGE NEW lcl_msg_class( msgid = 'XYZ'
                             msgno = '001'
                             msgty = 'E' ).

[ABAP] Email-Adresse validieren

DATA: lv_address_normal TYPE sx_address.
DATA: lv_local TYPE sx_addr.
DATA: lv_domain TYPE sx_addr.
DATA: lv_comment TYPE sx_addr.
DATA: lv_addr_normal_no_upper TYPE sx_address.
DATA: lv_addr_normal_no_up TYPE sx_address.

* Type
* FAX	Faxnummer
* INT	Internet Mail Adresse
* X40	X.400 Mail Adresse
* RML	SAPoffice Adresse
* PAG	Pager(SMS) Nummer
* PRT	Druckername
* *	Alle
DATA(lv_address_unstruct) = value sx_address( address = 'email (Test)@email.com'
                                              type    = 'INT' ).

WRITE: / lv_address_unstruct-type, lv_address_unstruct-address.

CALL FUNCTION 'SX_INTERNET_ADDRESS_TO_NORMAL'
  EXPORTING
    address_unstruct               = lv_address_unstruct
  IMPORTING
    address_normal                 = lv_address_normal        " Normalform: Local@DOMAIN
    local                          = lv_local                 " Lokaler Teil der Adresse
    domain                         = lv_domain                " Domäne (konvertiert zu Großbuchstaben)
    comment                        = lv_comment               " Kommentar der Adresse
    addr_normal_no_upper           = lv_addr_normal_no_upper  " Adresse: Local@Domain (Domäne unkonvertiert)
    addr_normal_no_up_with_comment = lv_addr_normal_no_up     " Normalform mit Kommentar
  EXCEPTIONS
    error_address_type             = 1
    error_address                  = 2
    error_group_address            = 3
    OTHERS                         = 4.

IF sy-subrc = 0.
  WRITE: / '                    Normalform:', lv_address_normal-type, lv_address_normal-address.
  WRITE: / '                  Lokaler Teil:', lv_local.
  WRITE: / '                        Domäne:', lv_domain.
  WRITE: / '                     Kommentar:', lv_comment.
  WRITE: / 'Adresse (Domäne unkonvertiert):', lv_addr_normal_no_upper-type, lv_addr_normal_no_upper-address.
  WRITE: / '      Normalform mit Kommentar:', lv_addr_normal_no_up-type, lv_addr_normal_no_up-address.
ELSE.
  WRITE: / 'Error:', sy-subrc.
ENDIF.

[ABAP] RTTS: Interne Tabelle dynamisch erzeugen

Variante 1 (aus DDIC-Struktur)

TRY.
* Strukturdeskriptor für Komponenten (Spalten) der Tabelle anhand einer vorhandenen Struktur erzeugen
    DATA(o_struct_desc) = cl_abap_structdescr=>describe_by_name( 'SFLIGHTS' ).

* Tabellendeskriptor
    DATA(o_table_desc) = cl_abap_tabledescr=>create(
                                                     p_line_type  = CAST #( o_struct_desc )           " Spalten
                                                     p_table_kind = cl_abap_tabledescr=>tablekind_std " Tabellentyp STANDARD TABLE
                                                     p_unique     = abap_false                        " NON-UNIQUE KEY
                                                   ).

* Tabellenobjekt anhand des Tabellendeskriptors erstellen
    DATA: o_table TYPE REF TO data.
    CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt
    FIELD-SYMBOLS <table> TYPE ANY TABLE.
    ASSIGN o_table->* TO <table>.

* Daten holen und in Feldsymbol schreiben
    SELECT carrid, connid, carrname, fldate FROM sflights INTO CORRESPONDING FIELDS OF TABLE @<table>.

* Datenausgabe
    cl_demo_output=>display( <table> ).

  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

Variante 2 (eigene Strukturkomponenten)

TRY.
* Dummy für Datadescriptor
    DATA: lv_fldate TYPE sflights-fldate.

* Komponenten (Spalten) der Tabelle
    DATA(it_components) = VALUE cl_abap_structdescr=>component_table(
* Erzeugung über direkte Typangabe, abgeleitet aus dem Typ des eigentlichen Datenelements
* CHAR 3
                                                                      (
                                                                        name = 'CARRID'
                                                                        type = cl_abap_elemdescr=>get_c( 3 ) " S_CARR_ID
                                                                      )
* NUMC 4
                                                                      (
                                                                        name = 'CONNID'
                                                                        type = cl_abap_elemdescr=>get_n( 4 ) " S_CONN_ID
                                                                      )
* Erzeugung über Namen des Datenelements
                                                                      (
                                                                        name = 'CARRNAME'
                                                                        type = CAST #( cl_abap_elemdescr=>describe_by_name( 'S_CARRNAME' ) )
                                                                      )
* Erzeugung über Dummy-Datenobjekt
                                                                      (
                                                                        name = 'FLDATE'
                                                                        type = cast #( cl_abap_datadescr=>describe_by_data( lv_fldate ) )
                                                                      )
                                                                    ).

* Strukturdeskriptor für Komponententabelle
    DATA(o_struct_desc) = cl_abap_structdescr=>create( it_components ).

* Tabellendeskriptor
    DATA(o_table_desc) = cl_abap_tabledescr=>create(
                                                     p_line_type  = o_struct_desc                       " Spalten
                                                     p_table_kind = cl_abap_tabledescr=>tablekind_std   " Tabellentyp STANDARD TABLE
                                                     p_unique     = abap_false                          " NON-UNIQUE KEY
                                                     p_key        = VALUE #(                            " CARRID, CONNID als KEY
                                                                             ( name = 'CARRID' )
                                                                             ( name = 'CONNID' )
                                                                           )
                                                     p_key_kind   = cl_abap_tabledescr=>keydefkind_user " Benutzerdefinierter Schlüssel
                                                   ).

* Tabellenobjekt anhand des Tabellendeskriptors erstellen
    DATA: o_table TYPE REF TO data.
    CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt
    FIELD-SYMBOLS <table> TYPE ANY TABLE.
    ASSIGN o_table->* TO <table>.

* Daten holen und in Feldsymbol schreiben
    SELECT carrid, connid, carrname, fldate FROM sflights INTO CORRESPONDING FIELDS OF TABLE @<table>.

* Datenausgabe
    cl_demo_output=>display( <table> ).

  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

[ABAP] Vergleich Feldsymbole (FIELD-SYMBOLS) und Datenreferenzen (REF TO)

Feldsymbole (FIELD-SYMBOLS)

  • Alias / Referenz auf Datenbereich
  • Zuweisung erfolgt zur Laufzeit
  • Casting möglich: ASSIGN … TO CASTING TYPE typename.

Datenreferenzen (REF TO)

  • Pointer auf Datenobjekte
  • typisiert: … TYPE REF TO typename.
  • untypisiert: … TYPE REF TO data.
  • Casting möglich: CAST, ?=
  • Zurgiff erfolgt immer über Dereferenzierung (->, ->*)

[ABAP] Layer(Schichten)-Prinzip

Layer(Schichten)-Prinzip

  • Layers of abstraction: hierarchisch (ober -> unten)
  • ein Layer == eine Funktionalität für ein Problem
  • jeder Layer kommuniziert nur mit Layer darunter / darüber
  • Kommunikation zw. Layern über Interfaces (Protokolle)
  • Layerimplementierungen sind ersetzbar

Beispiel (classic three-tiere architecture)

  • Präsentation layer (UI + UI-Events)
  • Application layer (Applikation, Services)
  • Persistence layer (Persistenz, Data provider)

[ABAP] Abbildung von boolschen Werten im ABAP

Typen

Typ          Herkunft                  Anmerkung
----------------------------------------------------------------------------------------------------------------------------------
abap_bool    Typegruppe ABAP           empfohlen in den offiziellen ABAP Programming Guidelines
                                       Ab Release 7.40 sind bei Predicative Method Calls Rückgabewerte vom Typ ABAP_BOOL notwendig
                                       https://help.sap.com/doc/abapdocu_752_index_htm/7.52/de-DE/abenpredicative_method_calls.htm
boolean      Datenelement BOOLEAN      hat keine Feldbezeichner
xfeld        Datenelement XFELD        hat keine Feldbezeichner
os_boolean   Datenelement OS_BOOLEAN
wdy_boolean  Datenelement WDY_BOOLEAN
ddbool_d     Datenelement DDBOOL_D

Werte

boolscher Typ  ABAP-Konstante                ABAP-Wert  Definition         Datentyp  Länge
------------------------------------------------------------------------------------------
true           abap_true                     'X'        Typegruppe ABAP    char      1
false          abap_false                    ' '        Typegruppe ABAP    char      1
               abap_undefined                '-'        Typegruppe ABAP    char      1
true           cl_abap_typedescr=>true       'X'        cl_abap_typedescr  char      1
false          cl_abap_typedescr=>false      ' '        cl_abap_typedescr  char      1
               cl_abap_typedescr=>undefined  '-'        cl_abap_typedescr  char      1

[ABAP] Interne Tabellen: Schleifen mit FOR, THEN, WHILE, GROUPS, IN GROUP

Variante 1 (FOR … WHILE)

DATA(it_strings) = VALUE stringtab( ).

it_strings = VALUE #(
* For i = 1 To 10
                      FOR i = 1 WHILE i < 11
                      (
                        |{ i }|
                      )
                    ).

cl_demo_output=>display( it_strings ).

Variante 2 (FOR … WHILE mit Schrittweite)

                        
DATA(it_strings) = VALUE stringtab( ).

it_strings = VALUE #(
* For i = 1 To 10 Step 2
                      FOR i = 1 THEN i + 2 WHILE i < 11
                      (
                        |{ i }|
                      )
                    ).

cl_demo_output=>display( it_strings ).

Variante 3 (NESTED FOR)

                        
SELECT * FROM sflight INTO TABLE @DATA(it_sflight).
SELECT * FROM spfli INTO TABLE @DATA(it_spfli).

DATA(it_strings) = VALUE stringtab(
* alle Einträge aus sflight ab 01.01.2013
                                    FOR <f> IN it_sflight INDEX INTO idxf WHERE ( fldate >= '20130101' )
* alle Einträge aus spfli mit den Schlüsseln wie in der Ergebnismenge des vorherigen FOR
                                      FOR <c> IN it_spfli INDEX INTO idxc WHERE ( carrid = <f>-carrid AND connid = <f>-connid )
                                      (
* Ausgabe als Stringtab
                                        |{ idxf } \| { idxc } \| { <c>-carrid } \| { <c>-connid } \| { <c>-airpfrom }|
                                      )
                                  ).

cl_demo_output=>display( it_strings ).

Variante 4 (FOR GROUPS, FOR … IN GROUP)

TYPES: BEGIN OF ty_mat,
         matnr TYPE matnr,
         mtart TYPE mtart,
         price TYPE kbetr,
       END OF ty_mat.

TYPES: ty_it_mat TYPE HASHED TABLE OF ty_mat WITH UNIQUE KEY matnr
                                             WITH NON-UNIQUE SORTED KEY key_mtart COMPONENTS mtart.

TYPES: BEGIN OF ty_mat_sum,
         mtart TYPE mtart,
         count TYPE i,
         price TYPE kbetr,
       END OF ty_mat_sum.

TYPES: ty_it_mat_sum TYPE HASHED TABLE OF ty_mat_sum WITH UNIQUE KEY mtart.

* Tabelle mit Materialien
DATA(it_mat) = VALUE ty_it_mat(
                                ( matnr = '1' mtart = 'ROH'  price = '1.56' )
                                ( matnr = '2' mtart = 'ROH'  price = '2.00' )
                                ( matnr = '3' mtart = 'NLAG' price = '3.10' )
                                ( matnr = '4' mtart = 'NLAG' price = '0.40' )
                                ( matnr = '5' mtart = 'NLAG' price = '4.10' )
                                ( matnr = '6' mtart = 'HALB' price = '1.00' )
                                ( matnr = '7' mtart = 'HALB' price = '0.10' )
                              ).

* Tabelle gruppiert nach Materialarten ohne 'HALB' und summierten Preisen
DATA(it_mat_sum) = VALUE ty_it_mat_sum(
                                        FOR GROUPS grp OF <mtart> IN it_mat WHERE ( mtart NE 'HALB' ) GROUP BY ( mtart = <mtart>-mtart size = GROUP SIZE )
                                        (
                                          mtart = grp-mtart " Materialart der Gruppe
                                          count = grp-size  " Anz. Elemente der Gruppe
                                          price = REDUCE #( " Summe über die Elemente der akt. Gruppe bilden
                                                            INIT p = '0.00'
                                                            FOR <m> IN GROUP grp WHERE ( mtart = grp-mtart )
                                                            NEXT p = p + <m>-price
                                                          )
                                        )
                                      ).

cl_demo_output=>display( it_mat_sum ).

Links