Registration

Dear SAP Community Member,
In order to fully benefit from what the SAP Community has to offer, please register at:
http://scn.sap.com
Thank you,
The SAP Community team.
Skip to end of metadata
Go to start of metadata

Sumário

Criei esse wiki com intuito de auxiliar a comunidade de NF-e Brasil para cenário outbound (XML por Email)de NF-e com adaptações de códigos java disponíveis pelo Henrique Pinto e Carlos Rodrigo.

Com esse wiki você estará apto a enviar o arquivo XML com corpo de texto no e-mail de forma dinâmica para os cenários de, NF-e - CC-e e NF-e Cancelamento outbound, todos os passos requeridos para implementar no SAP NetWeaver Process Integration - O exemplo foi desenvolvido no SAP PI 7.0.

Autor: Ricardo Viana
Empresa: Neoris do Brasil
Criado em: 07/11/2012

Agradecimento

Agradecimento ao Carlos Rodrigo pela assistência e contribuição na codificação.

Conteúdo

  • SAP BO NFE 10.0 - Outbound B2B Interfaces com envio de XML + Corpo de texto dinâmico.
  • Aplicável na solução SAP GRC NFE 10.0 - Brasil
    • Autor: Ricardo Viana
  • Introdução
  • Passos da Implementação
    1. Desenvolvimento de Função no SAP GRC NF-e
      1. Tabela envolvida no SAP GRC NF-e 10.0 - /XNFE/NFEHD
    2. Desenvolvimento de função no SAP ECC
      1. Tabelas envolvidas no SAP R3/ECC - LF1 - KNA1 - ADR6
    3. Ajuste dos clientes na tabela /XNFE/TB2B
  • Configuração
  • Testes

Introdução

De acordo com o Ajuste SINIEF #8, de 07/09/2010 empresas que emitem NF-e's tem que enviar o XML de NF-e para o recebedor da nota e para o transportador.Já existe um Wiki, criada pelo Henrique Pinto http://scn.sap.com/docs/DOC-1719, que apresenta a solução para enviar o XML por email ao transportador usando configuração dinâmica.

Adaptei a solução proposta pelo Henrique Pinto e inseri o corpo de texto e e-mail dinâmico em apenas um javamapping, que atende as mudanças de layouts dos XML's para NF-e como (nfeProc (antigamente procNFe),procCancNFe (sem a tag <CNPJDest>) e procEventoNFe).

Com isso não é necessário utilizando um JavaMapping para converter as tags nfeProc para procNFe e gerar novamente uma string do XML, pois na nova versão para NF-e ou XML vem aberto e não como uma String.

Os seguintes passos abaixo precisam estar desenvolvidos antes de iniciarmos o desenvolvimento.

  • Recebedor (Destinatário) da NF-e já está mantida como válida e ativo parceiro B2B na tabela /XNFE/TB2B e ativo.
  • Necessário desenvolver uma função que receba como parametro a chave de acesso e retorne o e-mail. (/xnfe/nfehd - No GRC e retorna o CNPJ Destinatario,lfa1/kna1 e adr6).
  • Importar o arquivo JavaMapping no SAP PI.

Nos próximos capítulos do Wiki o envio da NF-e Aprovada/Cancelada e Carta de Correção Eletrônica como XML + corpo de texto dinâmico será apresentada com maiores detalhes.

Passos de Implementação

Inicialmente é criar um produto, software componente e colocar como dependência os SWCV (SAP SLL-NFE 1.0 E SAP BO NFE 10.0) na SLD, o que pode ser verificado no documento do Henrique Pinto - Página 4.

Desenvolvimento de Função no SAP GRC NF-e.

No meu caso em particular o Cliente já possuía um desenvolvimento de uma função que alimentava uma tabela Z no GRC com (CNPJ - EMAIL - DESCRIÇÃO), com isso não houve a necessidade de fazer uma outra função para o ECC ler a KNA1/LFA1 e a ADR6, porém essa solução não e a ideal por questão de manutenção e outros.

