SAP RFC / BAPI
Requer o SAP NW RFC SDK instalado no servidor — ver SDK do SAP.
O caminho síncrono: o CMS chama o SAP. Uma Coleta chama uma função e transforma o retorno em mensagem; uma Entrega transforma a mensagem em parâmetros de uma chamada. Ver SAP para a visão geral dos três caminhos.
Arquitetura
A integração RFC não roda dentro do cms-api. Ela vive no microserviço
cms-sap-connector, que isola o SAP NetWeaver RFC SDK (código nativo em C, via node-rfc) do
processo principal.
Motivo: um crash de addon nativo derrubaria a API, o agendador e os workers junto. Em processo separado, ele derruba apenas a integração SAP.
O serviço fica só na rede interna do docker-compose (cms-network), sem porta publicada e sem
passar pelo nginx. Endpoints exceto /health exigem o header X-Internal-Token quando
SAP_CONNECTOR_TOKEN está configurada.
| Endpoint interno | Função |
|---|---|
GET /health | Liveness, sem autenticação |
POST /rfc/test | Testa a conexão (RFC_PING ou a função configurada). Nunca lança — falha vira { ok: false } |
POST /rfc/call | Chama a BAPI/RFC de negócio. Erro propaga como HTTP 502 |
Instalar o SDK
A comunicação usa o SAP NetWeaver RFC SDK oficial, a mesma biblioteca de integrações RFC em produção. Não há emulação nem tradução intermediária: a chamada sai do connector direto para o gateway RFC do seu SAP, com o mesmo protocolo de um programa ABAP remoto.
O SDK é licenciado pela SAP e não pode ser redistribuído, por isso não vem embutido na imagem.
Baixar
O SAP NW RFC SDK, no SAP Support Portal, com a licença do cliente. Não vai para o controle de versão.
Descompactar e ajustar o Dockerfile
Descompacte em nwrfcsdk/ e ajuste o Dockerfile (instruções comentadas no arquivo) para copiar o
SDK e configurar SAPNWRFC_HOME e LD_LIBRARY_PATH.
Instalar o node-rfc
npm install node-rfc, com essas variáveis já configuradas.
Ligar o cliente real
Defina SAP_RFC_CLIENT=real no ambiente do container.
A variante do SDK precisa bater com a plataforma do container (Linux x86_64), não com a do
servidor SAP (AIX, por exemplo). Baixar a variante errada é a causa mais comum de falha na
compilação do node-rfc.
Antes de o SDK ser instalado (SAP_RFC_CLIENT ainda não definida), o connector sobe com um stub
de desenvolvimento, que só responde às chamadas para que o restante do CMS possa ser construído e
testado em máquinas sem acesso a um SAP. É recurso de desenvolvimento e CI — toda instalação
produtiva roda com SAP_RFC_CLIENT=real.
Configurar a conexão
Na Conexão Externa do tipo SAP, o bloco de RFC client aceita dois modos de conexão:
| Modo | Campos | Quando |
|---|---|---|
| Application Server | Host e número da instância (sysnr) | Conexão direta a uma instância |
| Message Server | Host do message server, grupo de logon e SID | Logon balanceado, como um SAP GUI de produção |
Além disso: mandante, usuário, senha, idioma, SAProuter (opcional), tamanho do
pool de conexões e a função usada no teste (padrão RFC_PING).
O campo Timeout (ms), ao lado da função de teste, é o prazo do Testar Conexão e do Keep Alive: vazio vale 10000, e aceita de 1000 a 60000. Serve para o SAP que responde devagar — por SAProuter, VPN ou de outro continente — e que, com o prazo fixo de antes, ficava OFF mesmo estando no ar. Nas consultas de metadados (descrever a função ou a estrutura, buscar a BAPI) o campo só aumenta o prazo padrão delas, nunca o diminui. As chamadas de Coleta e Entrega não usam este campo: cada uma tem o timeout próprio.

