Developpement BAPI ABAP : Creer et utiliser des Business APIs

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

Les BAPIs (Business Application Programming Interfaces) sont des interfaces standardisees pour l’acces aux objets metier SAP. Ils suivent des conventions strictes et permettent une integration uniforme.

Conventions BAPI

ConventionDescription
NommageBAPI_<OBJET>_<ACTION>
Parametre RETURNToujours BAPIRET2 ou BAPIRET2_T
Pas de COMMITL’appelant est responsable
Pas de dialoguesPas de popups ou messages
Compatible RFCModule fonction compatible RFC

Structure BAPIRET2

ChampDescription
TYPES/E/W/I/A (Success/Error/Warning/Info/Abort)
IDClasse de message
NUMBERNumero de message
MESSAGETexte de message complet
MESSAGE_V1-V4Variables
LOG_NONumero de log
LOG_MSG_NONumero de message du log

Exemples

1. Appeler un BAPI standard

" BAPI pour lire un client
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.
" Verification des erreurs
IF line_exists( lt_return[ type = 'E' ] ).
" Traiter les erreurs
LOOP AT lt_return INTO DATA(ls_error) WHERE type = 'E'.
WRITE: / ls_error-message.
ENDLOOP.
ELSE.
" Succes
WRITE: / ls_address-name, ls_address-city.
ENDIF.

2. BAPI avec COMMIT

DATA: lt_return TYPE TABLE OF bapiret2.
" Creer une commande
CALL FUNCTION 'BAPI_PO_CREATE1"
EXPORTING
poheader = ls_header
poheaderx = ls_headerx
TABLES
poitem = lt_items
poitemx = lt_itemsx
return = lt_return.
" Verification des erreurs
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0.
" Succes - effectuer le COMMIT
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT"
EXPORTING
wait = abap_true. " Attendre le commit
WRITE: / 'Commande creee'.
ELSE.
" Erreur - ROLLBACK
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
" Afficher les messages d'erreur
LOOP AT lt_return INTO DATA(ls_msg) WHERE type CA 'EAX'.
WRITE: / ls_msg-message.
ENDLOOP.
ENDIF.

3. Creer son propre BAPI

" Module fonction : Z_BAPI_CUSTOMER_GETLIST
FUNCTION z_bapi_customer_getlist.
*"----------------------------------------------------------------------
*"*"Interface locale :
*" 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
*"----------------------------------------------------------------------
" Validation des entrees
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.
" Lire les donnees
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.
" Methode d'aide pour ajouter des entrees RETURN
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. Classe wrapper BAPI

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 pour creer...
CALL FUNCTION 'BAPI_CUSTOMER_CREATE..."
" Parametres...
TABLES
return = lt_return.
check_return( lt_return ).
" En cas de succes, COMMIT
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT"
EXPORTING wait = abap_true.
rv_kunnr = '...'. " Nouveau numero client
ENDMETHOD.
METHOD check_return.
" Verifier les erreurs dans RETURN
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.
" Utilisation
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: / 'Erreur :', lx_error->get_text( ).
ENDTRY.

5. BAPI pour traitement de masse

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.
" Creer une commande individuelle
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.
" Verifier
READ TABLE lt_order_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0 AND lv_order_no IS NOT INITIAL.
" Succes
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 = |Commande { lv_order_no } creee|
) TO return.
ELSE.
" Erreur
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.
" Resume
APPEND VALUE #(
type = 'I"
id = 'ZORD"
number = '002"
message = |{ lines( et_success ) } reussis, { lines( et_failed ) } echoues|
) TO return.
ENDFUNCTION.

6. Classe d’exception BAPI

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.
" Utiliser le premier message d'erreur
LOOP AT it_return INTO DATA(ls_return) WHERE type CA 'EAX'.
ro_error = from_bapiret2( ls_return ).
RETURN.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

7. Appeler un BAPI via RFC

DATA: lt_return TYPE TABLE OF bapiret2.
" Destination RFC
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: / 'Erreur RFC :', lv_message.
ELSE.
" Verifier le retour BAPI
check_return( lt_return ).
ENDIF.

8. BAPI avec Update Task

