Olá pessoal…
Hoje vou mostrar uma função que desenvolvi, que retorna o xml de uma nota transmitida ou cancelada via AdvPL.
A função utiliza recursos do TSS para carregar e criar o arquivo xml, é necessário apenas informar, o número da nota, a série, e o caminho para geração do arquivo xml.
Abaixo a função desenvolvida:
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zSpedXML Função que gera o arquivo xml da nota (normal ou cancelada) através do documento e da série disponibilizados @author Atilio @since 25/07/2017 @version 1.0 @param cDocumento, characters, Código do documento (F2_DOC) @param cSerie, characters, Série do documento (F2_SERIE) @param cArqXML, characters, Caminho do arquivo que será gerado (por exemplo, C:\TOTVS\arquivo.xml) @param lMostra, logical, Se será mostrado mensagens com os dados (erros ou a mensagem com o xml na tela) @type function @example Segue exemplo abaixo u_zSpedXML("000000001", "1", "C:\TOTVS\arquivo1.xml", .F.) //Não mostra mensagem com o XML u_zSpedXML("000000001", "1", "C:\TOTVS\arquivo2.xml", .T.) //Mostra mensagem com o XML /*/ User Function zSpedXML(cDocumento, cSerie, cArqXML, lMostra) Local aArea := GetArea() Local cURLTss := PadR(GetNewPar("MV_SPEDURL","http://"),250) Local oWebServ Local cIdEnt := RetIdEnti() Local cTextoXML := "" Default cDocumento := "" Default cSerie := "" Default cArqXML := GetTempPath()+"arquivo_"+cSerie+cDocumento+".xml" Default lMostra := .F. //Se tiver documento If !Empty(cDocumento) cDocumento := PadR(cDocumento, TamSX3('F2_DOC')[1]) cSerie := PadR(cSerie, TamSX3('F2_SERIE')[1]) //Instancia a conexão com o WebService do TSS oWebServ:= WSNFeSBRA():New() oWebServ:cUSERTOKEN := "TOTVS" oWebServ:cID_ENT := cIdEnt oWebServ:oWSNFEID := NFESBRA_NFES2():New() oWebServ:oWSNFEID:oWSNotas := NFESBRA_ARRAYOFNFESID2():New() aAdd(oWebServ:oWSNFEID:oWSNotas:oWSNFESID2,NFESBRA_NFESID2():New()) aTail(oWebServ:oWSNFEID:oWSNotas:oWSNFESID2):cID := (cSerie+cDocumento) oWebServ:nDIASPARAEXCLUSAO := 0 oWebServ:_URL := AllTrim(cURLTss)+"/NFeSBRA.apw" //Se tiver notas If oWebServ:RetornaNotas() //Se tiver dados If Len(oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3) > 0 //Se tiver sido cancelada If oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFECANCELADA != Nil cTextoXML := oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFECANCELADA:cXML //Senão, pega o xml normal Else cTextoXML := oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFE:cXML EndIf //Gera o arquivo MemoWrite(cArqXML, cTextoXML) //Se for para mostrar, será mostrado um aviso com o conteúdo If lMostra Aviso("zSpedXML", cTextoXML, {"Ok"}, 3) EndIf //Caso não encontre as notas, mostra mensagem Else ConOut("zSpedXML > Verificar parâmetros, documento e série não encontrados ("+cDocumento+"/"+cSerie+")...") If lMostra Aviso("zSpedXML", "Verificar parâmetros, documento e série não encontrados ("+cDocumento+"/"+cSerie+")...", {"Ok"}, 3) EndIf EndIf //Senão, houve erros na classe Else ConOut("zSpedXML > "+IIf(Empty(GetWscError(3)), GetWscError(1), GetWscError(3))+"...") If lMostra Aviso("zSpedXML", IIf(Empty(GetWscError(3)), GetWscError(1), GetWscError(3)), {"Ok"}, 3) EndIf EndIf EndIf RestArea(aArea) Return
Update Dezembro de 2021:
O grande Jorge Alberto ( LinkedIn ), fez uma contribuição para que seja exportado a tag NFeProc juntamente com a tag do XML principal, abaixo segue o exemplo (trecho alterado da linha 59 a 63):
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zSpedXML Função que gera o arquivo xml da nota (normal ou cancelada) através do documento e da série disponibilizados @author Atilio @since 25/07/2017 @version 1.0 @param cDocumento, characters, Código do documento (F2_DOC) @param cSerie, characters, Série do documento (F2_SERIE) @param cArqXML, characters, Caminho do arquivo que será gerado (por exemplo, C:\TOTVS\arquivo.xml) @param lMostra, logical, Se será mostrado mensagens com os dados (erros ou a mensagem com o xml na tela) @type function @example Segue exemplo abaixo u_zSpedXML("000000001", "1", "C:\TOTVS\arquivo1.xml", .F.) //Não mostra mensagem com o XML u_zSpedXML("000000001", "1", "C:\TOTVS\arquivo2.xml", .T.) //Mostra mensagem com o XML /*/ User Function zSpedXML(cDocumento, cSerie, cArqXML, lMostra) Local aArea := GetArea() Local cURLTss := PadR(GetNewPar("MV_SPEDURL","http://"),250) Local oWebServ Local cIdEnt := RetIdEnti() Local cTextoXML := "" Default cDocumento := "" Default cSerie := "" Default cArqXML := GetTempPath()+"arquivo_"+cSerie+cDocumento+".xml" Default lMostra := .F. //Se tiver documento If !Empty(cDocumento) cDocumento := PadR(cDocumento, TamSX3('F2_DOC')[1]) cSerie := PadR(cSerie, TamSX3('F2_SERIE')[1]) //Instancia a conexão com o WebService do TSS oWebServ:= WSNFeSBRA():New() oWebServ:cUSERTOKEN := "TOTVS" oWebServ:cID_ENT := cIdEnt oWebServ:oWSNFEID := NFESBRA_NFES2():New() oWebServ:oWSNFEID:oWSNotas := NFESBRA_ARRAYOFNFESID2():New() aAdd(oWebServ:oWSNFEID:oWSNotas:oWSNFESID2,NFESBRA_NFESID2():New()) aTail(oWebServ:oWSNFEID:oWSNotas:oWSNFESID2):cID := (cSerie+cDocumento) oWebServ:nDIASPARAEXCLUSAO := 0 oWebServ:_URL := AllTrim(cURLTss)+"/NFeSBRA.apw" //Se tiver notas If oWebServ:RetornaNotas() //Se tiver dados If Len(oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3) > 0 //Se tiver sido cancelada If oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFECANCELADA != Nil cTextoXML := oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFECANCELADA:cXML //Senão, pega o xml normal (foi alterado abaixo conforme dica do Jorge Alberto) Else cTextoXML := '<?xml version="1.0" encoding="UTF-8"?>' cTextoXML += '<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">' cTextoXML += oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFE:cXML cTextoXML += oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFE:cXMLPROT cTextoXML += '</nfeProc>' EndIf //Gera o arquivo MemoWrite(cArqXML, cTextoXML) //Se for para mostrar, será mostrado um aviso com o conteúdo If lMostra Aviso("zSpedXML", cTextoXML, {"Ok"}, 3) EndIf //Caso não encontre as notas, mostra mensagem Else ConOut("zSpedXML > Verificar parâmetros, documento e série não encontrados ("+cDocumento+"/"+cSerie+")...") If lMostra Aviso("zSpedXML", "Verificar parâmetros, documento e série não encontrados ("+cDocumento+"/"+cSerie+")...", {"Ok"}, 3) EndIf EndIf //Senão, houve erros na classe Else ConOut("zSpedXML > "+IIf(Empty(GetWscError(3)), GetWscError(1), GetWscError(3))+"...") If lMostra Aviso("zSpedXML", IIf(Empty(GetWscError(3)), GetWscError(1), GetWscError(3)), {"Ok"}, 3) EndIf EndIf EndIf RestArea(aArea) Return
Update Fevereiro de 2022:
O grande Josuel Silva ( LinkedIn ), fez uma adaptação no fonte para usar a classe FWFileWriter ao invés de MemoWrite, assim podendo usar a codificação UTF8. Segue abaixo:
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zSpedXML Função que gera o arquivo xml da nota (normal ou cancelada) através do documento e da série disponibilizados @author Atilio @since 25/07/2017 @version 1.0 @param cDocumento, characters, Código do documento (F2_DOC) @param cSerie, characters, Série do documento (F2_SERIE) @param cArqXML, characters, Caminho do arquivo que será gerado (por exemplo, C:\TOTVS\arquivo.xml) @param lMostra, logical, Se será mostrado mensagens com os dados (erros ou a mensagem com o xml na tela) @type function @example Segue exemplo abaixo u_zSpedXML("000000001", "1", "C:\TOTVS\arquivo1.xml", .F.) //Não mostra mensagem com o XML u_zSpedXML("000000001", "1", "C:\TOTVS\arquivo2.xml", .T.) //Mostra mensagem com o XML /*/ User Function zSpedXML(cDocumento, cSerie, cArqXML, lMostra) Local aArea := GetArea() Local cURLTss := PadR(GetNewPar("MV_SPEDURL","http://"),250) Local oWebServ Local cIdEnt := RetIdEnti() Local cTextoXML := "" Local oFileXML Default cDocumento := "" Default cSerie := "" Default cArqXML := GetTempPath()+"arquivo_"+cSerie+cDocumento+".xml" Default lMostra := .F. //Se tiver documento If !Empty(cDocumento) cDocumento := PadR(cDocumento, TamSX3('F2_DOC')[1]) cSerie := PadR(cSerie, TamSX3('F2_SERIE')[1]) //Instancia a conexão com o WebService do TSS oWebServ:= WSNFeSBRA():New() oWebServ:cUSERTOKEN := "TOTVS" oWebServ:cID_ENT := cIdEnt oWebServ:oWSNFEID := NFESBRA_NFES2():New() oWebServ:oWSNFEID:oWSNotas := NFESBRA_ARRAYOFNFESID2():New() aAdd(oWebServ:oWSNFEID:oWSNotas:oWSNFESID2,NFESBRA_NFESID2():New()) aTail(oWebServ:oWSNFEID:oWSNotas:oWSNFESID2):cID := (cSerie+cDocumento) oWebServ:nDIASPARAEXCLUSAO := 0 oWebServ:_URL := AllTrim(cURLTss)+"/NFeSBRA.apw" //Se tiver notas If oWebServ:RetornaNotas() //Se tiver dados If Len(oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3) > 0 //Se tiver sido cancelada If oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFECANCELADA != Nil cTextoXML := oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFECANCELADA:cXML //Senão, pega o xml normal (foi alterado abaixo conforme dica do Jorge Alberto) Else cTextoXML := '<?xml version="1.0" encoding="UTF-8"?>' cTextoXML += '<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">' cTextoXML += oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFE:cXML cTextoXML += oWebServ:oWsRetornaNotasResult:OWSNOTAS:oWSNFES3[1]:oWSNFE:cXMLPROT cTextoXML += '</nfeProc>' EndIf //Gera o arquivo oFileXML := FWFileWriter():New(cArqXML, .T.) oFileXML:SetEncodeUTF8(.T.) oFileXML:Create() oFileXML:Write(cTextoXML) oFileXML:Close() //Se for para mostrar, será mostrado um aviso com o conteúdo If lMostra Aviso("zSpedXML", cTextoXML, {"Ok"}, 3) EndIf //Caso não encontre as notas, mostra mensagem Else ConOut("zSpedXML > Verificar parâmetros, documento e série não encontrados ("+cDocumento+"/"+cSerie+")...") If lMostra Aviso("zSpedXML", "Verificar parâmetros, documento e série não encontrados ("+cDocumento+"/"+cSerie+")...", {"Ok"}, 3) EndIf EndIf //Senão, houve erros na classe Else ConOut("zSpedXML > "+IIf(Empty(GetWscError(3)), GetWscError(1), GetWscError(3))+"...") If lMostra Aviso("zSpedXML", IIf(Empty(GetWscError(3)), GetWscError(1), GetWscError(3)), {"Ok"}, 3) EndIf EndIf EndIf RestArea(aArea) Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Muito bom, obrigado por compartilhar seu conhecimento, estou aprendendo muito aqui no seu site.
Tem uma documentação completa sobre a WSNFeSBRA? ou como faço pra ver todos os Metodos dela?
Bom dia William, tudo bem?
Por ser uma classe padrão, apenas a TOTVS possui a documentação dela, se você for um cliente, você pode solicitar por chamado. Mas não sei se passariam isso.
Agora, se você for um analista da TOTVS, se tiver a chave de ouro, procure pelo .prx e no fonte padrão estará os métodos dela.
Um grande abraço.
Não testei, mas achei sensacional pela simplicidade do código, pelo uso dos recursos da linguagem, sem reinvenção da “roda”. Obrigado por compartilhar.
Obrigado pelo feedback Emerson.
Grande abraço jovem.
Boa tarde!
Estou precisando de uma função parecida, mas já tenho o XML e preciso gerar o PDF. Teria alguma opinião para o que pode ser feito?
Bom dia André, tudo bem?
Claro, o que você pode fazer, seria +- assim:
1 – Criar uma tela de parâmetros com o caminho do xml de origem
2 – No seu fonte, usar XMLParser / XMLParserFile para converter o texto em um objeto
3 – Instanciar um FWMSPrinter em um objeto
4 – Percorrer os nós do XML no objeto e imprimir no objeto de impressão
Consigo gerar o XML mas vem sem PROTOCOLO DE AUTORIZAÇÃO DE USO ? Alguem com este problema nao consigo acertar o codigo…
Então Geraldo, a função usa a conexão padrão do Protheus. A NFe já foi transmitida? Você está usando pelo SIGAADV ou SIGAMDI?
SIGAMDI , VOU TESTAR PELO SIGAADV e sim ja trasmitida e autorizada quando uso o exportar padrao do TSS ele exporta correto … estava subindo novo release mas vou retomar este assunte mas por enquanto muito obrigado todos os posts aqui so Fera … Vlw
Bom dia Dan_Atilio! Utilizei seu fonte para efetuar o download do XML, porém, alguns XML’s não vem no padrão correto. Alguns ele baixa normalmente, mas outros vem com informações ‘cortadas’ e vem tudo em uma mesma linha. Quando abro em .TXT ele traz normalmente as informações. Pode me dizer o porquê? Obrigado.
Bom dia Vitor.
O de trazer na mesma linha, é similar a você ir no Protheus, na tela de monitorar, pegar o schema e colar.
Ai para quebrar as linhas, você pode usar um plugin no Notepad++, o XML Tools (opção Pretty Print XML With Line Breaks).
Quanto ao conteúdo vir cortado, não sei te dizer, não peguei casos assim. Sempre corta com um número exato de caracteres?
Olá Danilo.
Teria alguma função para emitir NFs de entrada?
Essa só gera de NFs de saída.
Olá Thiago.
Eu não possuo, mas meu amigo Súlivan tem uma solução para isso, veja – https://sulivansistemas.com/protheus-download-xml-sefaz/
Ao entrar em contato com ele, fala que você veio pelo Terminal de Informação do Daniel Atilio. Pode ser que consiga um desconto.
Bom dia Dan_Atilio
Estou usando em um cliente a funcao que retorna o xml
e no meu caso esta gerando sem o protoloco de autorizacao.
debugando o fonte na classe que carrega o gera o xml, nao esta gerando com o protocolo mesmo
Tem ideia do que pode ser ?
Bom dia Wilker.
Se você fizer o processo manualmente funciona?
Por exemplo, abrir o SIGAMDI, ir em Faturamento, Nfe Sefaz, Outras Ações, Monitorar, Inserir o número da Nota, clicar em outras ações, e depois clicar em Schema e salvar o XML. Dessa forma traz o protocolo?
Abraços.
Aos colegas que estão com o problema do xml ser gerado sem o protocolo de uso, substitua a linha 59 pelo trecho abaixo:
Queria saber se tem algum parâmetro que pode ser informado para pesquisar no ambiente de de produção ou homologação
Acho que não tem Guilherme, pois ele vai pegar as parametrizações da empresa logada (através do MV_SPEDURL).
Fiz uma pequena alteração no fonte no momento da gravação substituído a função MemoWrite pela Classe FWFileWriter.
Desta forma, caso o XML contenha algum carácter UTF8, é possível setar a classe para gravar nesse formato e não deixar o XML inválido.
Alterado de :
MemoWrite(cArqXML, cTextoXML)
Para:
oFileXML := FWFileWriter():New(cArqXML, .T.)
oFileXML:SetEncodeUTF8(.T.)
oFileXML:Create()
oFileXML:Write(cTextoXML)
oFileXML:Close()
Isso me ajudou a corrigir um problema na geração do XML devido descrição de condição de pagamento:
Antes:
Negocia��o Futura
Depois:
Negociação Futura
Grato
Opa, muito obrigado pelo comentário e contribuição Josuel.
Realmente uma ótima dica, trocar para FWFileWriter.
Grande abraço.
Essa função RetIdEnti() ela é nativa ou você implementou ela Daniel?
Olá, Daniel.
Tenho uma dúvida, essa função para obter o IdEnt é nativa ou você desenvolveu ela? RetIdEnti()
Bom dia Thiago, tudo bem?
Sim ela é nativa.
Tanto que, para verificar no seu ambiente, aperte Ctrl + Shift + P no VSCode, e vá em inspetor de funções.
Procure pelo nome dessa função, ela estará dentro do SPEDNFE.PRX
Olá @ThiagoM,
esta função é nativa e retorna o codigo da entidade que será enviado para o TSS.
Basicamente para ela relaciona o codigo que está relacionado a Filial logada.
Grato.
boa noite! muito boa a função!
estou com um problema, utilizando ela via menu no sigamdi funcionou perfeitamente. Porem ao fazer a chamada a partir de uma API Rest , retorna que não achou a NF “zSpedXML > Verificar parâmetros, documento e série não encontrados” .
Bom dia Rodolfo.
Obrigado pelo feedback. Eu tive esse problema uma vez em REST, e era por causa que a filial não estava posicionada corretamente.
Então para resolver, tive que usar a função OpenFile, conforme esse exemplo: https://terminaldeinformacao.com/2021/12/01/como-mudar-de-empresa-e-filial-com-a-funcao-openfile/
Boa tarde!
Como faço para executar est função dentro da API?
Grato
Bom dia Altair, tudo joia?
Para acionar a chamada através de outros fontes, você deve fazer o seguinte:
Ai a partir disso, você consegue usar essa variável cConteudo.
Verifiquei aqui Altair, e você é um assinante premium, caso você queira, tem um fonte pronto de WebService com exemplo acionando a geração do xml e do pdf da Danfe, basta você acessar sua conta na Hotmart, ir em fontes premium, e no número 18 vai ter lá WebService para gerar a DANFE e o XML de uma NF. Esse é o link de exemplo desse conteúdo premium: https://terminaldeinformacao.com/2022/02/04/webservice-para-gerar-a-danfe-e-o-xml-de-uma-nf/
Um grande abraço.
esse webservice baixa notas que nao esteja no sped050?
Bom dia.
Não, essa rotina é específica para Notas que já estejam na SPED050.
Se você quer uma para baixar o XML direto do SEFAZ, recomendo verificar uma desenvolvida pelo Súlivan Simões – https://sulivansistemas.com/wp/protheus-rotina-de-download-de-xml-de-nf-e-e-ct-e/
Boa tarde!
O fonte funciona caso o Protheus e o TSS estejam no Cloud do Totvs?
É necessária alguma configuração específica no TSS?
Boa tarde Lucas, tudo joia?
Sim, nós já implantamos em clientes que usam o TCloud.
No caso não precisa de configuração específica, apenas o MV_SPEDURL precisa estar apontando para o TSS corretamente.
Boa tarde Rodofolfo!
Com fez para chamar a fcunção a partir da API? preciso chamá-la no GET.
Parabéns pelo trabalho!
Bom dia Douglas.
Nós que agradecemos pelo comentário e feedback.
Grande abraço.
Oi, bom dia. Parabéns pelo conteúdo!
Existe alguma customização para imprimir danfes canceladas?
Bom dia Marcos, tudo joia?
Obrigado pelo comentário e feedback.
Ainda não temos, pode ser que no futuro desenvolvemos algum template.
Se inscreva na nossa newsletter, que se fizermos, publicaremos um artigo divulgando.
Um grande abraço.
Boa tarde,
Existe a função da TOTVS que trás o xml e outras informações em um array: GetXMLNFE(cIdEnt, aNfs, @cModalidade, )
Bom dia Edilson, tudo joia?
Opa, show de bola, desconhecia essa GetXMLNFE, vou adicionar aqui na to-do list para estudar sobre.
Tenha uma ótima e abençoada quinta feira.
Um grande abraço.
Boa tarde!
Consigo filtrar apenas para gerar os XMLs das notas de venda? Pq temos operações de transferências entre filiais, devoluções de compras, entre outras, que utilizam a mesma rotina.
Desde já agradeço!
Bom dia Adauto, tudo joia?
Sim, você consegue, mas tem que ser na função anterior sua, que irá acionar a u_zSpedXML.
Por exemplo, nessa sua função anterior, você pode fazer uma query na SF2, e já filtrar o F2_TIPO antes de acionar a u_zSpedXML, nesse link tem um exemplo (veja o trecho escrito “Abaixo um Exemplo com While”: https://terminaldeinformacao.com/2019/03/02/funcao-para-gerar-danfe-e-xml-de-uma-nota-em-uma-pasta-via-advpl/
Tenha um ótimo e abençoado fim de semana.
Um grande abraço.