NFe B2B de saída
-
Upload
isaac-andrade -
Category
Documents
-
view
68 -
download
5
description
Transcript of NFe B2B de saída
Getting Started Newsletters Store
Search the Community
Welcome, Guest Login Register
Products Services & Support About SCN Downloads
Industries Training & Education Partnership Developer Center
Lines of Business University Alliances Events & Webinars Innovation
Added by Ricardo Guedes, last edited by Ricardo Guedes on Dec 14, 2011
Português (Portuguese) / … / SAP NFE
NFe B2B de saída - Enviando NFes por Email, WebService e Arquivo (ou FTP)
1. Introdução
1.1 Detalhes
1.1.1 Área(s) de Aplicação
1.1.2 Autor
1.1.3 Referências
1.1.4 Colaboração
1.2 Cenário
2. Preparação
2.1 Etapas da solução
3. Desenvolvimento ABAP
3.1 Tabela para armazenar os dados
3.2 RFC para busca dos dados
4. Integration Repository
4.1 Criação do Softw are Component Version (SWCV)
4.2 Message Mapping
4.2.1 User-Defined Function (UDF)
4.2.2 Message Mapping do Enhanced Receiver Determination
4.3 Interface Mapping
5. Desenvolvimento Java
5.1 Criação do Adapter Module
6. Integration Directory
6.1 Criação das Party's e Communication Channels
6.2 Cenário NTB2B
7. Testes
1. Introdução
1.1 Detalhes
1.1.1 Área(s) de Aplicação
Nota Fiscal Eletrônica - NFe (SLL-NFE 1.0)
SAP Process Integration (PI) 7.0
1.1.2 Autor
Ricardo Guedes
Created on: 12/02/2008
Biografia do(s) Autor(es):
Trabalho na Neoris desde 06/2007 como consultor de SAP PI e SAP Portal onde atuo em projetos de Nota Fiscal Eletrônica, de integrações de sistemas SAP/não-SAP e implantação de portais corporativos.
1.1.3 Referências
Configuração do B2B de NFe usando RFC Lookup
Configuração do Enhanced Receiver Determination
Thread do Fórum com a discussão sobre este tema
1.1.4 Colaboração
Colaboraram para o desenvolvimento desta solução:
Raphael Xavier
Henrique Pinto
1.2 Cenário
Em diversos projetos de implantação de Nota Fiscal Eletrônica (NFe) faz-se necessário o envio dos arquivos XML das NFes para os clientes. Para que os envios possam ser feitos por diversas formas e
não apenas uma, desenvolvimentos adicionais são necessários aos já criados para os envios por apenas uma forma.
Qualquer item que venha a melhorar a solução será bem vindo.
2. Preparação
2. Preparação
2.1 Etapas da solução
Para implementar esta solução, serão necessárias:
Tabela para armazenar os dados necessários referentes a cada uma das formas de envio. Por exemplo, endereço de e-mail, link do WebService, pasta de destino para o arquivo, etc;
RFC para buscar os dados;
Cenário do B2B de saída (NTB2B);
Alteração da User-Defined Function (UDF) do message mapping do cenário de B2B;
Criar um Adapter Module para trocar o nome do arquivo anexo do e-mail e inserir um texto no corpo do e-mail.
Configurar e implementar o Adapter Specif ic Message Attributes (ASMA) para passar os parâmetros para os adaptadores dinamicamente;
Implementar o Enhanced Receiver Determination para escolher dinamicamente qual serviço receberá a mensagem;
3. Desenvolvimento ABAP
3.1 Tabela para armazenar os dados
É necessária a utilização de uma tabela para armazenar as informações sobre qual forma o cliente deseja receber os XMLs de NFes emitidas.
Como é necessário utilizar os campos CNPJ e B2B Ativo, a sugestão é extender a tabela /XNFE/TB2B, fazendo os includes de acordo com a necessidade. Neste caso, foram adicionados os seguintes
campos:
Nome (para melhor identif icar os clientes na tabela);
Forma de envio (1-E-mail, 2-WebService e 3-Arquivo);
E-mail;
Pasta;
URL do WebService;
Action do WebService;
Usuário (para logar no WebService);
Senha (para logar no WebService).
3.2 RFC para busca dos dados
Esta é a mesma RFC como a criada no cenário tradicional de B2B de saída, porém, além o campo de e-mail que ela costuma retormar, adicionar os outros campos desejados no retorno da RFC para que
eles sejam utilizados no UDF.
Para facilitar, crie um programa e uma transação para fazer a manutenção dos dados adicionais desta tabela
4. Integration Repository
4.1 Criação do Software Component Version (SWCV)
Fazer a criação do SWCV assim como no cenário normal de um B2B. Vide a área de referências que indica a criação de um cenário de B2B.
4.2 Message Mapping
O message mapping terá uma diferença: uma quarta variável foi adicionada, pois ao mesmo tempo da RFC Lookup, foi feita a leitura do XML para identif icar a chave de acesso da NFe emitida, assim o nome
do arquivo poderia ser determinado.
4.2.1 User-Defined Function (UDF)
Para os cenários de envio de XML via B2B por e-mail foi criada uma RFC Lookup para que, durante o message mapping, seja feita uma chamada à RFC criada anteriormente, passando como parâmetro de
entrada o CNPJ do destinatário e obtendo como retorno os campos adicionais da tabela, com os dados referentes à opção de recebimento das NFes pelo cliente.
O código utilizado para o UDF pode ser visto a seguir:
public String retornaDados(String cnpj,String busSystem,String commChannel,String xml,Container container){
imports
com.sap.aii.mapping.api.*;com.sap.aii.mapping.lookup.*;java.util.Map;javax.xml.parsers.*;java.io.*;org.w3c.dom.*;
java.util.Map map;
AbstractTrace trace = container.getTrace();
Channel channel = null;
RfcAccessor accessor = null;
map = container.getTransformationParameters();
//envia a NFe para um administrador no caso de falha
String email = "[email protected]";
int forma = 0;
String pastaDestino = "";
String webserviceUrl = "";
String webserviceUsuario = "";
String webserviceAction = "";
try {
// Retorna o Communication Channel
channel = LookupService.getChannel(busSystem, commChannel);
trace.addWarning("Channel: " + channel);
// Get a RFC accessor for the channel
accessor = LookupService.getRfcAccessor(channel);
// Define a Mensagem de requisicao para a RFC
String req = "<ns0:ZPIF_NFE_CLIENTE xmlns:ns0='urn:sap-com:document:sap:rfc:functions'><ZCNPJ>" + cnpj + "</ZCNPJ>
</ns0:ZPIF_NFE_CLIENTE>";
// Create the xml inputstream
InputStream inputStream = new ByteArrayInputStream(req.getBytes("UTF-8"));
// Create xml payload
XmlPayload payload = LookupService.getXmlPayload(inputStream);
// Execute lookup
XmlPayload result = accessor.call(payload);
// Get the response
InputStream resp = result.getContent();
// Parse the response
//Campo ZFORMA
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(resp);
Node nodeForma = (Node) doc.getElementsByTagName("ZFORMA").item(0);
if (nodeForma.hasChildNodes() && !nodeForma.getFirstChild().getNodeValue().equals("")) {
forma = Integer.parseInt(nodeForma.getFirstChild().getNodeValue());
}
//Campo ZEMAIL
Node nodeEmail = (Node) doc.getElementsByTagName("ZEMAIL").item(0);
if (nodeEmail.hasChildNodes() && !nodeEmail.getFirstChild().getNodeValue().equals("")) {
email = nodeEmail.getFirstChild().getNodeValue();
}
//Campo ZPASTA_DESTINO
Node nodePasta = (Node) doc.getElementsByTagName("ZPASTA_DESTINO").item(0);
if (nodePasta.hasChildNodes() && !nodePasta.getFirstChild().getNodeValue().equals("")) {
pastaDestino = nodePasta.getFirstChild().getNodeValue();
}
//Campo ZWEBSERVICE_URL
Node nodeUrl = (Node) doc.getElementsByTagName("ZWEBSERVICE_URL").item(0);
if (nodeUrl.hasChildNodes() && !nodeUrl.getFirstChild().getNodeValue().equals("")) {
webserviceUrl = nodeUrl.getFirstChild().getNodeValue();
}
//Campo ZWEBSERVICE_USUARIO
Node nodeUsuario = (Node) doc.getElementsByTagName("ZWEBSERVICE_USU").item(0);
if (nodeUsuario.hasChildNodes() && !nodeUsuario.getFirstChild().getNodeValue().equals("")) {
webserviceUsuario = nodeUsuario.getFirstChild().getNodeValue();
}
//Campo ZWEBSERVICE_ACTION
Node nodeAction = (Node) doc.getElementsByTagName("ZWEBSERVICE_ACT").item(0);
if (nodeAction.hasChildNodes() && !nodeAction.getFirstChild().getNodeValue().equals("")) {
webserviceAction = nodeAction.getFirstChild().getNodeValue();
}
} catch (Exception e) {
trace.addWarning("Falha na RFC: " + e);
} finally {
// Close the accessor in order to free resources.
if (accessor!=null) {
try {
accessor.close();
} catch (Exception e) {
trace.addWarning("Erro ao finalizar o accessor: " + e);
}
}
}
// Definir qual rota o XML sera enviado
if (forma == 1){
// Envio via E-MAIL
int posicaoId = xml.indexOf("Id=");
String chaveAcesso = xml.substring(posicaoId + 7, posicaoId + 51);
String filename = chaveAcesso + ".xml";
map.put(StreamTransformationConstants.RECEIVER_SERVICE, "EMAIL");
// Preenche o dynamic configuration para o campo "para" no mail adapter
DynamicConfigurationKey toKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/Mail", "THeaderTO");
DynamicConfigurationKey attachfilenameKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File",
"FileName");
DynamicConfiguration conf = (DynamicConfiguration)
container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
conf.put(toKey, email);
conf.put(attachfilenameKey, filename);
}
else if(forma == 2){
// Envio via WEBSERVICE
map.put(StreamTransformationConstants.RECEIVER_SERVICE, "WEBSERVICE");
// Preenche o dynamic configuration para os parametros do SOAP adapter
DynamicConfigurationKey urlKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP",
"TServerLocation");
4.2.2 Message Mapping do Enhanced Receiver Determination
Para definir qual serviço receberá a mensagem, utilizamos o recurso Enhanced Receiver Determination. Para isso, criamos o seguinte message mapping. Para o campo "Party" adicionamos a constante
referente à party referente ao B2B, que será vista mais adiante:
Para o campo "Service", criar outro UDF com RFC Lookup, para que, de acordo com a forma de recebimento escolhida, ele determine qual serviço receberá a mensagem:
DynamicConfigurationKey userKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP", "TAuthKey");
DynamicConfigurationKey actionKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP",
"THeaderSOAPACTION");
DynamicConfiguration conf = (DynamicConfiguration)
container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
conf.put(urlKey, webserviceUrl);
conf.put(userKey, webserviceUsuario);
conf.put(actionKey, webserviceAction);
}
else if (forma == 3){
// Envio via Arquivo
int posicaoId = xml.indexOf("Id=");
String chaveAcesso = xml.substring(posicaoId + 7, posicaoId + 51);
String filename = chaveAcesso + ".xml";
map.put(StreamTransformationConstants.RECEIVER_SERVICE, "FILE");
// Preenche o dynamic configuration para os parametros do File adapter
DynamicConfigurationKey filenameKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File",
"FileName");
DynamicConfigurationKey pastadestinoKey = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File",
"Directory");
DynamicConfiguration conf = (DynamicConfiguration)
container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
conf.put(filenameKey, filename);
conf.put(pastadestinoKey, pastaDestino);
}
// Since this is a dummy mapping, return the same value from input
return cnpj;
O código utilizado para o UDF pode ser visto a seguir (desta vez, a variável que recebe a string do XML não se faz necessária)::
java.util.Map map;
AbstractTrace trace = container.getTrace();
Channel channel = null;
RfcAccessor accessor = null;
map = container.getTransformationParameters();
int forma = 0;
String servico = "";
try {
// Retorna o Communication Channel
channel = LookupService.getChannel(busSystem, commChannel);
// Get a RFC accessor for the channel
accessor = LookupService.getRfcAccessor(channel);
// Define a Mensagem de requisicao para a RFC
String req = "<ns0:ZPIF_NFE_CLIENTE xmlns:ns0='urn:sap-com:document:sap:rfc:functions'><ZCNPJ>" + cnpj + "</ZCNPJ>
</ns0:ZPIF_NFE_CLIENTE>";
// Create the xml inputstream
InputStream inputStream = new ByteArrayInputStream(req.getBytes("UTF-8"));
// Create xml payload
XmlPayload payload = LookupService.getXmlPayload(inputStream);
// Execute lookup
4.3 Interface Mapping
Criar um interface mapping que tem como mensagem de origem a Message Inteface "NTB2B_procNFe_OB" e como destino o Message Interface "ReceiverDetermination", encontrado no namespace
"http://sap.com/xi/XI/System":
// Execute lookup
XmlPayload result = accessor.call(payload);
// Get the response
InputStream resp = result.getContent();
// Parse the response
//Campo ZFORMA
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(resp);
Node nodeForma = (Node) doc.getElementsByTagName("ZFORMA").item(0);
if (nodeForma.hasChildNodes() && \!nodeForma.getFirstChild().getNodeValue().equals("")) {
forma = Integer.parseInt(nodeForma.getFirstChild().getNodeValue());
}
} catch (Exception e) {
trace.addWarning("Falha na RFC: " + e);
} finally {
// Close the accessor in order to free resources.
if (accessor\!=null) {
try {
accessor.close();
} catch (Exception e) {
trace.addWarning("Erro ao finalizar o accessor: " + e);
}
}
}
// Definir qual rota o XML sera enviado
if (forma == 1){
// Envio via E-MAIL
servico = "EMAIL";
}
else if(forma == 2){
// Envio via WEBSERVICE
servico = "WEBSERVICE";
}
else if (forma == 3){
// Envio via Arquivo
servico = "FILE";
}
return servico;
5. Desenvolvimento Java
5.1 Criação do Adapter Module
Nesta parte é necessário desenvolver um código em Java. Ele é relativamente simples de ser implementado. O código pode ser visto a seguir:
package br.com.neoris.nfe.attachment;
import com.sap.aii.af.mp.module.*;
import com.sap.aii.af.ra.ms.api.*;
import com.sap.aii.af.service.auditlog.*;
import javax.ejb.*;
public class SetAttachmentNameBean implements SessionBean, Module {
private SessionContext myContext;
private AuditMessageKey amk;
public SetAttachmentNameBean() { }
public void ejbRemove() { }
public void ejbActivate() {}
public void ejbPassivate() { }
public void setSessionContext(SessionContext context) {
myContext = context;
}
public void ejbCreate() throws CreateException {
}
public ModuleData process(ModuleContext moduleContext, ModuleData inputModuleData) throws ModuleException {
Message msg = (Message) inputModuleData.getPrincipalData();
if (msg.getMessageDirection() == MessageDirection.INBOUND) {
amk = new AuditMessageKey(msg.getMessageId(), AuditDirection.INBOUND);
} else {
amk = new AuditMessageKey(msg.getMessageId(), AuditDirection.OUTBOUND);
}
Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "NFe: Entrando no modulo para definir nome do arquivo...");
try {
Payload text = msg.getDocument();
byte xmlContent[] = text.getContent();
String fileName = msg.getMessageProperty("http://sap.com/xi/XI/System/File", "FileName");
StringBuffer content = new StringBuffer();
content.append("Prezado cliente, \r\n\r\n");
content.append("Segue arquivo anexo referente a sua Nota Fiscal Eletr\u00F4nica.\r\n\r\n");
content.append("\r\n\r\n");
content.append("Att,\r\n");
content.append("Nome da Empresa\r\n");
content.append("Ramo de Atividade");
text.setContent(content.toString().getBytes("UTF-8"));
text.setContentType("text/plain;charset=\"UTF-8\";");
Payload payload = msg.createPayload();
payload.setContent(xmlContent);
if (fileName == null) {
Em caso de dúvidas de como criar um Adapter Module, acesse a página de Como Criar um Adapter Module na seção Referências. Após compilar o código, fazer o deploy do mesmo no SDM (lembrando que
para este desenvolvimento utilizamos o PI 7.0).
6. Integration Directory
6.1 Criação das Party's e Communication Channels
Criar uma Party para o B2B. Ela abrigará todas as formas de envio de NFe, neste caso, EMAIL, FILE (para arquivo ou FTP) e WEBSERVICE e um receiver communication channel para cada caso:
As configurações dos communication channels foram feitas conforme as f iguras a seguir (Notem que os f lags para utilização do ASMA estão ativos, assim os parâmetros que determinamos como
dinâmicos podem ser enviados aos adaptadores):
Mail Adapter (note na aba Module a importação do Custom Adapter Module criado anteriormente):
if (fileName == null) {
fileName = "default.xml";
}
payload.setContentType("application/xml");
payload.setName(fileName);
payload.setDescription(fileName);
msg.addAttachment(payload);
inputModuleData.setPrincipalData(msg);
} catch (Exception e) {
throw new ModuleException(e);
}
return inputModuleData;
}
}
SOAP Adapter:
File Adapter:
6.2 Cenário NTB2B
Criadas as Party's, Services e Adapters (communication channels) para cada uma das três formas de envio, alterar o parâmetro "Type of Receiver Determination" para "Extended" no Receiver
Determination e escolher o Interface Mapping criado anteriormente:
7. TestesPara testar cada um dos cenários, ativar o B2B para um determinado CNPJ e na tabela criada, colocar qual a forma de envio que deseja enviar o XML.
Envio via E-Mail:
Envio via WebService:
Envio via Arquivo:
No labels
2 Comments
Fabio Fernandes
Parabéns Guedes.
Excelente trabalho sobre NFE e na disseminação do WIKI em português.
Abs,
Fábio Fernandes
Diretor Neoris / SAP Mentor
Fernando Ros
Excelente trabalho Guedes.
Adorei a qualidade das informações dá pra implementar sem ter que buscar informações complementares em outras fontes.
Abraços, Fernando Da Rós
Follow SCNContact Us SAP Help Portal
Privacy Terms of Use Legal Disclosure Copyright