Criar uma função que receba um parâmetro de entrada CHAVE DE ACESSO da NF-e e retorna o CNPJ DO DESTINATARIO (STDC1).

Dentro dessa mesma função, com o CNPJ, desenvolver outra função que leia as infos das tabelas do sap ecc e retorne o e-mail.

Desenvolvimento de função no SAP ECC

Criar uma função que receba o CNPJ ou CPF e realiza consultas na KNA1 e LFA1 depois vá até a ADR6 e extraia o e-mail do cliente.

Ajuste dos clientes na tabela /XNFE/TB2B

Essa tabela deve estar sempre atualizada e os clientes que optarem em receber o XML da NF-e por e-mail devem estar ativos.

Para realizar essa configuração você deve ir a transação SPRONOTA FISCAL ELETRONICA

Outbound/Saida

Cadastro CNPJ

Código para Java Mapping

Basta importar o código no Ecplise ou qualquer outro compilador de sua preferência, adicionar as libs do SAP PI de desenvolvimento,
gerar o arquivo .JAR e importar no SAP PI.

Existe duas classes, uma é para definir o XML e capturar o e-mail e outra para definir o corpo de texto do e-mail.

No link abaixo você pode verificar as libs java - SAP - que você precisa importar no eclipse para realizar algum desenvolvimento:

Xi Libraries

Solicitar a um BASIS para te mandar as libs

Basis - SAP PI Libraries

Anexo + email:

Anexo
/*
 * Desenvolvedor: Ricardo Viana
 * Data:07/11/2012
 * Projeto: Upgrade NF-e 10.0
 * Java: Classe de envio de XML
 */

package nfeB2B.neoris;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

import com.sap.aii.mapping.api.StreamTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.lookup.Channel;
import com.sap.aii.mapping.lookup.LookupService;
import com.sap.aii.mapping.lookup.RfcAccessor;
import com.sap.aii.mapping.lookup.XmlPayload;

public class XmlNFe_To_Mail implements StreamTransformation{
	private String prefixoSubject = new String();
	private String emailFrom = new String();
	private String prefixoDocumento = new String();
	private	String	frase = new String();
	private String gap = "\n\r";
	// substituir pela da sua empresa
	private final String NFE_EMPRESA = "NFE EMPRESA X : ";
	private final String NFe = "NFE";
	//substituir essas variaveis pelo e-mail da sua empresa
	private final String NFe_Mail = "E-MAIL@EMPRESA X";

	public String getGap() {
		return gap;
	}

	public void setGap(String gap) {
		this.gap = gap;
	}

	public String getFrase() {
		return frase;
	}

	public void setFrase(String frase) {
		this.frase = frase;
	}

	//INI-------------------------------------------------------------
	// Configuracoes quando necessitar usar RFC Lookup

	// Substituir as infos abaixo com o BSsystem do GRC cadastrado no seu ambiente
	static String BSystem = "PIDCLNT810";
	// RFC de retorno do GRC
	static String CChannel = "CC_RFC_RCV";

	public String getBSystem() {
		return BSystem;
	}

	public String getPrefixoSubject() {
		return prefixoSubject;
	}

	public void setPrefixoSubject(String prefixoSubject) {
		this.prefixoSubject = prefixoSubject;
	}

	public String getEmailFrom() {
		return emailFrom;
	}

	public void setEmailFrom(String emailFrom) {
		this.emailFrom = emailFrom;
	}

	public String getPrefixoDocumento() {
		return prefixoDocumento;
	}

	public void setPrefixoDocumento(String prefixoDocumento) {
		this.prefixoDocumento = prefixoDocumento;
	}

	public String getCChannel() {
		return CChannel;
	}

	private void configParamEmail(){
		setEmailFrom(NFe_Mail);
		setPrefixoDocumento(NFe);
		setPrefixoSubject(NFE_EMPRESA);
	}

