[ABAP] Testen, ob per RFC ein Funktionsbaustein im Zielsystem vorhanden ist

* https://www.berater-wiki.de/RFC-Funktionsbausteine
* https://download.consolut.com/direct/SAP_PrintDoku/de/BCFESDE2/BCFESDE2.PDF

* Funktionsbaustein-Name, verwendet Suchhilfe pb_func_key
PARAMETERS: p_func TYPE rs38l_fnam MATCHCODE OBJECT pb_func_key.
* RFC-Verbindung
PARAMETERS: p_rfc TYPE rfcdest.

START-OF-SELECTION.

* Nachschauen, ob RFC-Verbindung vorhanden
  SELECT SINGLE d~rfcdest, d~rfctype, d~rfcoptions, t~rfcdoc1, t~rfcdoc2, t~rfcdoc3
    INTO @DATA(lv_rfc)
    FROM rfcdes AS d
    INNER JOIN rfcdoc AS t ON ( d~rfcdest = t~rfcdest )
    WHERE d~rfcdest = @p_rfc
      AND t~rfclang = @sy-langu.

  IF sy-subrc = 0.
    DATA: lv_err_msg TYPE char255.
* wenn RFC-Verbindung vorhanden -> anpingen und Systemfehler (Dumps) abfangen
    CALL FUNCTION 'RFC_PING' DESTINATION p_rfc
      EXCEPTIONS
        system_failure        = 1 MESSAGE lv_err_msg
        communication_failure = 2 MESSAGE lv_err_msg
        OTHERS                = 3.

    IF sy-subrc = 0.
* RFC-Ping ok
      WRITE: / '[', p_rfc, '] RFC-Aufruf erfolgreich.'.

* Existenzprüfung und Funktionsgruppe zu Funktionsbaustein besorgen
      CALL FUNCTION 'FUNCTION_EXISTS' DESTINATION p_rfc
        EXPORTING
          funcname           = p_func
        EXCEPTIONS
          function_not_exist = 1
          OTHERS             = 2.

      IF sy-subrc = 0.
        WRITE: / 'Funktionsbaustein:', p_func, 'existiert im Zielsystem:', p_rfc.
      ELSE.
        WRITE: / 'Funktionsbaustein:', p_func, 'existiert nicht im Zielsystem:', p_rfc.
      ENDIF.
    ELSE.
* RFC-Ping fehlerhaft
      WRITE: / '[', p_rfc, '] RFC-Aufruf gescheitert:', lv_err_msg.
    ENDIF.
  ELSE.
* RFC-Verbindung nicht vorhanden
    WRITE: / '[', p_rfc, '] RFC-Verbindung nicht vorhanden.'.
  ENDIF.

[ABAP] Angemeldete User eines Servers auslesen und IP-Adressen ermitteln

* lokale Server ermitteln
DATA: it_server_list_v4 TYPE STANDARD TABLE OF msxxlist WITH DEFAULT KEY.
DATA: it_server_list_v6 TYPE STANDARD TABLE OF msxxlist_v6 WITH DEFAULT KEY.

CALL FUNCTION 'TH_SERVER_LIST'
  TABLES
    list           = it_server_list_v4
    list_ipv6      = it_server_list_v6
  EXCEPTIONS
    no_server_list = 1
    OTHERS         = 2.

IF sy-subrc = 0.

  LOOP AT it_server_list_v6 ASSIGNING FIELD-SYMBOL(<s>).

    WRITE: / |{ <s>-host } ({ <s>-hostaddr_v4_str })|.

    DATA: it_users TYPE STANDARD TABLE OF uinfo WITH DEFAULT KEY.

* Angemeldete User einer SAP-Instanz holen
    CALL FUNCTION 'THUSRINFO' DESTINATION <s>-name
      TABLES
        usr_tabl              = it_users
      EXCEPTIONS
        system_failure        = 1
        communication_failure = 2
        OTHERS                = 3.

    IF sy-subrc = 0.
