BAPI - Business Application Programming Interface
📋 Visão Geral
BAPI (Business Application Programming Interface) são métodos padronizados de Business Objects SAP que permitem integração com processos de negócio.
Características: - ✅ RFC-enabled (podem ser chamados remotamente) - ✅ Padronizados e documentados - ✅ Validações de negócio incluídas - ✅ Versionados e estáveis - ✅ Suportados oficialmente pela SAP
🎯 Diferença: BAPI vs RFC vs Function Module
| Aspecto | Function Module | RFC | BAPI |
|---|---|---|---|
| Propósito | Qualquer lógica | Chamada remota | Processo de negócio |
| Padronização | Não | Não | Sim |
| Documentação | Opcional | Opcional | Obrigatória |
| Validação | Manual | Manual | Automática |
| Estabilidade | Pode mudar | Pode mudar | Versionado |
| Uso Externo | Não recomendado | Sim | Sim (preferido) |
🔍 Encontrar BAPIs
Transaction BAPI
Explorador de BAPIs:
- BAPI ou BAPI Explorer
- Navegar pela árvore de Business Objects
- Ver métodos disponíveis
Exemplo de estrutura:
📁 SalesOrder
└─ 📄 BAPI_SALESORDER_CREATEFROMDAT2
└─ 📄 BAPI_SALESORDER_CHANGE
└─ 📄 BAPI_SALESORDER_GETLIST
📁 Material
└─ 📄 BAPI_MATERIAL_SAVEDATA
└─ 📄 BAPI_MATERIAL_GET_DETAIL
SE37 - Function Builder
Procurar BAPIs:
- Padrão de nome: BAPI_*
- Exemplo: BAPI_*CUSTOMER*
📊 Estrutura Comum de BAPIs
Parâmetros Típicos
CALL FUNCTION 'BAPI_EXEMPLO'
EXPORTING
iv_objeto_key = lv_key " Chave do objeto
IMPORTING
ev_resultado = lv_resultado " Resultado
TABLES
it_dados = lt_dados " Dados de entrada
et_return = lt_return " Mensagens
EXCEPTIONS
error = 1
OTHERS = 2.
Tabela RETURN
Todas as BAPIs retornam mensagens via tabela RETURN:
TYPES: BEGIN OF ty_return,
type TYPE bapireturn-type, " S/E/W/I/A
id TYPE bapireturn-id, " Message Class
number TYPE bapireturn-number, " Message Number
message TYPE bapireturn-message," Texto
END OF ty_return.
DATA: lt_return TYPE TABLE OF bapiret2.
Tipos de mensagem:
- S - Success
- E - Error
- W - Warning
- I - Information
- A - Abort
💡 BAPIs Mais Usados
1️⃣ BAPI_SALESORDER_CREATEFROMDAT2
Criar Ordem de Venda:
DATA: ls_header TYPE bapisdhd1,
lt_items TYPE TABLE OF bapisditm,
lt_partners TYPE TABLE OF bapiparnr,
lt_return TYPE TABLE OF bapiret2,
lv_order TYPE vbeln_va.
" Cabeçalho
ls_header-doc_type = 'TA'.
ls_header-sales_org = '1000'.
ls_header-distr_chan = '10'.
ls_header-division = '00'.
" Item
APPEND VALUE #(
itm_number = '000010'
material = 'MAT-001'
target_qty = '10'
plant = '1000'
) TO lt_items.
" Parceiro (Cliente)
APPEND VALUE #(
partn_role = 'AG' " Sold-to Party
partn_numb = '1000'
) TO lt_partners.
" Criar ordem
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
EXPORTING
order_header_in = ls_header
IMPORTING
salesdocument = lv_order
TABLES
return = lt_return
order_items_in = lt_items
order_partners = lt_partners.
" Verificar erros
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
WRITE: / '❌ Erro ao criar ordem:'.
LOOP AT lt_return INTO DATA(ls_msg) WHERE type = 'E'.
WRITE: / ls_msg-message.
ENDLOOP.
" Desfazer
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
" Commit
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'.
WRITE: / |✅ Ordem criada: { lv_order }|.
ENDIF.
2️⃣ BAPI_MATERIAL_GET_DETAIL
Buscar Detalhes de Material:
DATA: ls_material TYPE bapi_mara,
lt_return TYPE TABLE OF bapiret2.
CALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL'
EXPORTING
material = 'MAT-001'
IMPORTING
material_general_data = ls_material
TABLES
return = lt_return.
IF ls_material IS NOT INITIAL.
WRITE: / |Material: { ls_material-material }|.
WRITE: / |Descrição: { ls_material-matl_desc }|.
WRITE: / |Tipo: { ls_material-matl_type }|.
ELSE.
WRITE: / '❌ Material não encontrado'.
ENDIF.
3️⃣ BAPI_GOODSMVT_CREATE
Criar Movimento de Mercadorias:
DATA: ls_header TYPE bapi2017_gm_head_01,
ls_code TYPE bapi2017_gm_code,
lt_items TYPE TABLE OF bapi2017_gm_item_create,
lt_return TYPE TABLE OF bapiret2,
lv_matdoc TYPE bapi2017_gm_head_ret-mat_doc.
" Código de movimento (MB01)
ls_code-gm_code = '01'. " Goods Receipt
" Cabeçalho
ls_header-pstng_date = sy-datum.
ls_header-doc_date = sy-datum.
" Item
APPEND VALUE #(
material = 'MAT-001'
plant = '1000'
stge_loc = '0001'
move_type = '501' " GR sem pedido
entry_qnt = '100'
entry_uom = 'PC'
) TO lt_items.
" Criar movimento
CALL FUNCTION 'BAPI_GOODSMVT_CREATE'
EXPORTING
goodsmvt_header = ls_header
goodsmvt_code = ls_code
IMPORTING
materialdocument = lv_matdoc
TABLES
goodsmvt_item = lt_items
return = lt_return.
" Verificar
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
WRITE: / '❌ Erro ao criar movimento'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = 'X'.
WRITE: / |✅ Material document: { lv_matdoc }|.
ENDIF.
4️⃣ BAPI_ACC_DOCUMENT_POST
Lançar Documento Contábil:
DATA: ls_header TYPE bapiache09,
lt_gl TYPE TABLE OF bapiacgl09,
lt_curr TYPE TABLE OF bapiaccr09,
lt_return TYPE TABLE OF bapiret2,
lv_docnr TYPE bapi_acc_doc_header_ret.
" Cabeçalho
ls_header-username = sy-uname.
ls_header-comp_code = '1000'.
ls_header-doc_date = sy-datum.
ls_header-pstng_date = sy-datum.
ls_header-doc_type = 'SA'.
ls_header-ref_doc_no = 'REF-001'.
" Item GL - Débito
APPEND VALUE #(
itemno_acc = '1'
gl_account = '400000'
comp_code = '1000'
pstng_date = sy-datum
doc_type = 'SA'
) TO lt_gl.
" Item GL - Crédito
APPEND VALUE #(
itemno_acc = '2'
gl_account = '500000'
comp_code = '1000'
pstng_date = sy-datum
doc_type = 'SA'
) TO lt_gl.
" Valores
APPEND VALUE #(
itemno_acc = '1'
currency = 'EUR'
amt_doccur = '1000.00'
) TO lt_curr.
APPEND VALUE #(
itemno_acc = '2'
currency = 'EUR'
amt_doccur = '-1000.00'
) TO lt_curr.
" Lançar
CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST'
EXPORTING
documentheader = ls_header
IMPORTING
obj_key = lv_docnr
TABLES
accountgl = lt_gl
currencyamount = lt_curr
return = lt_return.
" Verificar
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
WRITE: / '❌ Erro ao lançar documento'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = 'X'.
WRITE: / |✅ Documento contábil: { lv_docnr }|.
ENDIF.
5️⃣ BAPI_CUSTOMER_GETLIST
Buscar Lista de Clientes:
DATA: lt_customers TYPE TABLE OF bapi_customer_data,
lt_return TYPE TABLE OF bapiret2,
ls_maxrows TYPE bapi_maxrows.
ls_maxrows-maxrows = 100.
CALL FUNCTION 'BAPI_CUSTOMER_GETLIST'
EXPORTING
maxrows = ls_maxrows
TABLES
customer_list = lt_customers
return = lt_return.
WRITE: / |Clientes encontrados: { lines( lt_customers ) }|, /.
LOOP AT lt_customers INTO DATA(ls_customer) TO 20.
WRITE: / |{ ls_customer-customer } - { ls_customer-name }|.
ENDLOOP.
🔄 Commit e Rollback
BAPI_TRANSACTION_COMMIT
SEMPRE necessário após BAPIs de modificação:
" ✅ Forma correta
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
" ... parâmetros ...
IF sy-subrc = 0.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = 'X'. " Aguardar commit
ENDIF.
Parâmetro WAIT:
- wait = 'X' - Aguarda commit terminar (recomendado)
- wait = ' ' - Commit assíncrono
BAPI_TRANSACTION_ROLLBACK
Desfazer alterações em caso de erro:
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
" Erro encontrado - desfazer
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
MESSAGE 'Operação cancelada' TYPE 'E'.
ELSE.
" Sucesso - confirmar
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = 'X'.
ENDIF.
🛡️ Tratamento de Erros
Análise de Mensagens RETURN
CLASS lcl_bapi_helper DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
check_return
IMPORTING it_return TYPE bapiret2_t
RETURNING VALUE(rv_has_error) TYPE abap_bool,
display_messages
IMPORTING it_return TYPE bapiret2_t.
ENDCLASS.
CLASS lcl_bapi_helper IMPLEMENTATION.
METHOD check_return.
" Verifica se há erros
READ TABLE it_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
rv_has_error = xsdbool( sy-subrc = 0 ).
IF rv_has_error = abap_false.
" Verificar aborts
READ TABLE it_return WITH KEY type = 'A' TRANSPORTING NO FIELDS.
rv_has_error = xsdbool( sy-subrc = 0 ).
ENDIF.
ENDMETHOD.
METHOD display_messages.
LOOP AT it_return INTO DATA(ls_msg).
DATA(lv_icon) = SWITCH #( ls_msg-type
WHEN 'E' THEN '❌'
WHEN 'W' THEN '⚠️'
WHEN 'S' THEN '✅'
WHEN 'I' THEN 'ℹ️'
ELSE '•' ).
WRITE: / |{ lv_icon } { ls_msg-message }|.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
" Uso
START-OF-SELECTION.
DATA lt_return TYPE bapiret2_t.
" ... chamar BAPI ...
IF lcl_bapi_helper=>check_return( lt_return ) = abap_true.
WRITE: / '═══ ERROS ═══', /.
lcl_bapi_helper=>display_messages( lt_return ).
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
WRITE: / '✅ Sucesso!'.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = 'X'.
ENDIF.
⚡ Boas Práticas
✅ Fazer
" 1. Sempre verificar RETURN
CALL FUNCTION 'BAPI_XXX'
TABLES return = lt_return.
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0. " ✅ Verificar erros
" Tratar erro
ENDIF.
" 2. SEMPRE fazer COMMIT após modificação
CALL FUNCTION 'BAPI_XXX_CREATE'
" ... parâmetros ...
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' " ✅ Commit
EXPORTING wait = 'X'.
" 3. Usar WAIT = 'X' em commits
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = 'X'. " ✅ Aguardar
" 4. Rollback em caso de erro
IF lv_error = abap_true.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'. " ✅ Desfazer
ENDIF.
" 5. Documentar BAPIs usados
*&---------------------------------------------------------------------*
*& Usa BAPI_SALESORDER_CREATEFROMDAT2 para criar ordens
*& Requer autorização V_VBAK_AAT
*&---------------------------------------------------------------------*
❌ Evitar
" 1. Não verificar erros
CALL FUNCTION 'BAPI_XXX'
TABLES return = lt_return.
" ❌ E se houve erro?
" 2. Esquecer COMMIT
CALL FUNCTION 'BAPI_XXX_CREATE'
" ... criar algo ...
" ❌ Nada foi salvo!
" 3. COMMIT sem WAIT
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'. " ❌ Pode não ter terminado
" 4. Usar COMMIT WORK direto
COMMIT WORK. " ❌ Usar BAPI_TRANSACTION_COMMIT
" 5. Misturar BAPI com UPDATE
CALL FUNCTION 'BAPI_XXX_CREATE'.
UPDATE dbtab SET field = value. " ❌ Inconsistente!
🔧 Criar BAPI Customizado
1. Criar Function Module (SE37)
FUNCTION z_bapi_customer_create.
*"----------------------------------------------------------------------
*"*"Interface Local:
*" IMPORTING
*" VALUE(IS_CUSTOMER) TYPE ZST_CUSTOMER
*" EXPORTING
*" VALUE(EV_KUNNR) TYPE KUNNR
*" TABLES
*" RETURN STRUCTURE BAPIRET2
*"----------------------------------------------------------------------
" Validações
IF is_customer-name1 IS INITIAL.
APPEND VALUE bapiret2(
type = 'E'
id = 'Z_MSG'
number = '001'
message = 'Nome é obrigatório'
) TO return.
RETURN.
ENDIF.
" Lógica de negócio
TRY.
" Gerar número
CALL FUNCTION 'NUMBER_GET_NEXT'
EXPORTING
nr_range_nr = '01'
object = 'Z_KUNNR'
IMPORTING
number = ev_kunnr.
" Inserir cliente
INSERT kna1 FROM VALUE #(
kunnr = ev_kunnr
name1 = is_customer-name1
land1 = is_customer-land1
).
IF sy-subrc = 0.
APPEND VALUE bapiret2(
type = 'S'
id = 'Z_MSG'
number = '002'
message = |Cliente { ev_kunnr } criado|
) TO return.
ENDIF.
CATCH cx_root INTO DATA(lo_ex).
APPEND VALUE bapiret2(
type = 'E'
message = lo_ex->get_text( )
) TO return.
ENDTRY.
ENDFUNCTION.
2. Configurar como BAPI
- SE37 → Attributes
- ☑ Remote-Enabled Module
- Processing Type: Normal
- Save & Activate
3. Criar Business Object (SWO1)
Opcional, mas recomendado para integração completa.
💡 Exemplo Completo: Criar Pedido de Compra
*&---------------------------------------------------------------------*
*& Report Z_BAPI_CREATE_PO
*&---------------------------------------------------------------------*
REPORT z_bapi_create_po.
DATA: ls_header TYPE bapimepoheader,
ls_headerx TYPE bapimepoheaderx,
lt_items TYPE TABLE OF bapimepoitem,
lt_itemsx TYPE TABLE OF bapimepoitemx,
lt_return TYPE TABLE OF bapiret2,
lv_ponumber TYPE ebeln.
START-OF-SELECTION.
" Cabeçalho do pedido
ls_header-comp_code = '1000'.
ls_header-doc_type = 'NB'.
ls_header-vendor = '1000'.
ls_header-purch_org = '1000'.
ls_header-pur_group = '001'.
" Flags de atualização
ls_headerx-comp_code = 'X'.
ls_headerx-doc_type = 'X'.
ls_headerx-vendor = 'X'.
ls_headerx-purch_org = 'X'.
ls_headerx-pur_group = 'X'.
" Item 1
APPEND VALUE #(
po_item = '00010'
material = 'MAT-001'
plant = '1000'
quantity = '100'
net_price = '10.50'
price_unit = '1'
) TO lt_items.
APPEND VALUE #(
po_item = '00010'
material = 'X'
plant = 'X'
quantity = 'X'
net_price = 'X'
price_unit = 'X'
) TO lt_itemsx.
" Item 2
APPEND VALUE #(
po_item = '00020'
material = 'MAT-002'
plant = '1000'
quantity = '50'
net_price = '25.00'
price_unit = '1'
) TO lt_items.
APPEND VALUE #(
po_item = '00020'
material = 'X'
plant = 'X'
quantity = 'X'
net_price = 'X'
price_unit = 'X'
) TO lt_itemsx.
" Criar pedido
CALL FUNCTION 'BAPI_PO_CREATE1'
EXPORTING
poheader = ls_header
poheaderx = ls_headerx
IMPORTING
exppurchaseorder = lv_ponumber
TABLES
return = lt_return
poitem = lt_items
poitemx = lt_itemsx.
" Verificar resultado
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
" Erro
WRITE: / '❌ Erro ao criar pedido:', /.
LOOP AT lt_return INTO DATA(ls_msg) WHERE type CA 'EA'.
WRITE: / ls_msg-message.
ENDLOOP.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
" Sucesso
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = 'X'.
WRITE: / '✅ Pedido criado com sucesso!'.
WRITE: / |Número: { lv_ponumber }|.
WRITE: / |Itens: { lines( lt_items ) }|, /.
" Mensagens de sucesso
LOOP AT lt_return INTO ls_msg WHERE type = 'S'.
WRITE: / ls_msg-message.
ENDLOOP.
ENDIF.
🔗 Próximos Passos
- RFC - BAPIs são RFCs especiais
- OData - Expor BAPIs via OData
- Web Services - Consumir BAPIs via SOAP
Tags: #BAPI #Integrações #BusinessAPI #ABAP #RFC