Las BAPIs (Business Application Programming Interfaces) son interfaces estandarizadas para acceder a objetos de negocio SAP. Siguen convenciones estrictas y permiten una integracion uniforme.
Convenciones BAPI
| Convencion | Descripcion |
|---|---|
| Nomenclatura | BAPI_<OBJETO>_<ACCION> |
| Parametro RETURN | Siempre BAPIRET2 o BAPIRET2_T |
| Sin COMMIT | El llamador es responsable |
| Sin dialogos | Sin popups ni mensajes |
| Habilitado RFC | Modulo de funcion remote-enabled |
Estructura BAPIRET2
| Campo | Descripcion |
|---|---|
| TYPE | S/E/W/I/A (Success/Error/Warning/Info/Abort) |
| ID | Clase de mensaje |
| NUMBER | Numero de mensaje |
| MESSAGE | Texto completo del mensaje |
| MESSAGE_V1-V4 | Variables |
| LOG_NO | Numero de log |
| LOG_MSG_NO | Numero de mensaje en log |
Ejemplos
1. Llamar BAPI estandar
" BAPI para leer un clienteDATA: 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.
" Verificacion de erroresIF line_exists( lt_return[ type = 'E' ] ). " Tratar error LOOP AT lt_return INTO DATA(ls_error) WHERE type = 'E'. WRITE: / ls_error-message. ENDLOOP.ELSE. " Exito WRITE: / ls_address-name, ls_address-city.ENDIF.2. BAPI con COMMIT
DATA: lt_return TYPE TABLE OF bapiret2.
" Crear pedidoCALL FUNCTION 'BAPI_PO_CREATE1' EXPORTING poheader = ls_header poheaderx = ls_headerx TABLES poitem = lt_items poitemx = lt_itemsx return = lt_return.
" Verificacion de erroresREAD TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0. " Exito - ejecutar COMMIT CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = abap_true. " Esperar al Commit
WRITE: / 'Pedido creado'.ELSE. " Error - ROLLBACK CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
" Mostrar mensajes de error LOOP AT lt_return INTO DATA(ls_msg) WHERE type CA 'EAX'. WRITE: / ls_msg-message. ENDLOOP.ENDIF.3. Crear BAPI propia
" Modulo de funcion: Z_BAPI_CUSTOMER_GETLISTFUNCTION z_bapi_customer_getlist.*"----------------------------------------------------------------------*"*"Interfaz local:*" 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*"----------------------------------------------------------------------
" Validacion de entrada 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.
" Leer datos 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.
" Metodo auxiliar para agregar entradas RETURNFORM 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. Clase Wrapper para 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 para crear... CALL FUNCTION 'BAPI_CUSTOMER_CREATE...' " Parametros... TABLES return = lt_return.
check_return( lt_return ).
" En exito COMMIT CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = abap_true.
rv_kunnr = '...'. " Nuevo numero de cliente ENDMETHOD.
METHOD check_return. " Verificar errores en 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.
" UsoTRY. 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: / 'Error:', lx_error->get_text( ).ENDTRY.5. BAPI para procesamiento masivo
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.
" Crear pedido individual 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.
" Verificar READ TABLE lt_order_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0 AND lv_order_no IS NOT INITIAL. " Exito 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 = |Pedido { lv_order_no } creado| ) TO return. ELSE. " Error 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.
" Resumen APPEND VALUE #( type = 'I' id = 'ZORD' number = '002' message = |{ lines( et_success ) } exitosos, { lines( et_failed ) } fallidos| ) TO return.
ENDFUNCTION.6. Clase de excepcion 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. " Usar primer mensaje de error LOOP AT it_return INTO DATA(ls_return) WHERE type CA 'EAX'. ro_error = from_bapiret2( ls_return ). RETURN. ENDLOOP. ENDMETHOD.ENDCLASS.7. Llamar BAPI via RFC
DATA: lt_return TYPE TABLE OF bapiret2.
" Destino RFCDATA(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: / 'Error RFC:', lv_message.ELSE. " Verificar retorno BAPI check_return( lt_return ).ENDIF.8. BAPI con Update Task
FUNCTION z_bapi_document_save.*"----------------------------------------------------------------------*" IMPORTING*" VALUE(IS_DOCUMENT) TYPE TY_DOCUMENT*" TABLES*" RETURN STRUCTURE BAPIRET2*"----------------------------------------------------------------------
" Validacion perform_validation( EXPORTING is_document = is_document CHANGING ct_return = return[] ).
IF line_exists( return[ type = 'E' ] ). RETURN. ENDIF.
" Guardar en Update Task CALL FUNCTION 'Z_UPDATE_DOCUMENT' IN UPDATE TASK EXPORTING is_document = is_document.
" Mensaje de exito APPEND VALUE bapiret2( type = 'S' id = 'ZDOC' number = '001' message = 'Documento sera guardado' ) TO return.
" COMMIT sera ejecutado por el llamador!
ENDFUNCTION.9. Funciones auxiliares BAPI
CLASS zcl_bapi_helper DEFINITION. PUBLIC SECTION. " Verifica si RETURN contiene errores CLASS-METHODS: has_errors IMPORTING it_return TYPE bapiret2_t RETURNING VALUE(rv_error) TYPE abap_bool.
" Filtra mensajes por tipo CLASS-METHODS: get_messages_by_type IMPORTING it_return TYPE bapiret2_t iv_type TYPE sy-msgty RETURNING VALUE(rt_messages) TYPE bapiret2_t.
" Convierte RETURN a String CLASS-METHODS: return_to_string IMPORTING it_return TYPE bapiret2_t RETURNING VALUE(rv_string) TYPE string.
" Agrega mensaje 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.
" UsoDATA: lt_return TYPE bapiret2_t.
zcl_bapi_helper=>add_message( EXPORTING iv_type = 'S' iv_id = 'ZMSG' iv_number = '001' iv_v1 = 'Exito' 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)
Transaccion: BAPI
1. Seleccionar Business Object (ej. Customer)2. Mostrar metodos (GetList, GetDetail, Create, etc.)3. Ver documentacion y parametros4. Determinar nombre del modulo de funcion5. Posibilidad de test via SE3711. BAPIs estandar importantes
" ClientesCALL FUNCTION 'BAPI_CUSTOMER_GETLIST'. " Listar clientesCALL FUNCTION 'BAPI_CUSTOMER_GETDETAIL2'. " Detalles de clienteCALL FUNCTION 'BAPI_CUSTOMER_CREATEFROMDAT1'. " Crear cliente
" ProveedoresCALL FUNCTION 'BAPI_VENDOR_GETLIST'. " Listar proveedoresCALL FUNCTION 'BAPI_VENDOR_GETDETAIL'. " Detalles de proveedor
" MaterialesCALL FUNCTION 'BAPI_MATERIAL_GETLIST'. " Listar materialesCALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL'. " Detalles de material
" Pedidos de compraCALL FUNCTION 'BAPI_PO_CREATE1'. " Crear pedidoCALL FUNCTION 'BAPI_PO_CHANGE'. " Modificar pedidoCALL FUNCTION 'BAPI_PO_GETDETAIL'. " Detalles de pedido
" Pedidos de ventaCALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'. " Crear pedidoCALL FUNCTION 'BAPI_SALESORDER_GETLIST'. " Listar pedidosCALL FUNCTION 'BAPI_SALESORDER_CHANGE'. " Modificar pedido
" ContabilizacionesCALL FUNCTION 'BAPI_ACC_DOCUMENT_POST'. " Contabilizar documento FI
" Control de transaccionesCALL FUNCTION 'BAPI_TRANSACTION_COMMIT'. " CommitCALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. " RollbackChecklist BAPI
- Modulo de funcion es habilitado RFC- Parametro RETURN del tipo BAPIRET2- Sin COMMIT WORK en la BAPI- Sin sentencias MESSAGE- Sin llamadas de dialogo (Popups)- Manejo de errores completo- Documentacion de parametros- Verificacion de autorizacion implementada- Validacion de entrada presente- Testeable via SE37Notas importantes / Mejores practicas
- COMMIT WORK nunca en la BAPI - el llamador decide.
- RETURN siempre llenar con mensajes descriptivos.
- Habilitado RFC marcar para llamadas remotas.
- Sin MESSAGE statements - solo llenar RETURN.
- Implementar verificacion de autorizacion en la BAPI.
- Validacion de entrada antes del procesamiento.
- Clases Wrapper para uso simplificado.
- BAPI Explorer (transaccion BAPI) para documentacion.
- Procesamiento masivo con COMMITs individuales por registro.
- Combinar con Clases de excepcion para integracion OO.