* Name, Terminal, IP-Adresse ausgeben
      LOOP AT it_users ASSIGNING FIELD-SYMBOL(<u>).

        DATA(lv_ip_user) = ||.

* IP besteht aus 4x HEX-Wert
        IF xstrlen( <u>-hostadr ) = 4.
* jeder Hex-Wert wird in Integer konvertiert
          lv_ip_user = |{ CONV i( <u>-hostadr+0(1) ) }.{ CONV i( <u>-hostadr+1(1) ) }.{ CONV i( <u>-hostadr+2(1) ) }.{ CONV i( <u>-hostadr+3(1) ) }|.
        ENDIF.

        WRITE: / '    ', <u>-bname, <u>-term, lv_ip_user.

      ENDLOOP.
    ENDIF.

  ENDLOOP.
ENDIF.

[ABAP] Testen, ob eine RFC-Verbindung vorhanden ist und funktioniert

PARAMETERS: p_rfc TYPE rfcdest.

START-OF-SELECTION.

* Nachschauen, ob RFC-Verbindung vorhanden
  SELECT SINGLE d~rfcdest, d~rfctype, d~rfcoptions, t~rfcdoc1, t~rfcdoc2, t~rfcdoc3
    INTO @DATA(lv_rfc)
    FROM rfcdes AS d
    INNER JOIN rfcdoc AS t ON ( d~rfcdest = t~rfcdest )
    WHERE d~rfcdest = @p_rfc
      AND t~rfclang = @sy-langu.

  IF sy-subrc = 0.
    WRITE: / '[', p_rfc, ']', lv_rfc-rfcdest, lv_rfc-rfctype, lv_rfc-rfcoptions, lv_rfc-rfcdoc1, lv_rfc-rfcdoc2, lv_rfc-rfcdoc3.

    DATA: lv_err_msg TYPE char255.
* wenn RFC-Verbindung vorhanden -> anpingen und Systemfehler (Dumps) abfangen
    CALL FUNCTION 'RFC_PING' DESTINATION p_rfc
      EXCEPTIONS
        system_failure        = 1 MESSAGE lv_err_msg
        communication_failure = 2 MESSAGE lv_err_msg
        OTHERS                = 3.

    IF sy-subrc = 0.
* RFC-Ping ok
      WRITE: / '[', p_rfc, '] RFC-Aufruf erfolgreich.'.
    ELSE.
* RFC-Ping fehlerhaft
      WRITE: / '[', p_rfc, '] RFC-Aufruf gescheitert:', lv_err_msg.
    ENDIF.
  ELSE.
* RFC-Verbindung nicht vorhanden
    WRITE: / '[', p_rfc, '] RFC-Verbindung nicht vorhanden.'.
  ENDIF.

[ABAP] RFC-Aufruf einer Transaktion

DATA: it_error TYPE STANDARD TABLE OF bdcmsgcoll.

DATA: lv_rc TYPE sy-subrc.

* Batch
DATA(it_batch) = VALUE bdcdata_tab( ( dynbegin = 'T' fnam = 'FD03' )
                                    ( program = 'SAPMF02D' dynpro = '0106' dynbegin = 'X' )
                                    ( fnam = 'RF02D-KUNNR' fval = '40000' )
                                    ( fnam = 'RF02D-BUKRS' fval = '' )
                                    ( fnam = 'RF02D-D0110' fval = abap_true )
                                    ( fnam = 'RF02D-D0120' fval = abap_true )
                                    ( fnam = 'BDC_OKCODE'  fval = '/00' ) ).

* RFC-Aufruf
CALL FUNCTION 'RFC_CALL_TRANSACTION_USING'
  DESTINATION 'XYZ'
  EXPORTING
    tcode                   = 'FD03'
    mode                    = 'E'
  IMPORTING
    subrc                   = lv_rc
  TABLES
    bt_data                 = it_batch
    l_errors                = it_error
  EXCEPTIONS
    authority_not_available = 1
    OTHERS                  = 2.

* Datenausgabe
WRITE: / sy-subrc.
WRITE: / lv_rc.