	public void execute(InputStream in, OutputStream out)
			throws StreamTransformationException {
		try{
			configParamEmail();

			//Transforma mensagem em entrada em string ----INICIO
			BufferedReader inpxml = new BufferedReader(new InputStreamReader(in));
			StringBuffer buffer = new StringBuffer();
			String line = "";

			while ((line = inpxml.readLine()) != null) {
				buffer.append(line);
			}

			String inptxml = buffer.toString();

			//Obtendo dados para o envio de e-mail
			String idNFe = "";
			String numeroNF = "";
			idNFe = inptxml.substring(inptxml.indexOf("<chNFe>")+7,inptxml.indexOf("</chNFe>"));
			numeroNF = idNFe.substring(25,34);

			if ( inptxml.indexOf("infEvento") > 0){
				this.setPrefixoDocumento(this.getPrefixoDocumento().replaceAll("NFE", "CCE"));
				this.setPrefixoSubject(this.getPrefixoSubject().replaceAll("NFE", "CCE"));
			}

			if ( inptxml.indexOf("infCanc") > 0){
				this.setPrefixoDocumento(this.getPrefixoDocumento().replaceAll("NFE", "CancNFe"));
				this.setPrefixoSubject(this.getPrefixoSubject().replaceAll("NFE", "NFE CANCELADA"));

			}

			//--------------------- RFC LOOKUP -----------------------------------------
			Channel chn = null;
			RfcAccessor rfc = null;
			String email = "";

			chn = LookupService.getChannel(this.getBSystem(), this.getCChannel());
			rfc = LookupService.getRfcAccessor(chn);

			// Substituir com a sua função
			String req = "<ns0:SUA FUNÇÃO xmlns:ns0='urn:sap-com:document:sap:rfc:functions'><I_CHAVE>" + idNFe +
"</I_CHAVE></ns0:SUA FUNÇÃO>";

			InputStream inputRFC = new ByteArrayInputStream(req.getBytes("UTF-8"));

			XmlPayload rfcPayload = LookupService.getXmlPayload(inputRFC);
			XmlPayload result = rfc.call(rfcPayload);

			InputStream resp = result.getContent();

			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document doc = builder.parse(resp);

			Node node = (Node) doc.getElementsByTagName("EMAIL").item(0);
			if (node.hasChildNodes() && !node.getFirstChild().getNodeValue().equals("")) {
				email = node.getFirstChild().getNodeValue();
			}

			//monta XML de saida XiMail
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer transform = tf.newTransformer();
			//Cria escopo do XML
			Document docout = db.newDocument();
			Element root = docout.createElement("ns1:Mail");
			root.setAttribute("xmlns:ns1", "http://sap.com/xi/XI/Mail/30");
			docout.appendChild(root);

			//Cria elemento Subject
			Element subject = docout.createElement("Subject");
			root.appendChild(subject);
			Text subjectText = docout.createTextNode(getPrefixoSubject()+numeroNF); //Cria valor campo
			subject.appendChild(subjectText);

			//Cria elemento From
			Element from = docout.createElement("From");
			root.appendChild(from);
			Text fromText = docout.createTextNode(getEmailFrom()); //Cria valor campo
			from.appendChild(fromText);

			if ( email.length() > 0 ){
				email += ";";
			}else {
				email = "nfe-empresa@xpto.com.br";
			}

			//Cria elemento To
			Element to = docout.createElement("To");
			root.appendChild(to);
			Text toText = docout.createTextNode(email); //Cria valor campo
			to.appendChild(toText);

			//Cria elemento Content Type
			Element contentType = docout.createElement("Content_Type");
			root.appendChild(contentType);
			//Text contentTypeText = docout.createTextNode("application/xml"); //Cria valor campo
			Text contentTypeText = docout.createTextNode("multipart/mixed;boundary=--AaZz"); //Cria valor campo
			contentType.appendChild(contentTypeText);

			// Criando o corpo de texto do e-mail e o anexo
			BodyText texto = new BodyText(idNFe,getFrase(),inptxml);
			//Cria elemento Content
			Element content = docout.createElement("Content");
			root.appendChild(content);
			Text contentText;

			// substituir a sua empresa
			if ("NFE EMPRESA X : ".equalsIgnoreCase(getPrefixoSubject())){
				contentText = docout.createTextNode(texto.getnfeText());
			}
			// substituir a sua empresa
			else if("NFE CANCELADA EMPRESA X: ".equalsIgnoreCase(getPrefixoSubject())){
				contentText = docout.createTextNode(texto.getCnfeText());
			}
			else
			{
				contentText = docout.createTextNode(texto.getcceText());
			}
			//Cria valor campo contet Text
			content.appendChild(contentText);


			//Cria elemento Content Disposition
			//Element contentDisp = docout.createElement("Content_Disposition");
			//root.appendChild(contentDisp);
			//Text contentDispText = docout.createTextNode("attachment;filename=" + getPrefixoDoxumento() + idNFe + ".xml"); //Cria valor campo
			//contentDisp.appendChild(contentDispText);

			//Fecha o XML
			DOMSource domS = new DOMSource(docout);
			transform.transform((domS), new StreamResult(out));

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void setParameter(Map arg0) {
		// TODO Auto-generated method stub

	}
	//public static void main(String[] args)String id ="50121140432544050080550060000000081234573380";
	//	System.out.println("Número da NF-e: "+id.substring(25, 34));
	//	System.out.println("Data emissão: "+ id.substring(4,6)+"/20"+id.substring(2,4));
	//	System.out.println("Série da NF-e: "+id.substring(22, 25));
	//}
}

Corpo de texto

Corpo e-mail
/*
 * Desenvolvedor: Ricardo Viana
 * Data:07/11/2012
 * Projeto: Upgrade NF-e 10.0
 * Java: Classe corpo de texto e-mail e anexo
 *
 */

package nfeB2B.neoris;

public class BodyText {
	private String nfeText = new String ();
	private String cnfeText = new String ();
	private String cceText = new String ();
	private String content = new String ();
	private String chaveNFe = new String ();
	private String frase = new String ();
	private String xmlString = new String ();
	private final String gap = "\n\r";
	private String numeroNFe =  new String ();
	private String dataNFe = new String ();
	private String serieNFe = new String ();
	//private String sefazNFe = new String();



	public BodyText(String chaveNFe, String frase, String xmlString) {
		this.chaveNFe = chaveNFe;
		this.frase = frase;
		this.xmlString = xmlString;
		this.numeroNFe = chaveNFe.substring(25, 34);
		this.dataNFe = chaveNFe.substring(4,6)+"/20"+chaveNFe.substring(2,4);
		this.serieNFe = chaveNFe.substring(22,25);
		//this.sefazNFe = chaveNFe.substring(0,2);
	}

	private String getGap() {
		return gap;
	}

	public String getnfeText() {
		// Corpo de texto da NF-e autorizada
		nfeText ="Prezado cliente, "+getGap()+getGap()+
	    "Segue arquivo anexo referente a Nota Fiscal Eletrônica "+ getGap()+ getGap()+
	    "Número da NF-e Autorizada: "+ numeroNFe +  getGap()+
	    "Série: "+ serieNFe+ getGap()+
	    "Data emissão (MM/AAAA): " + dataNFe + getGap()+getGap()+
	    "Atenciosamente,"+getGap()+getGap()+
	    "EMPRESA X";

		// Preencher o campo Content com o corpo de texto e arquivo .XML em anexo.
		content = "----AaZz\r\n Content-Type: text/plain; charset=UTF-8\r\n" +
        "Content-Disposition: inline\r\n\r\n" + nfeText +
        "\r\n----AaZz\r\nContent-Disposition: attachment; filename="+ "NF-e EMPRESA X - " + chaveNFe +
        ".xml" +"\r\n\r\n" + xmlString + "\r\n";

		return content;
	}

	public String getCnfeText() {
		// Corpo de texto do e-mail de NF-e cancelada
		cnfeText ="Prezado cliente, "+getGap()+getGap()+
	    "Segue arquivo anexo referente ao Cancelamento da Nota Fiscal Eletrônica."+ getGap()+getGap()+
	    "Número da NF-e cancelada: "+ numeroNFe +  getGap()+
	    "Série: "+ serieNFe+ getGap()+
	    "Data emissão (MM/AAAA): " + dataNFe + getGap()+getGap()+
	    "Atenciosamente,"+getGap()+getGap()+
	    "EMPRESA X";

		// Preencher o campo Content com o corpo de texto e arquivo .XML em anexo.
		content = "----AaZz\r\n Content-Type: text/plain; charset=UTF-8\r\n" +
        "Content-Disposition: inline\r\n\r\n" + cnfeText +
        "\r\n----AaZz\r\nContent-Disposition: attachment; filename="+ " NF-e Cancelada EMPRESA X - " + chaveNFe +
        ".xml" +"\r\n\r\n" + xmlString + "\r\n";

		return content;
	}

	public String getcceText() {
		// Corpo de texto do e-mail de carta de correção eletrônica
		cceText ="Prezado cliente, "+getGap()+getGap()+
	    "Segue arquivo anexo referente a Carta de Correção Eletrônica." + getGap()+ getGap() +
	    "Número da NF-e que recebeu correção eletrônica: "+ numeroNFe +  getGap()+
	    "Série: "+ serieNFe+ getGap()+
	    "Data emissão (MM/AAAA): " + dataNFe + getGap()+getGap()+
	    "Atenciosamente,"+getGap()+getGap()+
	    "EMPRESA X";

		// Preencher o campo Content com o corpo de texto e arquivo .XML em anexo.
		content = "----AaZz\r\n Content-Type: text/plain; charset=UTF-8\r\n" +
        "Content-Disposition: inline\r\n\r\n" + cceText +
        "\r\n----AaZz\r\nContent-Disposition: attachment; filename="+ "CC-e EMPRESA X - " + chaveNFe +
        ".xml" +"\r\n\r\n" + xmlString + "\r\n";
		return content;
	}
}

Configuração

A configuração é a parte mais tranquila para essas interfaces, vá para Repository do SAP PI no seu SWCV no BASICS OBJECTS - NameSpace...

Você precisa dentro do seu SWCV importar a estutura do XI Mail - SAP Note 748024

SWCV com depedência SAPBO SLL-NFE 10.0

Como foi explicado anteriormente o seu SWCV deve ter a dependencia do SAPBO SSL-NFE 10.0

SLD:

Importar a estrutura XiMail.xsd como external definition dentro do seu SWCV:


 
Importar o arquivo .jar extraido do seu compilador com os códigos acima:
 

Arquivo .jar importado, vai possuir duas classes.

 
Alterar as interfaces Inbound Stantard do SWCV ,que você incluiu na SLD como dependentes, no namespace: http://sap.com/xi/NFE/006 - SWCV - ZNFE10_B2BMAIL , 1.0 of xxx 

Alterar: CTB2B_procCancNFe_IB / ETB2B_procEventoNFe_IB e NTB2B_procNFe_IB , todos para estrutura do Mail

 

 Alterar os interfaces mapping stantard, incluindo o javaMapping na transformação, esse exemplo abaixo foi com a interface NTB2B_procNFe_TO_procNFe, o mesmo devem ser feitas para as interfaces de CTB2B_procCancNFe_TO_procCancNFe e ETB2B_procEventoNFe_TO_procEventoNFe:

Vamos agora para configuração:

Importar os cenários stantard via wizard e alterar os interfaces determinations para os do seu SWCV .

Você deve alterar as interfaces inbound dos três cenários e os interface determinations, pois, ambos foram alterados no repository, como pode ser visto em uma imagem anterior.

As interface inbound são Mail agora e os interfaces mapping receberam 1 java mapping a mais na tranformação.

Agora basta criar uma Party ou Bussiness Service, um canal de comunicação Mail com XIPAYLOAD e um detalhe muito importante deixar marcado Use Mail Package e no Content Encoding como None and Keep Attachments pode estar ou não verificado, vai funcionar.

Testes

sxi_monitor com positivo:

Caixa de e-mail com corpo e anexo para uma NF-e Autorizada:


 Exemplo de e-mail recebido para uma NF-e cancelada:

 

Bom espero que essa wiki auxilie pessoas que estão fazendo esses cenários, caso tenha carta de correção eletrônica, será necessário fazer uma adaptação simples no código java.

Atenciosamente,

Viana.

  • No labels

11 Comments

  1. Guest

    Muito bom o WIki, fiz tudo e estou com problemas.

    O Teste da Interface no Design está OK, o Teste da Interface no Configuration também está Ok, Inclusive consigo ver o Email que está sendo gerado, porém não envia o Email.

    Na SXI_MONITOR estou tendo a Exception StringIndexOutOfBoundsException: String Index out of Range: 0,  como as interfaces estão OK, o erro deve ser no CC, vc tem algo de diferente configurado no Module?

  2. Guest

    Rafael, verifique se esse erro não está acontecendo por causa do resultado dos emails da RFC. Pois se o retorno dos e-mails está vindo com " ; " a mais do que o necessário, vai dar exatamente esse erro.

  3. Oi Rafael Freitas boa tarde,

    Esse wiki funciona, outra duas pessoas utilizaram ele.

    Acredito que na copia e ao compilar o documento você deve ter feito alguma alteração por isso está gerando esse erro.

    Sugiro você verificar novamente o código java e fazer um teste no Interface Mapping ou Operation Mapping, dependendo da sua versão de SAP PI, se funcionar significa que esta tudo ok com o código.

    Agora vai a minha pergunta, você alterou no Interface Determination no cenário de B2B a interface INBOUND e o Interface/Operation Mapping ?

    Atenciosamente,

    Ricardo Viana.

  4. Rafael,

    Já descobri por que está dando esse erro : StringIndexOutOfBoundsException: String Index out of Range: 0

    A versão do seu PI é a 7.1 ?

    Se for esse código so funciona na 7.0

    Estou desenvolvendo para PI 7.1 agora, pois estou precisando.

    Quando terminar posto aqui

  5. Guest

    Muito Bom!

    Funcionou perfeitamente no PI  7.31.

    Fiz somente algumas adaptações mas para atender algumas necessidades da empresa.

    Obrigado Viana

  6. Alexandre boa noite,

    Muito bom cara !!

    Apenas na versao 7.10 ou 7.11 que precisa de uma adaptação no código de execute para transform.

    Parabens cara,

    Sucesso Abracos,

    Viana.

  7. Former Member

    Olá Ricardo,

    Estou dando os primeiros passos com NFe e pelo que entendi com este código java, eu não preciso do Message Mapping no PI, é isto mesmo? Possuo um material onde tenho que fazer todo o mapping e operation no Enterprise Builder.

  8. Former Member

     

    oi
    Estamos tentando implementar cenário de correio de saída B2B.
    A equipe de GRC e ECC não tem certeza de como enviar um anexo com o arquivo xml que deve ser enviado para Recepient na SEFAZ.

    Você pode nos ajudar com o que abordagem devemos folllow?
    Eu estou usando o google tradutor para traduzir Inglês para urso portugese.Please comigo se houver qualquer problema.

    Obrigado,
    Indu Khurana.

  9. Former Member

    Boa tarde, eu estou no SP 23 do grc. Este passo a passo ainda se aplica? 

    Obrigado,

    Renan

    1. Former Member

      Boa tarde Renan. Não tivemos problemas em usar essa solução como apoio para o B2B Outbound aqui. Também estamos no SP 23

  10. Former Member

    Boa tarde. Segui esse passo a passo e aqui funcionou corretamente. Muito obrigado e parabéns pelo artigo.