ABAP BAPI Development: Business APIs erstellen und nutzen

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

BAPIs (Business Application Programming Interfaces) sind standardisierte Schnittstellen für den Zugriff auf SAP-Geschäftsobjekte. Sie folgen strengen Konventionen und ermöglichen eine einheitliche Integration.

BAPI-Konventionen

KonventionBeschreibung
NamensgebungBAPI_<OBJEKT>_<AKTION>
RETURN-ParameterImmer BAPIRET2 oder BAPIRET2_T
Kein COMMITAufrufer ist verantwortlich
Keine DialogeKeine Popups oder Messages
RFC-fähigRemotefähiger Funktionsbaustein

BAPIRET2-Struktur

FeldBeschreibung
TYPES/E/W/I/A (Success/Error/Warning/Info/Abort)
IDNachrichtenklasse
NUMBERNachrichtennummer
MESSAGEVollständiger Nachrichtentext
MESSAGE_V1-V4Variablen
LOG_NOLog-Nummer
LOG_MSG_NOLog-Nachrichtennummer

Beispiele

1. Standard-BAPI aufrufen

" BAPI zum Lesen eines Kunden
DATA: ls_address TYPE bapicustomer_04,
lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2'
EXPORTING
customerno = '0000001000'
IMPORTING
customeraddress = ls_address
TABLES
return = lt_return.
" Fehlerprüfung
IF line_exists( lt_return[ type = 'E' ] ).
" Fehler behandeln
LOOP AT lt_return INTO DATA(ls_error) WHERE type = 'E'.
WRITE: / ls_error-message.
ENDLOOP.
ELSE.
" Erfolg
WRITE: / ls_address-name, ls_address-city.
ENDIF.

2. BAPI mit COMMIT

DATA: lt_return TYPE TABLE OF bapiret2.
" Bestellung anlegen
CALL FUNCTION 'BAPI_PO_CREATE1'
EXPORTING
poheader = ls_header
poheaderx = ls_headerx
TABLES
poitem = lt_items
poitemx = lt_itemsx
return = lt_return.
" Fehlerprüfung
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0.
" Erfolg - COMMIT durchführen
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = abap_true. " Warten auf Commit
WRITE: / 'Bestellung angelegt'.
ELSE.
" Fehler - ROLLBACK
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
" Fehlermeldungen ausgeben
LOOP AT lt_return INTO DATA(ls_msg) WHERE type CA 'EAX'.
WRITE: / ls_msg-message.
ENDLOOP.
ENDIF.

3. Eigenen BAPI erstellen

" Funktionsbaustein: Z_BAPI_CUSTOMER_GETLIST
FUNCTION z_bapi_customer_getlist.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(IV_COUNTRY) TYPE LAND1 OPTIONAL
*" VALUE(IV_MAX_ROWS) TYPE I DEFAULT 100
*" EXPORTING
*" VALUE(ET_CUSTOMERS) TYPE ZTT_CUSTOMER_LIST
*" TABLES
*" RETURN STRUCTURE BAPIRET2
*"----------------------------------------------------------------------
" Eingabevalidierung
IF iv_max_rows < 1 OR iv_max_rows > 10000.
append_return(
EXPORTING
iv_type = 'E'
iv_id = 'ZCUST'
iv_number = '001'
iv_v1 = CONV #( iv_max_rows )
CHANGING
ct_return = return[]
).
RETURN.
ENDIF.
" Daten lesen
TRY.
SELECT kunnr, name1, ort01, land1
FROM kna1
WHERE land1 = @iv_country OR @iv_country IS INITIAL
INTO CORRESPONDING FIELDS OF TABLE @et_customers
UP TO @iv_max_rows ROWS.
IF sy-subrc <> 0.
append_return(
EXPORTING
iv_type = 'I'
iv_id = 'ZCUST'
iv_number = '002'
CHANGING
ct_return = return[]
).
ELSE.
append_return(
EXPORTING
iv_type = 'S'
iv_id = 'ZCUST'
iv_number = '003'
iv_v1 = CONV #( lines( et_customers ) )
CHANGING
ct_return = return[]
).
ENDIF.
CATCH cx_root INTO DATA(lx_error).
append_return(
EXPORTING
iv_type = 'E'
iv_id = 'ZCUST'
iv_number = '004'
iv_v1 = lx_error->get_text( )(50)
CHANGING
ct_return = return[]
).
ENDTRY.
ENDFUNCTION.
" Hilfsmethode zum Hinzufügen von RETURN-Einträgen
FORM append_return
USING
iv_type TYPE sy-msgty
iv_id TYPE sy-msgid
iv_number TYPE sy-msgno
iv_v1 TYPE clike OPTIONAL
iv_v2 TYPE clike OPTIONAL
iv_v3 TYPE clike OPTIONAL
iv_v4 TYPE clike OPTIONAL
CHANGING
ct_return TYPE bapiret2_t.
DATA: ls_return TYPE bapiret2,
lv_text TYPE string.
MESSAGE ID iv_id TYPE iv_type NUMBER iv_number
WITH iv_v1 iv_v2 iv_v3 iv_v4
INTO lv_text.
ls_return-type = iv_type.
ls_return-id = iv_id.
ls_return-number = iv_number.
ls_return-message = lv_text.
ls_return-message_v1 = iv_v1.
ls_return-message_v2 = iv_v2.
ls_return-message_v3 = iv_v3.
ls_return-message_v4 = iv_v4.
APPEND ls_return TO ct_return.
ENDFORM.