LOOP AT it_batch ASSIGNING FIELD-SYMBOL(<b>).
  WRITE: / <b>-program, <b>-dynpro, <b>-dynbegin, <b>-fnam, <b>-fval.
ENDLOOP.

LOOP AT it_error ASSIGNING FIELD-SYMBOL(<e>).
  WRITE: / <e>-tcode, <e>-dyname, <e>-dynumb, <e>-msgtyp, <e>-msgspra, <e>-msgid, <e>-msgnr, <e>-msgv1, <e>-msgv2, <e>-msgv3, <e>-msgv4, <e>-env, <e>-fldname.
ENDLOOP.

[ABAP] Textobjekte per RFC lesen

DATA: lv_rfc_syst TYPE sy-sysid.
DATA: it_txt_lines TYPE STANDARD TABLE OF ibiptextln.
DATA: it_ret TYPE STANDARD TABLE OF bapiret2.
DATA: it_links TYPE STANDARD TABLE OF bapi_doc_drad_keys.

lv_rfc_syst = sy-sysid.

it_txt_lines = VALUE #( ( tdobject = 'MATERIAL' tdid = 'BEST' tdname = '000000001234567890' tdspras = 'DE' ) ).

CALL FUNCTION 'RFC_READ_TEXT' DESTINATION lv_rfc_syst
  TABLES
    text_lines  = it_txt_lines
    messages    = it_ret
    objectlinks = it_links.

IF lines( it_ret ) = 0.
  LOOP AT it_txt_lines ASSIGNING FIELD-SYMBOL(<fs_txt_line>).
    WRITE: / <fs_txt_line>-tdline.
  ENDLOOP.
ENDIF.

[ABAP] Tabellenzugriff per RFC-Baustein

DATA: lv_max_rows TYPE soid-accnt VALUE '100'.       " auf 100 Einträge begrenzen, 0 - alle
DATA: lv_separator TYPE char1 VALUE ';'.             " Spaltenseparator
DATA: it_rfc_stxh TYPE STANDARD TABLE OF char512.    " RFC-Datentabelle, Spaltensumme max 512 Zeichen, da Rückgabetyp Zeile -> TAB512
                                                     " das Problem kann man "umgehen", indem man die Spalten einzeln einliest (Performance!)
DATA: it_fields TYPE STANDARD TABLE OF rfc_db_fld.   " Namen der Spalten
DATA: it_options TYPE STANDARD TABLE OF rfc_db_opt.  " 72 Zeichen
DATA: it_stxh TYPE STANDARD TABLE OF stxh.           " umgewandelte Ausgabetabelle mit richtigen DDIC-Datentypen
DATA: it_split_values TYPE STANDARD TABLE OF string. " Splitzeile für Datenkonvertierung

* Spalten
it_fields = VALUE #( ( fieldname = 'TDOBJECT' )
                     ( fieldname = 'TDNAME' )
                     ( fieldname = 'TDID' )
                     ( fieldname = 'TDTITLE' )
                     ( fieldname = 'TDLUSER' ) ).

* WHERE-Bedingung
it_options = VALUE #( ( |TDOBJECT EQ 'TEXT' AND TDID EQ 'ADRS'| ) ).

* Daten per RFC aus Fremdsystem holen, Userlogin wird abgefragt
* Nachteil: es sind nur einfache Tabellenabfragen möglich, keine JOINS
CALL FUNCTION 'RFC_READ_TABLE' DESTINATION 'XA1'
  EXPORTING
    query_table           = 'STXH'
    delimiter             = lv_separator
    rowcount              = lv_max_rows
  TABLES
    options               = it_options
    fields                = it_fields   " Aufruf: Liste der zu lesenden Felder, Rückgabe: Zu jedem Feld Offset, Länge, Typ, Kurztext
    data                  = it_rfc_stxh
  EXCEPTIONS
    table_not_available   = 1
    table_without_data    = 2
    option_not_valid      = 3
    field_not_valid       = 4
    not_authorized        = 5
    data_buffer_exceeded  = 6
    system_failure        = 7
    communication_failure = 8
    OTHERS                = 9.