Aumentar o timeout não resolve SAP inacessível. Se o teste dá timeout of 10000ms exceeded sem
resposta nenhuma, confira antes se o host responde nas portas 32NN (dispatcher) e 33NN
(gateway), onde NN é o número da instância — porta fechada ou DDNS desatualizado dão o mesmo
erro com qualquer prazo.
O botão Testar Conexão faz uma chamada real e devolve o erro do SAP quando falha — é onde aparecem os clássicos de implantação: usuário bloqueado, mandante errado, SAProuter inacessível.
Use um usuário de serviço do tipo comunicação, com a role S_RFC restrita aos function groups necessários. É a proteção real da integração — a lista de funções bloqueadas do CMS é apenas a primeira camada. Ver SAP.
Coleta — SAP_RFC
Chama um módulo de função ou BAPI e transforma o retorno em mensagem.
Achar a função
O botão de busca pesquisa funções no SAP por nome ou fragmento, e mostra a descrição de cada uma. Ao escolher, o CMS importa a assinatura: parâmetros de IMPORT, de EXPORT e as tabelas.
Declarar os parâmetros
Os parâmetros são declarados em JSON, mas você edita clicando nos campos do popup Parâmetros Função SAP. Cada parâmetro de IMPORT tem uma origem:
| Origem | Significado |
|---|---|
fixo | Valor literal, sempre o mesmo |
template | Placeholders {{...}} — data, variáveis, valores calculados |
jsonpath | Um campo do último payload recebido |
| vem de fora | Vira uma Variável de Entrada, informada por quem chama a Coleta |
estrutura | Um parâmetro de estrutura inteiro (ex.: NOTIFHEADER) montado em JSON, com {{variáveis}} em cada campo |
resposta | Só em chamadas seguintes: um campo da resposta do passo anterior |
Estruturas. Um parâmetro de estrutura abre num editor próprio (Monaco, em JSON), com o painel de
variáveis ao lado: as Variáveis de Entrada da Coleta/Entrega e as Globais. Dá para criar uma
Variável de Entrada nova direto do painel e já usá-la na estrutura — {"SHORT_TEXT": "{{descricao}}", "EQUIPMENT": "{{equipamento}}"}.
Variáveis de Entrada livres. Além das que nascem de um parâmetro “vem de fora”, você pode declarar variáveis que só aparecem dentro de estruturas ou de chamadas seguintes. Elas entram no contrato do mesmo jeito.
Em Parâmetros TABLES, out lista as tabelas de saída a devolver, e in (opcional) mapeia as
tabelas de entrada — origem fixo (array literal de linhas) ou jsonpath.
{
"in": { "PLANTSELECTION": { "origem": "fixo",
"valor": "[{\"SIGN\":\"I\",\"OPTION\":\"EQ\",\"PLANT_LOW\":\"1000\"}]" } },
"out": ["RETURN", "T_MATERIAIS"]
}Coleta agendada ou sob demanda
Aqui está uma decisão de projeto que muda o comportamento da integração inteira:
- sem Variáveis de Entrada — a Coleta é varrida pelo agendador, no cron configurado;
- com ao menos uma Variável de Entrada — a Coleta sai do agendador e ganha uma URL própria, executada sob demanda por quem chamar.
No modo sob demanda, faltando uma variável obrigatória, a API rejeita com HTTP 400 na hora — não vira mensagem em erro. Ver API pública.
Testar sem sair do CMS
O botão de teste executa a função com os parâmetros declarados e mostra o retorno. É o que evita o ciclo “salva, espera o cron, olha a mensagem em erro, corrige”.
Para tabelas grandes, há ainda o popup de campos da tabela, que lista as colunas do retorno e permite espiar valores — útil para descobrir o nome exato do campo antes de escrever o Transformador.
Cache de metadados
Os metadados da função (parâmetros de import/export e tabelas) ficam guardados em cache local no banco. O popup de parâmetros funciona offline, e um botão “Atualizar do SAP” recarrega quando a função muda no ERP.
Instalar um Pack SAP preenche esse cache como efeito colateral da verificação de compatibilidade — depois disso os popups abrem instantâneos, mesmo com o SAP inacessível.
Entrega — SAP_RFC_CALL
O caminho inverso: os dados da mensagem viram parâmetros de uma chamada RFC/BAPI.
A configuração é a mesma — função, parâmetros IMPORT, parâmetros TABLES — com duas diferenças importantes.
Payload de Entrada
Os campos marcados “vem de fora” formam o Payload de Entrada: o contrato que a mensagem entregue precisa cumprir. Cada alias resolve contra o payload da mensagem, e marcar um como obrigatório faz o CMS recusar o envio, com mensagem clara, quando o campo não vem.
Essa validação acontece antes de a mensagem chegar ao SAP. A diferença prática é grande: em vez
de uma falha de RFC com mensagem técnica, o operador lê “faltou o campo ordem”. A regra
correspondente aparece em Erros de Negócio com a etiqueta AUTO,
onde você decide se ela bloqueia a interface.
Commit
BAPIs de escrita não gravam nada até o commit. A opção “Chamar BAPI_TRANSACTION_COMMIT após a
chamada” faz o connector emiti-lo na mesma sessão RFC da chamada — e das chamadas seguintes,
depois da última. Se o RETURN de algum passo vier com tipo E ou A, o connector faz
BAPI_TRANSACTION_ROLLBACK no lugar do commit.
Chamar em seguida, na mesma sessão
Algumas BAPIs só funcionam em par: BAPI_ALM_NOTIF_CREATE monta a nota de PM na memória da sessão,
e só BAPI_ALM_NOTIF_SAVE a grava — na mesma sessão. Cada mensagem do CMS abre a sua própria
conexão RFC, então duas Entregas encadeadas (ou uma resposta encaminhada) não servem: a nota criada
na primeira não existe na segunda.
A seção “Chamar em seguida, na mesma sessão” acrescenta passos à mesma Entrega (e à Coleta), executados um depois do outro na conexão da função principal:
- cada passo tem a sua função (com a mesma busca no SAP), os seus parâmetros de import e as tabelas de saída;
- a origem
respostalê um campo do passo anterior —NOTIFHEADER_EXPORT.NOTIF_NO, por exemplo. A tela lista os campos de saída do passo anterior e sugere o de mesmo nome; - os campos do payload de entrada e as estruturas funcionam como na função principal;
- o retorno de cada passo entra no resultado com o nome da função (
BAPI_ALM_NOTIF_SAVE.NOTIFHEADER.NOTIF_NO).
O editor do passo se preenche a partir do SAP: ao escolher a função, os parâmetros de import aparecem prontos para mapear, e as tabelas de saída são escolhidas num popup.
Configurar BAPI_TRANSACTION_COMMIT como a função da Entrega é bloqueado — o commit tem lugar
próprio, justamente para não virar uma chamada solta sem a BAPI de negócio antes.
Erros
O erro do SAP chega ao CMS com o texto original, no idioma da conexão. A partir dele:
- falha de comunicação (gateway fora, usuário bloqueado) vira Erro de Entrega, com retentativa;
- retorno de negócio (a tabela
RETURNcom tipoE) vira Erro de Negócio quando há uma regra cadastrada — e é assim que “ordem não liberada” deixa de parecer sucesso.
Os Packs SAP já trazem essas regras prontas para os cenários que cobrem.