4. BAPI-Wrapper-Klasse

CLASS zcl_customer_bapi DEFINITION.
PUBLIC SECTION.
TYPES: BEGIN OF ty_customer,
kunnr TYPE kunnr,
name1 TYPE name1_gp,
ort01 TYPE ort01_gp,
land1 TYPE land1_gp,
END OF ty_customer,
ty_customers TYPE STANDARD TABLE OF ty_customer WITH KEY kunnr.
METHODS: get_customer
IMPORTING iv_kunnr TYPE kunnr
RETURNING VALUE(rs_customer) TYPE ty_customer
RAISING zcx_bapi_error.
METHODS: get_customers_by_country
IMPORTING iv_country TYPE land1
RETURNING VALUE(rt_customers) TYPE ty_customers
RAISING zcx_bapi_error.
METHODS: create_customer
IMPORTING is_data TYPE ty_customer
RETURNING VALUE(rv_kunnr) TYPE kunnr
RAISING zcx_bapi_error.
PRIVATE SECTION.
METHODS: check_return
IMPORTING it_return TYPE bapiret2_t
RAISING zcx_bapi_error.
ENDCLASS.
CLASS zcl_customer_bapi IMPLEMENTATION.
METHOD get_customer.
DATA: ls_address TYPE bapicustomer_04,
lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2'
EXPORTING
customerno = iv_kunnr
IMPORTING
customeraddress = ls_address
TABLES
return = lt_return.
check_return( lt_return ).
rs_customer = VALUE #(
kunnr = iv_kunnr
name1 = ls_address-name
ort01 = ls_address-city
land1 = ls_address-country
).
ENDMETHOD.
METHOD get_customers_by_country.
DATA: lt_address TYPE TABLE OF bapicustomer_04,
lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST'
TABLES
addressdata = lt_address
return = lt_return.
check_return( lt_return ).
rt_customers = VALUE #(
FOR ls_addr IN lt_address
WHERE ( country = iv_country OR iv_country IS INITIAL )
( kunnr = ls_addr-customer
name1 = ls_addr-name
ort01 = ls_addr-city
land1 = ls_addr-country )
).
ENDMETHOD.
METHOD create_customer.
DATA: lt_return TYPE TABLE OF bapiret2.
" BAPI zum Anlegen...
CALL FUNCTION 'BAPI_CUSTOMER_CREATE...'
" Parameter...
TABLES
return = lt_return.
check_return( lt_return ).
" Bei Erfolg COMMIT
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = abap_true.
rv_kunnr = '...'. " Neue Kundennummer
ENDMETHOD.
METHOD check_return.
" Fehler in RETURN prüfen
LOOP AT it_return INTO DATA(ls_return)
WHERE type CA 'EAX'.
RAISE EXCEPTION TYPE zcx_bapi_error
EXPORTING
textid = zcx_bapi_error=>bapi_error
msgid = ls_return-id
msgno = ls_return-number
msgv1 = ls_return-message_v1
msgv2 = ls_return-message_v2
msgv3 = ls_return-message_v3
msgv4 = ls_return-message_v4.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
" Verwendung
TRY.
DATA(lo_customer) = NEW zcl_customer_bapi( ).
DATA(ls_customer) = lo_customer->get_customer( '0000001000' ).
WRITE: / ls_customer-name1, ls_customer-ort01.
CATCH zcx_bapi_error INTO DATA(lx_error).
WRITE: / 'Fehler:', lx_error->get_text( ).
ENDTRY.