IF sy-subrc = 0.
  TRY .
* Datenausgabe
      LOOP AT it_rfc_stxh ASSIGNING FIELD-SYMBOL(<rfc_stxh_line>).

* neue Zeile in der Ausgabetabelle erzeugen
        APPEND INITIAL LINE TO it_stxh ASSIGNING FIELD-SYMBOL(<stxh>).
* Elemente der Datenzeile am Separator splitten
        SPLIT <rfc_stxh_line> AT lv_separator INTO TABLE it_split_values.
* Elemente ausgeben
        LOOP AT it_split_values ASSIGNING FIELD-SYMBOL(<value>).
* Spalte + Zelle der Ausgabetabelle anhand des Spaltennamens holen
* es werden nur Werte die Spalten gefüllt, die in it_fields deklariert wurden
          ASSIGN COMPONENT it_fields[ sy-tabix ]-fieldname OF STRUCTURE <stxh> TO FIELD-SYMBOL(<cell>).
          IF <cell> IS ASSIGNED.
* Split-Wert in die Zelle schreiben
            <cell> = condense( val = <value> ).
          ENDIF.

        ENDLOOP.
      ENDLOOP.

* Ausgabe
* Header
      DATA(lv_head) = ||.

      LOOP AT it_fields ASSIGNING FIELD-SYMBOL(<field>).
        DATA(lv_sl) = strlen( <field>-fieldname ).
        DATA(lv_width) = COND i( WHEN lv_sl < <field>-length THEN lv_sl ELSE <field>-length ).
        lv_head = |{ lv_head }{ substring( val = <field>-fieldname off = 0 len = lv_width ) WIDTH = <field>-length + 1 }|.
      ENDLOOP.

      WRITE: / lv_head.

* Daten
      LOOP AT it_stxh ASSIGNING FIELD-SYMBOL(<line>).
        WRITE: / <line>-tdobject, <line>-tdname, <line>-tdid, <line>-tdtitle, <line>-tdluser.
      ENDLOOP.

    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.
ELSE.
  WRITE: / 'Fehler:', sy-subrc.
ENDIF.

[ABAP] Eine Transaktion in einem neuen Fenster (Task) aufrufen

DATA: it_params TYPE STANDARD TABLE OF tpara.

START-OF-SELECTION.
* Parameter für die Transaktion
  it_params = VALUE #( ( paramid = 'BUK' partext = '0001' )
                       ( paramid = 'BLN' partext = '12345678' )
                       ( paramid = 'GJR' partext = '2016' ) ).

* RFC-Aufruf für Transaktion FB03 in neuem Task
  CALL FUNCTION 'CC_CALL_TRANSACTION_NEW_TASK' STARTING NEW TASK 'FB03_TASK' DESTINATION 'NONE'
    EXPORTING
      transaction           = 'FB03'
      skip_first_screen     = abap_false
    TABLES
      paramtab              = it_params
    EXCEPTIONS
      communication_failure = 97
      system_failure        = 98
      OTHERS                = 99.

  IF sy-subrc NE 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

[ABAP] Prüfen, ob ein Funktionsbaustein oder Programm per RFC aufgerufen wurde

DATA: lv_caller_in_same_system TYPE answer.

* RFC-Ausführung im gleichen R/3-System ?
CALL FUNCTION 'RFC_WITHIN_SAME_SYSTEM'
  IMPORTING
    caller_in_same_system     = lv_caller_in_same_system
  EXCEPTIONS
    system_call_not_supported = 1
    no_rfc_communication      = 2
    internal_error            = 3
    OTHERS                    = 4.

WRITE: / 'Same system:', lv_caller_in_same_system.
WRITE: / sy-subrc.

oder

CALL 'RFCControl' ID 'CODE' FIELD 'B'.
IF sy-subrc = 0.
  WRITE:/ 'RFC'.
ENDIF.