Você já precisou gerar o PDF e o XML de uma nota em uma pasta qualquer?
Basicamente, nessa função desenvolvida, você passa por parâmetro o número da nota, a série e a pasta em que quer os arquivos gerados. A partir disso, é chamado a função zSpedXML (Função que retorna o xml de uma nota em AdvPL). Depois disso, é acessado o RDMake da DANFEII e gerado o pdf da danfe.Abaixo o código fonte desenvolvido:
//Bibliotecas #Include "Protheus.ch" #Include "TBIConn.ch" #Include "Colors.ch" #Include "RPTDef.ch" #Include "FWPrintSetup.ch" /*/{Protheus.doc} zGerDanfe Função que gera a danfe e o xml de uma nota em uma pasta passada por parâmetro @author Atilio @since 10/02/2019 @version 1.0 @param cNota, characters, Nota que será buscada @param cSerie, characters, Série da Nota @param cPasta, characters, Pasta que terá o XML e o PDF salvos @type function @example u_zGerDanfe("000123ABC", "1", "C:\TOTVS\NF") @obs Para o correto funcionamento dessa rotina, é necessário: 1. Ter baixado e compilado o rdmake danfeii.prw 2. Ter baixado e compilado o zSpedXML.prw - https://terminaldeinformacao.com/2017/12/05/funcao-retorna-xml-de-uma-nota-em-advpl/ /*/ User Function zGerDanfe(cNota, cSerie, cPasta) Local aArea := GetArea() Local cIdent := "" Local cArquivo := "" Local oDanfe := Nil Local lEnd := .F. Local nTamNota := TamSX3('F2_DOC')[1] Local nTamSerie := TamSX3('F2_SERIE')[1] Local dDataDe := sToD("20190101") Local dDataAt := Date() Private PixelX Private PixelY Private nConsNeg Private nConsTex Private oRetNF Private nColAux Default cNota := "" Default cSerie := "" Default cPasta := GetTempPath() //Se existir nota If ! Empty(cNota) //Pega o IDENT da empresa cIdent := RetIdEnti() //Se o último caracter da pasta não for barra, será barra para integridade If SubStr(cPasta, Len(cPasta), 1) != "\" cPasta += "\" EndIf //Gera o XML da Nota cArquivo := cNota + "_" + dToS(Date()) + "_" + StrTran(Time(), ":", "-") u_zSpedXML(cNota, cSerie, cPasta + cArquivo + ".xml", .F.) //Define as perguntas da DANFE Pergunte("NFSIGW",.F.) MV_PAR01 := PadR(cNota, nTamNota) //Nota Inicial MV_PAR02 := PadR(cNota, nTamNota) //Nota Final MV_PAR03 := PadR(cSerie, nTamSerie) //Série da Nota MV_PAR04 := 2 //NF de Saida MV_PAR05 := 1 //Frente e Verso = Sim MV_PAR06 := 2 //DANFE simplificado = Nao MV_PAR07 := dDataDe //Data De MV_PAR08 := dDataAt //Data Até //Cria a Danfe oDanfe := FWMSPrinter():New(cArquivo, IMP_PDF, .F., , .T.) //Propriedades da DANFE oDanfe:SetResolution(78) oDanfe:SetPortrait() oDanfe:SetPaperSize(DMPAPER_A4) oDanfe:SetMargin(60, 60, 60, 60) //Força a impressão em PDF oDanfe:nDevice := 6 oDanfe:cPathPDF := cPasta oDanfe:lServer := .F. oDanfe:lViewPDF := .F. //Variáveis obrigatórias da DANFE (pode colocar outras abaixo) PixelX := oDanfe:nLogPixelX() PixelY := oDanfe:nLogPixelY() nConsNeg := 0.4 nConsTex := 0.5 oRetNF := Nil nColAux := 0 //Chamando a impressão da danfe no RDMAKE RptStatus({|lEnd| u_DanfeProc(@oDanfe, @lEnd, cIdent, , , .F.)}, "Imprimindo Danfe...") oDanfe:Print() EndIf RestArea(aArea) Return
Caso precise gerar várias notas, basta fazer um while ou for com os dados e chamar a função zGerDanfe, abaixo um exemplo com for:
Local nAtual := 0 Local aNotas := {} // Nota Série Pasta aAdd(aNotas, {"000000001", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000002", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000003", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000004", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000005", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000006", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000007", "1", "C:\TOTVS\NF"}) aAdd(aNotas, {"000000008", "1", "C:\TOTVS\NF"}) For nAtual := 1 To Len(aNotas) u_zGerDanfe(aNotas[nAtual][01], aNotas[nAtual][02], aNotas[nAtual][03]) Next
Abaixo um Exemplo com While:
//Monta a consulta e executa cQuery := " SELECT F2_DOC, F2_SERIE ...." TCQuery cQuery New Alias "QRY" //enquanto houver dados While ! QRY->(EoF()) //chama a rotina u_zGerDanfe(QRY->F2_DOC, QRY->F2_SERIE, "C:\TOTVS\NF") //pula registro QRY->(DbSkip()) EndDo
Atenção – Update 2020
Se o seu arquivo estiver sendo gerado com 1 kb, no pacote RDMAKE novo disponibilizado pela TOTVS, verifique a função DanfeProc. Nas versões antigas, ela era uma Static Function (por isso usamos o StaticCall), como ela é uma User Function agora, pode-se utilizar diretamente u_DanfeProc.
Atenção – Update 2022
Se o seu arquivo estiver sendo gerado com conteúdo vazio, a TOTVS criou dois parâmetros novos no NFSIGW de Data De e Data Até, os MV_PAR07 e MV_PAR08, eu atualizei o fonte acima informando esses dois, revise o seu fonte caso esteja com esse mesmo problema.
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Boa tarde teria como ao invés de passar o número da chave fazer uma pesquisa por data de emissão e baixar várias notas de uma vez?
Bom dia Fabrício.
Sim teria, no exemplo escrito “Exemplo com While”, veja que no começo é feito uma query na SF2, basta você filtrar o F2_EMISSAO.
Abraços.
Boa Noite Dan
Obrigado pelas dicas e ajudas que proporciona para todos!.
Mas estou com um problema, neste fonte da geração da danfe, no momento que executa o trecho do código “oDanfe:Print()”, abre a tela das perguntas da rotina, sendo que dentro tem “Pergunte(“NFSIGW”,.F.)”, sabe o que pode ser ?
Valeuu
Boa noite Saimon.
Nos ambientes que testei, funcionou, pode ser alguma coisa especifica do seu danfeii.prw.
Dentro do fonte, veja onde tem Pergunte(“…”, .T.) para fazer testes.
Qualquer coisa, entre no nosso fórum do Discord, para podermos te ajudar.
Abraços.
show!! código perfeito e ainda usa o DANFEII padrão. valeu!
Opa, obrigado pelo comentário Fabio.
Grande abraço.
Olá Dan,
Obrigado por compartilhar conhecimento e dispor tempo em produzir o material.
Estou à procura de alguma rotina padrão ou customizada que gere o DANFE a partir de um XML que recebi de um fornecedor, você já desenvolveu algo assim ou sabe se no Protheus tenha no Padrão ?
Grande Abraço
Rodrigo Teixeira
Bom dia Rodrigo, tudo bem?
Obrigado pelo feedback jovem.
Na verdade, eu pensei em desenvolver já, mas acabei deixando de molho por enquanto.
Abraços.
Eu apliquei os fontes, mas está gerando o PDF com apenas 1k e vazio.
Ja teve essa situação ?
Aha! Achei o problema. No Fonte tá chamando a DANFEPROC como Static e ela é USER.
Obrigado.
Opa, obrigado pelo comentário Dantas.
Realmente no RDMAKE novo, a Static Function se tornou User Function.
Abraços.
Porque todas danfe que eu tento gera apenas 1kb
Bom dia Francisco.
Conforme comentário acima do Dantas, no pacote RDMAKE novo, a DanfeProc é uma User Function, então não precisa chamar ela com StaticCall.
Bom dia,
o RDMAKE que estou utilizando a DanfeProc ainda é uma Static Function porém só gera arquivos com 1kb. Tem alguma outra alternativa?
Boa tarde Tiago.
Nesse caso, acho que só debugando o código mesmo.
Coloca um Breakpoint logo no começo do DanfeProc e um logo antes do Return, e veja se o objeto está sendo manipulado.
Grande abraço.
Dan
Excelente material. Teria uma função que leia um arquivo XML (XML DO FORNECEDOR) e imprima uma DANFE em PDF ?
Obrigado
Abraço
Wagner
Bom dia Wagner.
Infelizmente não possuo jovem.
Grande abraço.
Dan, excelente material.
Por um acaso você teria uma rotina que lê o arquivo XML (FORNECEDOR) em uma determinada pasta e gere uma DANFE em PDF ?
Obrigado
Wagner
Bom dia Wagner.
Infelizmente não possuo jovem.
Grande abraço.
Danilo para corrigir o problema de 1k teria que chamar direto ficando assim?
RPTStatus({|lEnd| U_DANFEProc(@oDanfe, @lEnd, cIDEnt, , , .F.,,,)}, “Imprimindo DANFE…” )
Mas mesmo assim não deu certo, poderia me auxiliar?
Então Thiago, acho que não precisa de RPTStatus, pode chamar direto, por exemplo:
U_DANFEProc(@oDanfe, , cIDEnt, Nil, Nil, @lExistNFe, lIsLoja,,lAutomato )
Essa linha acima peguei direto do fonte DANFEII do RDMAKE.
Dantas poderia compartilhar sua modificações nas linhas:
//Chamando a impressão da danfe no RDMAKE
RptStatus({|lEnd| StaticCall(DANFEII, DanfeProc, @oDanfe, @lEnd, cIdent, , , .F.)}, “Imprimindo Danfe…”)
oDanfe:Print()
Pois a que fiz não está dando certo
Aguem ai esta com erro de gerar somente XML sem autorizacao ? pela funcao exportar do TSS ele traz completo
Você está executando dentro do SIGAMDI / SIGAADV?
Bom dia Dan estou com o mesmo problema do Geraldo, estou executando chamando pelo SIGAMDI e gera o XML sem a autorização.
Bom dia Roberto.
Acho que pode ser alguma customização dentro do danfeii ou até mesmo variáveis.
Talvez eu teria analisar o código fonte, se quiser nos mande, entrando em contato – https://atiliosistemas.com/contato/
Boa tarde Atilio, beleza?
Queria agradecer por compartilhar seu conhecimento com a gente de forma clara é simples, isso ajuda muito, utilizo e recomendo seu site para muitos de meus amigos que compartilham do mesmo problema.
Para quem teve problemas com a nova chamada gerando o danfe com arquivo vazio a chamada que funcionou foi essa.
RPTStatus( {|lEnd| U_DANFEProc(@oDanfe, @lEnd, cIDEnt, Nil, Nil, .F., .F.,,.F. )}, “Imprimindo DANFE…” )
Vlw Flw
Opa, eu que agradeço pelo comentário Gustavo.
Aí sim hein, esse comentário vai ajudar bastante o pessoal.
Grande abraço.
Boa Tarde Atilio, utilizar sua rotinas para gerar XML e DANFE, mas não estou conseguindo imprimir o DANFE quando a rotina é chamada via agendamento/schedule. Voce, com sua experiencia, já fez a impressão do danfe via schedule ?
Grande abraço
Bom dia Gildesio, tudo bem?
Eu nunca precisei fazer via Schedule, mas já imprimi outros FWMSPrinter dessa forma.
A chave é ir testando os atributos e métodos e corrigindo os erros conforme forem sendo exibidos.
Nesse link tem exemplo de geração do FWMSPrinter via job: https://terminaldeinformacao.com/knowledgebase/fwmsprinter/
Grande abraço.
Parabéns pela ferramenta, estou usando, fiz aquela adaptação para buscar mais de um arquivo conforme código abaixo. O único problema é que compilei em uma rpo de teste que tenho aqui e na produção, no rpo de teste, ele cria os pdfs certinho, quando rodo no rpo da produção ele gera um arquivo de 1k.
Se eu pegar o rpo da produção e jogar na teste, ele funciona normal, se eu voltar para a produção ele gera arquivo de 1k, já deixei o appserver.ini iguais, já coloquei no mesmo balance e nada. Não sei o que pode ser….
User Function gdanfe()
Local aArea := GetArea()
Local nRegs1 := 0
Local cQuery := “”
Local aItens := {}
If AskMe() //função que faz as perguntas
cQuery := “select F2_DOC, F2_SERIE, F2_CLIENTE ”
cQuery += ” from ” +RetSqlName(“SF2″)
cQuery += ” where F2_CLIENTE between ‘”+ AllTrim(MV_PAR02) +”‘ AND ‘”+ AllTrim(MV_PAR03) +”‘”
cQuery += ” and F2_EMISSAO between ‘”+ DTOS(MV_PAR04) +”‘ AND ‘”+ DTOS(MV_PAR05) +”‘”
cQuery += ” and F2_FILIAL ='” +xFilial(“SF2”)+ “‘ ”
cQuery += ” and R_E_C_D_E_L_=0 ”
cQuery := ChangeQuery(cQuery)
TCQUERY cQuery New Alias “QRY”
Count To nRegs1
dbSelectArea(“QRY”)
QRY->(dbGoTop())
If nRegs1 > 0
While ! QRY->(EoF())
aAdd(aItens,{AllTrim(QRY->F2_DOC),AllTrim(QRY->F2_SERIE),AllTrim(MV_PAR01),AllTrim(QRY->F2_CLIENTE) })
QRY->(DbSkip())
EndDo
Else
MsgInfo(“Notas não encontradas!”,”Observação!”)
EndIf
EndIf
If len(aItens) > 0
xPrinD(aItens)
aItens := {}
EndIf
If Select(“QRY”) > 0
QRY->(dbCloseArea())
EndIf
RestArea(aArea)
Return
Static Function xPrinD(aPar)
Local I := 0
Local cDir := ” ”
For I := 1 To Len(aPar)
u_zGerDanfe(cValToChar(aPar[I][1]),cValToChar(aPar[I][2]),cValToChar(aPar[I][3]),cValToChar(aPar[I][4]))
cDir := cValToChar(aPar[1][3])
Next
MsgInfo(“Notas salvas com sucesso, salvas em:”+cDir,”Observação!”)
Return
Pessoal. Quem tiver apresentando problema reportado acima. Pode ser o parâmetro MV_PAR07 e MV_PAR08 que está preenchido no seu perfil. coloquei a data vazia e deu tudo certo.
MV_PAR01 := PadR(cNota, nTamNota) //Nota Inicial
MV_PAR02 := PadR(cNota, nTamNota) //Nota Final
MV_PAR03 := PadR(cSerie, nTamSerie) //Série da Nota
MV_PAR04 := 2 //NF de Saida
MV_PAR05 := 2 //Frente e Verso = Sim
MV_PAR06 := 2 //DANFE simplificado = Nao
MV_PAR07 := CTOD(” / / “)
MV_PAR08 := CTOD(” / / “)
Opa, obrigado pelo comentário Elson.
Com certeza vai ajudar.
Grande abraço.
Francisco c Dantas, você conseguiu imprimir o DANFE via schedule ? poderia me chamar no skype?: gildesiocp. Obrigado
Amigo DAN_ATILIO,
Só para sinalizar, a classe FWMSPrinter não funciona com gravação de arquivos em pasta que não tenha uma letra (C:\, F:\ etc.)
Exemplo:
cArquivo:= “Meu_Arquivo.PDF”
oDanfe := FWMSPrinter():New(cArquivo, IMP_PDF, .F., ”, .T., .F., , , .T., .T., , .F.)
oDanfe:cPathPDF := “\x_relatorios\”
Dá um erro que precisa ter uma Letra de Drive.
Eu não consegui gerar a DANFE em PDF via schedule, por essa razão.
ABs.
Entendi Francisco.
Obrigado pelo comentário.
Olá pessoal. Interessante seu comentário, Francisco. Vou tentar essa solução. Obrigado.
Bom dia to usando SIGAMDI
Boa tarde! Isso funciona sem que a nota seja transmitida ?
Boa tarde.
Não testei. Como a base, ele chama rotinas internas da TOTVS, acho que só realizando testes mesmo.
Olá, muito boa essa rotina.. mas estou com um problema, o XML que é baixado, parece não possuir a tag xMotivo, possuo uma integração com um sistema de geração de guias e estão pedindo o XML com esta tag, como posso extrair este XML ? pode me dar alguma dica.
Obrigado.
Boa tarde Julio.
Obrigado pelo feedback. Bom, essa rotina utiliza funções padrões, então o ideal é você abrir o Protheus, ir em Faturamento, abrir o Nfe Sefaz, clicar em Outras Ações > Monitor, digitar um número de uma NF.
Depois clique em Schema, e veja se no XML tem o conteúdo, se não tiver, ai você precisar o motivo de não estar gerando essa tag internamente no seu ambiente.
Olá. Infelizmente nada do que façamos resolve o problema do arquivo com 1k. Mas agradeço por disponibilizar a rotina.
Eu que agradeço pelo feedback Fernando.
Caso queira, entre em contato conosco por e-Mail para que assim possamos lhe orientar e ajudar.
Abraços.
Muito boa tarde!
E pra gerar somente o Pdf da Danfe em uma pasta? Eu ignoro a função zSpedXML ? Ou mesmo assim irei precisar dela ?
Bom dia Lucas, tudo joia?
Sim, basta você ignorar a que gera o XML.
Muito Obrigado!!!
Tenha uma ótima semana.
Opa, eu que agradeço pelo comentário.
Abraços.
Muito obrigado!
Me ajudou muito esse Update de 2022, estava com esse problema e os dois parâmetros de Data corrigiram
Tenha uma ótima semana.
Opa, nós que agradecemos pelo comentário Eriberto.
Grande abraço.
Essa atualização de 2022 me ajudou muito e sempre recomendo seu site quando alguém me pergunta onde aprender ADVPL.
Muito obrigado, seus conteúdos ajudam demais.
Boa tarde João, tudo joia?
Opa, obrigado pelo carinho e feedback. É muita bondade e generosidade sua.
Um forte abraço.
Oi boa tarde, o meu ta gerando a danfe.rel e não pdf …. o que pode ser ?
Boa noite José, tudo joia?
Você precisa baixar (ou atualizar) o printer.exe (dentro da sua pasta SmartClient ou dentro da sua pasta AppServer se for rodar via Job / WS).
Segue um link sobre o TOTVS Printer (printer.exe): https://terminaldeinformacao.com/2021/03/17/o-que-e-e-para-que-serve-o-totvs-printer-no-protheus/
Abraços.
Bom dia, tudo bem ?
Como faço pra gerar o pdf dentro de uma pasta da protheus_data ?
Boa tarde Cesar, tudo joia graças a Deus e você?
Opa, recentemente nos perguntaram sobre isso no grupo do WhatsApp, segue a resposta que demos na ocasião:
[…]
Para gerar então a DANFE via WebService ou um Scheduler, algumas mudanças precisam ser feitas no zGerDanfe, sendo:
a. Você precisa ter o printer.exe dentro da pasta do appserver em questão
b. A cPasta tem que apontar para um diretório dentro da Protheus Data, exemplo: cPasta := “\x_sua_pasta\”
c. O atributo lServer tem que ser verdadeiro, exemplo: oDanfe:lServer := .T.
Com isso, ao acionar o fonte na sua customização, ele vai gerar o arquivo dentro da Protheus Data, ai você pode disparar por email o pdf ou retornar ele em um WebService.
[…]
Um grande abraço.
Eu queria contrubuir , porque apanhei bastante para gerar o PDF no Protheus_data. Segue a solução :
cPasta := “\pdfs\” // diretorio destino
oDanfe := FWMSPrinter():New(cArquivo,6,.T., cPasta,.T.)
oDanfe:cPathPDF:=cPasta
oDanfe:SetViewPDF(.F.)
//Propriedades da DANFE
oDanfe:SetResolution(78)
oDanfe:SetPortrait()
oDanfe:SetPaperSize(DMPAPER_A4)
oDanfe:SetMargin(60, 60, 60, 60)
Bom dia Marcelo, tudo joia?
Opa, obrigado pelo comentário e contribuição, será de extrema valia.
Um grande abraço.