5. BAPI für Massenverarbeitung

FUNCTION z_bapi_orders_create_mass.
*"----------------------------------------------------------------------
*" IMPORTING
*" VALUE(IT_ORDERS) TYPE ZTT_ORDER_CREATE
*" EXPORTING
*" VALUE(ET_SUCCESS) TYPE ZTT_ORDER_NUMBERS
*" VALUE(ET_FAILED) TYPE ZTT_ORDER_FAILED
*" TABLES
*" RETURN STRUCTURE BAPIRET2
*"----------------------------------------------------------------------
DATA: lt_order_return TYPE TABLE OF bapiret2,
lv_order_no TYPE vbeln.
LOOP AT it_orders INTO DATA(ls_order).
CLEAR: lt_order_return, lv_order_no.
" Einzelne Bestellung anlegen
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
EXPORTING
order_header_in = ls_order-header
IMPORTING
salesdocument = lv_order_no
TABLES
return = lt_order_return
order_items_in = ls_order-items
order_partners = ls_order-partners.
" Prüfen
READ TABLE lt_order_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0 AND lv_order_no IS NOT INITIAL.
" Erfolg
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = abap_true.
APPEND VALUE #( order_no = lv_order_no ) TO et_success.
APPEND VALUE #(
type = 'S'
id = 'ZORD'
number = '001'
message = |Bestellung { lv_order_no } angelegt|
) TO return.
ELSE.
" Fehler
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
APPEND VALUE #(
index = sy-tabix
messages = lt_order_return
) TO et_failed.
APPEND LINES OF lt_order_return TO return.
ENDIF.
ENDLOOP.
" Zusammenfassung
APPEND VALUE #(
type = 'I'
id = 'ZORD'
number = '002'
message = |{ lines( et_success ) } erfolgreich, { lines( et_failed ) } fehlgeschlagen|
) TO return.
ENDFUNCTION.

6. BAPI Exception-Klasse

CLASS zcx_bapi_error DEFINITION
INHERITING FROM cx_static_check
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES: if_t100_message.
CONSTANTS:
BEGIN OF bapi_error,
msgid TYPE symsgid VALUE 'ZBAPI',
msgno TYPE symsgno VALUE '001',
attr1 TYPE scx_attrname VALUE 'MSGV1',
attr2 TYPE scx_attrname VALUE 'MSGV2',
attr3 TYPE scx_attrname VALUE 'MSGV3',
attr4 TYPE scx_attrname VALUE 'MSGV4',
END OF bapi_error.
DATA: msgid TYPE sy-msgid,
msgno TYPE sy-msgno,
msgv1 TYPE sy-msgv1,
msgv2 TYPE sy-msgv2,
msgv3 TYPE sy-msgv3,
msgv4 TYPE sy-msgv4.
METHODS: constructor
IMPORTING
textid LIKE if_t100_message=>t100key OPTIONAL
previous LIKE previous OPTIONAL
msgid TYPE sy-msgid OPTIONAL
msgno TYPE sy-msgno OPTIONAL
msgv1 TYPE sy-msgv1 OPTIONAL
msgv2 TYPE sy-msgv2 OPTIONAL
msgv3 TYPE sy-msgv3 OPTIONAL
msgv4 TYPE sy-msgv4 OPTIONAL.
CLASS-METHODS: from_bapiret2
IMPORTING is_return TYPE bapiret2
RETURNING VALUE(ro_error) TYPE REF TO zcx_bapi_error.
CLASS-METHODS: from_bapiret2_table
IMPORTING it_return TYPE bapiret2_t
RETURNING VALUE(ro_error) TYPE REF TO zcx_bapi_error.
ENDCLASS.
CLASS zcx_bapi_error IMPLEMENTATION.
METHOD constructor.
super->constructor( previous = previous ).
me->msgid = msgid.
me->msgno = msgno.
me->msgv1 = msgv1.
me->msgv2 = msgv2.
me->msgv3 = msgv3.
me->msgv4 = msgv4.
IF textid IS INITIAL.
if_t100_message~t100key = bapi_error.
ELSE.
if_t100_message~t100key = textid.
ENDIF.
ENDMETHOD.
METHOD from_bapiret2.
ro_error = NEW #(
msgid = is_return-id
msgno = is_return-number
msgv1 = is_return-message_v1
msgv2 = is_return-message_v2
msgv3 = is_return-message_v3
msgv4 = is_return-message_v4
).
ENDMETHOD.
METHOD from_bapiret2_table.
" Erste Fehlermeldung verwenden
LOOP AT it_return INTO DATA(ls_return) WHERE type CA 'EAX'.
ro_error = from_bapiret2( ls_return ).
RETURN.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