FUNCTION z_bapi_document_save.
*"----------------------------------------------------------------------
*" IMPORTING
*" VALUE(IS_DOCUMENT) TYPE TY_DOCUMENT
*" TABLES
*" RETURN STRUCTURE BAPIRET2
*"----------------------------------------------------------------------
" Validation
perform_validation(
EXPORTING is_document = is_document
CHANGING ct_return = return[]
).
IF line_exists( return[ type = 'E' ] ).
RETURN.
ENDIF.
" Enregistrement dans Update Task
CALL FUNCTION 'Z_UPDATE_DOCUMENT' IN UPDATE TASK
EXPORTING
is_document = is_document.
" Message de succes
APPEND VALUE bapiret2(
type = 'S"
id = 'ZDOC"
number = '001"
message = 'Le document sera enregistre"
) TO return.
" Le COMMIT sera effectue par l'appelant !
ENDFUNCTION.

9. Fonctions utilitaires BAPI

CLASS zcl_bapi_helper DEFINITION.
PUBLIC SECTION.
" Verifie si RETURN contient des erreurs
CLASS-METHODS: has_errors
IMPORTING it_return TYPE bapiret2_t
RETURNING VALUE(rv_error) TYPE abap_bool.
" Filtre les messages par type
CLASS-METHODS: get_messages_by_type
IMPORTING it_return TYPE bapiret2_t
iv_type TYPE sy-msgty
RETURNING VALUE(rt_messages) TYPE bapiret2_t.
" Convertit RETURN en string
CLASS-METHODS: return_to_string
IMPORTING it_return TYPE bapiret2_t
RETURNING VALUE(rv_string) TYPE string.
" Ajoute un message
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.
" Utilisation
DATA: lt_return TYPE bapiret2_t.
zcl_bapi_helper=>add_message(
EXPORTING
iv_type = 'S"
iv_id = 'ZMSG"
iv_number = '001"
iv_v1 = 'Succes"
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)

Transaction : BAPI
1. Selectionner l'objet metier (par ex. Customer)
2. Afficher les methodes (GetList, GetDetail, Create, etc.)
3. Consulter la documentation et les parametres
4. Determiner le nom du module fonction
5. Possibilite de test via SE37

11. BAPIs standard importants

" Clients
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST'. " Lister les clients
CALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2'. " Details client
CALL FUNCTION 'BAPI_CUSTOMER_CREATEFROMDAT1'. " Creer un client
" Fournisseurs
CALL FUNCTION 'BAPI_VENDOR_GETLIST'. " Lister les fournisseurs
CALL FUNCTION 'BAPI_VENDOR_GETDETAIL'. " Details fournisseur
" Articles
CALL FUNCTION 'BAPI_MATERIAL_GETLIST'. " Lister les articles
CALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL'. " Details article
" Commandes d'achat
CALL FUNCTION 'BAPI_PO_CREATE1'. " Creer une commande
CALL FUNCTION 'BAPI_PO_CHANGE'. " Modifier une commande
CALL FUNCTION 'BAPI_PO_GETDETAIL'. " Details commande
" Commandes de vente
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'. " Creer une commande
CALL FUNCTION 'BAPI_SALESORDER_GETLIST'. " Lister les commandes
CALL FUNCTION 'BAPI_SALESORDER_CHANGE'. " Modifier une commande
" Ecritures
CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST'. " Comptabiliser une piece FI
" Controle de transaction
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'. " Commit
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. " Rollback

Checklist BAPI

✓ Le module fonction est compatible RFC
✓ Parametre RETURN de type BAPIRET2
✓ Pas de COMMIT WORK dans le BAPI
✓ Pas d'instructions MESSAGE
✓ Pas d'appels de dialogue (popups)
✓ Gestion complete des erreurs
✓ Documentation des parametres
✓ Controle d'autorisation implemente
✓ Validation des entrees presente
✓ Testable via SE37

Remarques importantes / Bonnes pratiques

  • COMMIT WORK jamais dans le BAPI - l’appelant decide.
  • RETURN toujours rempli avec des messages explicites.
  • Marquer comme compatible RFC pour les appels distants.
  • Pas d’instructions MESSAGE - seulement remplir RETURN.
  • Implementer le controle d’autorisation dans le BAPI.
  • Validation des entrees avant le traitement.
  • Classes wrapper pour une utilisation simplifiee.
  • BAPI Explorer (transaction BAPI) pour la documentation.
  • Traitement de masse avec COMMITs individuels par enregistrement.
  • Combinez avec les Classes d’exception pour l’integration OO.