7. BAPI über RFC aufrufen

DATA: lt_return TYPE TABLE OF bapiret2.
" RFC-Destination
DATA(lv_destination) = 'PRD_CLNT100'.
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST'
DESTINATION lv_destination
TABLES
addressdata = lt_address
return = lt_return
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message
OTHERS = 3.
IF sy-subrc <> 0.
WRITE: / 'RFC-Fehler:', lv_message.
ELSE.
" BAPI-Rückgabe prüfen
check_return( lt_return ).
ENDIF.

8. BAPI mit Update Task

FUNCTION z_bapi_document_save.
*"----------------------------------------------------------------------
*" IMPORTING
*" VALUE(IS_DOCUMENT) TYPE TY_DOCUMENT
*" TABLES
*" RETURN STRUCTURE BAPIRET2
*"----------------------------------------------------------------------
" Validierung
perform_validation(
EXPORTING is_document = is_document
CHANGING ct_return = return[]
).
IF line_exists( return[ type = 'E' ] ).
RETURN.
ENDIF.
" Speicherung in Update Task
CALL FUNCTION 'Z_UPDATE_DOCUMENT' IN UPDATE TASK
EXPORTING
is_document = is_document.
" Erfolgsmeldung
APPEND VALUE bapiret2(
type = 'S'
id = 'ZDOC'
number = '001'
message = 'Dokument wird gespeichert'
) TO return.
" COMMIT wird vom Aufrufer durchgeführt!
ENDFUNCTION.

9. BAPI-Hilfsfunktionen

CLASS zcl_bapi_helper DEFINITION.
PUBLIC SECTION.
" Prüft ob RETURN Fehler enthält
CLASS-METHODS: has_errors
IMPORTING it_return TYPE bapiret2_t
RETURNING VALUE(rv_error) TYPE abap_bool.
" Filtert Nachrichten nach Typ
CLASS-METHODS: get_messages_by_type
IMPORTING it_return TYPE bapiret2_t
iv_type TYPE sy-msgty
RETURNING VALUE(rt_messages) TYPE bapiret2_t.
" Konvertiert RETURN zu String
CLASS-METHODS: return_to_string
IMPORTING it_return TYPE bapiret2_t
RETURNING VALUE(rv_string) TYPE string.
" Fügt Nachricht hinzu
CLASS-METHODS: add_message
IMPORTING iv_type TYPE sy-msgty
iv_id TYPE sy-msgid
iv_number TYPE sy-msgno
iv_v1 TYPE clike OPTIONAL
iv_v2 TYPE clike OPTIONAL
iv_v3 TYPE clike OPTIONAL
iv_v4 TYPE clike OPTIONAL
CHANGING ct_return TYPE bapiret2_t.
ENDCLASS.
CLASS zcl_bapi_helper IMPLEMENTATION.
METHOD has_errors.
rv_error = xsdbool(
line_exists( it_return[ type = 'E' ] ) OR
line_exists( it_return[ type = 'A' ] ) OR
line_exists( it_return[ type = 'X' ] )
).
ENDMETHOD.
METHOD get_messages_by_type.
rt_messages = FILTER #( it_return WHERE type = iv_type ).
ENDMETHOD.
METHOD return_to_string.
LOOP AT it_return INTO DATA(ls_return).
IF rv_string IS NOT INITIAL.
rv_string = rv_string && cl_abap_char_utilities=>newline.
ENDIF.
rv_string = rv_string && |{ ls_return-type }: { ls_return-message }|.
ENDLOOP.
ENDMETHOD.
METHOD add_message.
DATA: ls_return TYPE bapiret2,
lv_text TYPE string.
MESSAGE ID iv_id TYPE iv_type NUMBER iv_number
WITH iv_v1 iv_v2 iv_v3 iv_v4
INTO lv_text.
ls_return = VALUE #(
type = iv_type
id = iv_id
number = iv_number
message = lv_text
message_v1 = iv_v1
message_v2 = iv_v2
message_v3 = iv_v3
message_v4 = iv_v4
).
APPEND ls_return TO ct_return.
ENDMETHOD.
ENDCLASS.
" Verwendung
DATA: lt_return TYPE bapiret2_t.
zcl_bapi_helper=>add_message(
EXPORTING
iv_type = 'S'
iv_id = 'ZMSG'
iv_number = '001'
iv_v1 = 'Erfolg'
CHANGING
ct_return = lt_return
).
IF zcl_bapi_helper=>has_errors( lt_return ).
DATA(lv_errors) = zcl_bapi_helper=>return_to_string( lt_return ).
MESSAGE lv_errors TYPE 'E'.
ENDIF.

10. BAPI Explorer (BAPI)

Transaktion: BAPI
1. Business Object auswählen (z.B. Customer)
2. Methoden anzeigen (GetList, GetDetail, Create, etc.)
3. Dokumentation und Parameter einsehen
4. Funktionsbaustein-Name ermitteln
5. Testmöglichkeit über SE37

11. Wichtige Standard-BAPIs

" Kunden
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST'. " Kunden auflisten
CALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2'. " Kundendetails
CALL FUNCTION 'BAPI_CUSTOMER_CREATEFROMDAT1'. " Kunde anlegen
" Lieferanten
CALL FUNCTION 'BAPI_VENDOR_GETLIST'. " Lieferanten auflisten
CALL FUNCTION 'BAPI_VENDOR_GETDETAIL'. " Lieferantendetails
" Materialien
CALL FUNCTION 'BAPI_MATERIAL_GETLIST'. " Materialien auflisten
CALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL'. " Materialdetails
" Bestellungen
CALL FUNCTION 'BAPI_PO_CREATE1'. " Bestellung anlegen
CALL FUNCTION 'BAPI_PO_CHANGE'. " Bestellung ändern
CALL FUNCTION 'BAPI_PO_GETDETAIL'. " Bestelldetails
" Aufträge
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'. " Auftrag anlegen
CALL FUNCTION 'BAPI_SALESORDER_GETLIST'. " Aufträge auflisten
CALL FUNCTION 'BAPI_SALESORDER_CHANGE'. " Auftrag ändern
" Buchungen
CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST'. " FI-Beleg buchen
" Transaktionssteuerung
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'. " Commit
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. " Rollback

BAPI Checkliste

✓ Funktionsbaustein ist RFC-fähig
✓ RETURN-Parameter vom Typ BAPIRET2
✓ Kein COMMIT WORK im BAPI
✓ Keine MESSAGE-Anweisungen
✓ Keine Dialogaufrufe (Popups)
✓ Vollständige Fehlerbehandlung
✓ Dokumentation der Parameter
✓ Berechtigungsprüfung implementiert
✓ Eingabevalidierung vorhanden
✓ Testbar über SE37

Wichtige Hinweise / Best Practice

  • COMMIT WORK nie im BAPI – der Aufrufer entscheidet.
  • RETURN immer mit aussagekräftigen Nachrichten füllen.
  • RFC-fähig für Remote-Aufrufe markieren.
  • Keine MESSAGE-Statements – nur RETURN befüllen.
  • Berechtigungsprüfung im BAPI implementieren.
  • Eingabevalidierung vor Verarbeitung.
  • Wrapper-Klassen für einfache Verwendung.
  • BAPI Explorer (Transaktion BAPI) für Dokumentation.
  • Massenverarbeitung mit einzelnen COMMITs pro Datensatz.
  • Kombinieren Sie mit Exception Classes für OO-Integration.