Simplificando fontes - hbnfe (Harbour -w3 -es2)
Moderador: Moderadores
- sygecom
- Administrador

- Mensagens: 7131
- Registrado em: 21 Jul 2006 10:12
- Localização: Alvorada-RS
- Contato:
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Muito bom, acredito que exemplos de uso dessa nova forma ajudaria muito os usuários a entender como aplicar na pratica, mais uma vez parabéns pelo ótimo trabalho.
xHarbour.org + Hwgui + PostgreSql
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Tem a classe hbnfe. Ao usar a classe no aplicativo temos duas variáveis (entre outras): XmlEnvio, XmlResposta (não exatamente esses nomes).
Elas já existem na classe e passam a estar disponíveis no aplicativo ao usar a classe.
Até aí, ok, normal.
Como é colocado o texto do xml de envio nessa variável XmlEnvio?
Código: Selecionar todos
Xml := "texto"
MemoWrit( arquivo, Xml )
XmlEnvio := MemoRead( arquivo )
Não basta colocar o texto direto na variável XmlEnvio?
E o retorno?
Código: Selecionar todos
XmlRetorno := "webservice"
MemoWrit( arquivo, XmlRetorno )
Xml := MemoRead( arquivo )
Não basta pegar direto o conteúdo de XmlRetorno?
Isso representa exatamente a hbnfe hoje.
Toda aquela configuração de pastas, e leitura/gravação de pastas, não é necessária.
Ao gerar o EXE contendo aplicativo + hbnfe, tudo vira um único aplicativo.
Não há porque usar arquivos pro aplicativo conversar com ele mesmo.
E finalmente, dá pra reduzir mais um pouco.
Já que é enviar um arquivo e receber outro, então:
Código: Selecionar todos
XmlRetorno := Processo( XmlEnvio )
E o que sobra?
Falta conhecer qual é o certificado, qual é a UF, qual é o ambiente, etc, dependendo de qual for o processo.
Então essa seria a parte central da hbnfe, comum em qualquer que seja o processo.
E eliminando a parte de pastas dos fontes, o que deixa mais simples pra entender/usar.
Outra idéia durante este post:
Começar a hbnfe compatível com ACBR, FAZENDO USO do ACBR.
Vai começar com tudo funcionando, sem nenhuma rotina própria, usando ACBR.
A partir daí, ir incluindo as rotinas próprias e ir substituindo o uso, até eliminar de vez o ACBR.
Se acontecer de funcionar numa UF e em outra não, a alternativa do ACBR seria usada até que seja resolvido.
Pelo menos ninguém fugiria da hbnfe, apenas usaria uma alternativa existente.
Por enquanto são só idéias.
A primeira parte, sem arquivo, eu já usava na minha classe, então já está confirmado que funciona.
Acho que eu tenho uma situação diferente:
Tenho cliente que pode emitir NFE mesmo sem internet, tem o formulário de segurança que permite isso, pode emitir NFE SEM AUTORIZAÇÃO, e transmitir depois.
Em 2008 esta era a única opção de contingência disponível, ainda é válida, e quem fez formulário depois de 7 anos ainda não usou nem 10% deles, vai continuar com isso disponível muitos anos ainda.
Tem que pensar neste caso também, que foge da regra geral, assim como outras contingências.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Uma coisa curiosa que eu estou verificando, estou testando a tolerância zero com
-w3
-es2
ambos informados no hbmk.hbm
Deu um monte warning e não gerou o executável.
Fui acertando, declarando as variáveis locais e ficou uma sem explicação
A variável é nPos
Declarei assim: LOCAL nPos e mesmo assim tenho essa mensagem do hbmk2
DEMO.PRG(31) Warning W0032 Variable 'NPOS' is assigned but not used in function
'MAIN(23)'
A variável é atribuida a um achoice
nPos:=Achoice( 09,31,18,73,aVetArqTxt,.t.,"" )
Declarei a variável como memvar nPos, ai compilou sem erro
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Código: Selecionar todos
DEMO.PRG(31) Warning W0032 Variable 'NPOS' is assigned but not used in function
'MAIN(23)'
Confunde um pouco ter dois números de linha, mas o mais importante é o segundo número.
Dentro do fonte DEMO.PRG
Na linha 23 da função Main, NPOS recebe um valor, que não serve pra nada e poderia ser retirado.
A conclusão disso foi quando chegou na linha 31.
Por exemplo:
Código: Selecionar todos
LOCAL nPos := 0
nPos := 5
O compilador só consegue chegar a essa conclusão depois.
Por isso aparecem dois números de linha na mensagem de erro: o primeiro é quando ele chegou a essa conclusão, e o segundo é onde ele considera errado.
Ou se é PRIVATE, o que não seria bom.
Atribui o valor e não usa na função, mas usa em uma sub-rotina.
Código: Selecionar todos
nOpcao := Achoice( ... )
Rotina()
RETURN
FUNCTION Rotina()
IF nOpcao == 1
...
ENDIF
MEMVAR para o compilador significa que é alguma coisa que pode estar em uso em algum lugar.
O compilador considera que você informou isso, e não faz checagem dessa variável.
Se for igual acima, o melhor seria usar Rotina( nOpcao )
Tanto o Main() quanto Rotina() teriam sua própria variável local.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Há variáveis comuns em todos os processos, e facilita tudo se padronizar isso.
Código: Selecionar todos
CREATE CLASS hbNFeSped
VAR cCertificadoCN
VAR cUFWS
VAR cVersaoDados
VAR cAmbiente
VAR cUF
VAR cXml
VAR cXmlRetorno
VAR cXmlEnvelope
VAR cUrlWs
VAR cSoapAction
VAR cServico
VAR lOk
VAR ohbNFe
ENDCLASS
cCertificadoCN = CN do certificado
cUFWS = UF que será usada para comunicação
cVersaoDados = versão dos dados, vai no XML de comunicação
cAmbiente = ambiente produção, homologação, ou contingência
cUF = UF da nota
cXml = XML do documento
cXmlEnvelope = XML já com envelope pra comunicação com Sefaz
cUrlWs = endereço para comunicação com Sefaz
cSoapAction = operação que está sendo solicitada na Sefaz
cServico = serviço que está sendo solicitado na Sefaz
cXmlRetorno = resposta da Sefaz
lOk = indicativo se tudo deu certo
ohbNFe = pra ficar fácil transferir configuração a partir da classe hbnfe
Como todos precisam disso, podemos copiar esse mesmo fonte acima em tudo que é processo.
Mas o mais prático é usar herança.
Código: Selecionar todos
CREATE CLASS algumaclasse INHERIT hbNFeSped
Ao fazer isso, todas essas variáveis, e até métodos, serão automaticamente inclusos em cada processo.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Atualmente, GetUrlWs() está em hbnfe, com tudo que é endereço possível.
Acho melhor criar um método desses em cada processo.
Apesar de formato idêntico, o conteúdo vai ser diferente.
Motivo simples:
Hoje tem lá tudo que é endereço de tudo que é processo na classe hbnfe.
Por exemplo, uns 40 endereços de consultar status, dentre outros.
Mas aonde interessa o endereço de consultar status? só no processo de consultar status.
Então acho melhor criar uma GetUrlWs() no processo de consultar status com esses endereços de consultar status.
O lado bom é que cada fonte de cada processo vai ter o que pertence a ele.
Apareceu processo novo, só acrescentar os endereços no próprio fonte do processo.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Simplificando fontes - hbnfe (Harbour -w3 -es2)
para quem não utiliza ainda, e tiver dificuldade, poderá usar:
coloque no arquivo .HBP
afetara todos PRG
Código: Selecionar todos
-w3
-es2
sem precisar mudar no .HBP
Código: Selecionar todos
#pragma /w2 //de 0 a 3
#pragma /es2 //de 0 a 2
01001101011000010111001001100011011011110111001100100000010000010110111001110100011011110110111001101001011011110010000001000100011001010010000001000010011011110110111001101001
0101010001100101011011000011101000100000001010000011001000110111001010010011100100101101001110010011100000110100001100110010110100110101001100100011100100110000
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Deu PFDATA.PRG(85) Warning W0001 Ambiguous reference 'NUMLAN' no INDEX
INDEX ON STRZERO(NUMLAN,4) TAG LDR002
Só resolve colocando o nome da tabela na frente do campo campo->numlan
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Na indexação o melhor é indicar que trata-se de campo de arquivo: field->NumLan
Assim não tem problema com alias.
Sobre o #pragma, usava ao contrário:
Sempre fixo no hbp com -w3 -es2
E nos fontes precisando de ajuste
Código: Selecionar todos
#pragma -w0
#pragma -es0
- fica identificado que fontes falta mexer
- Tudo que fizer novo, já vai ser forçado a usar -w3 -es2
-w0 -es0 ou o maior nível que puder usar.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Por mais que eu queira fazer diferente, acabo sempre chegando à minha classe.
Código: Selecionar todos
METHOD CTeConsulta( cChave, cCertificado, cAmbiente )
METHOD NFeConsulta( cChave, cCertificado, cAmbiente )
METHOD MDFeConsulta( cChave, cCertificado, cAmbiente )
O nome da classe é SpedSefazClass.
Então:
Código: Selecionar todos
oClasse := SpedSefazClass():New()
oClasse:CteConsulta( "351510.....", "certificado", "1" )
? oClasse:cXmlResposta
A chave de acesso tem toda informação que precisa, então não precisa mais nada.
Por exemplo, a acima começando com 35, significa que é de São Paulo, então nem precisa configurar pra SP, porque a própria classe já faz.
Sobre o retorno:
É exatamente o retorno da Fazenda, sem inventar nada adicional.
E se é o retorno da Fazenda, qualquer biblioteca/DLL/etc. que seja utilizada vai trabalhar com esse retorno.
Não tem nada mais padrão que isso.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
1) Primeira coisa é o XML da nota, o aplicativo precisa gerar o XML.
as variáveis da classe, podem servir pra configurar, caso faça processos em sequência.
Código: Selecionar todos
CREATE CLASS SefazClass
VAR cAmbiente INIT WSPRODUCAO
VAR cVersao INIT "3.10" // Versão NFE
VAR cScan INIT "N"
VAR cUF INIT "SP"
VAR cCertificado INIT ""
VAR cXmlDados INIT ""
VAR cXmlRetorno INIT "Erro Desconhecido"
//---- Uso interno ----
VAR cVersaoXml INIT ""
VAR cServico INIT ""
VAR cSoapAction INIT ""
VAR cWebService INIT ""
VAR cXmlSoap INIT ""
VAR lIsDebugMode INIT .F.
//--- Uso em processo ---
VAR cProjeto INIT WSPROJETONFE
VAR cXmlRecibo INIT ""
VAR cXmlProtocolo INIT ""
VAR cXmlFinal INIT ""
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
No envio a(s) NFe(s) fica(m) dentro de um lote, e o lote é que é enviado
Código: Selecionar todos
METHOD NFeLoteEnvia( cXml, cLote, cUF, cCertificado, cAmbiente )
Código: Selecionar todos
oSefaz := SpedSefazClass():New()
oSefaz:NfeLoteEnvia( cXml, "1", "SP", "nomecertificado", "1" )
A resposta está em oSefaz:cXmlRetorno
O que esse método faz, só seguir o fonte:
Código: Selecionar todos
METHOD NFeLoteEnvia( cXml, cLote, cUF, cCertificado, cAmbiente ) CLASS SefazClass
cCertificado := iif( cCertificado == NIL, ::cCertificado, cCertificado )
cAmbiente := iif( cAmbiente == NIL, ::cAmbiente, cAmbiente )
cUF := iif( cUF == NIL, ::cUF, cUF )
::cXmlDados := ""
IF ::cVersao == "2.00"
::cVersaoXml := "2.00"
::cServico := "http://www.portalfiscal.inf.br/nfe/wsdl/NfeRecepcao2"
::cSoapAction := "nfeRecepcaoLote2"
::cWebService := ::GetWebService( cUF, WSNFERECEPCAO, cAmbiente, WSPROJETONFE )
ELSE
::cVersaoXml := "3.10"
::cServico := "http://www.portalfiscal.inf.br/nfe/wsdl/NfeAutorizacao"
::cSoapAction := "NfeAutorizacao"
::cWebService := ::GetWebService( cUF, WSNFEAUTORIZACAO, cAmbiente, WSPROJETONFE )
ENDIF
::cXmlDados += [<enviNFe versao="] + ::cVersaoXml + [" xmlns="http://www.portalfiscal.inf.br/nfe">]
// FOR nCont = 1 TO Len( Lotes )
::cXmlDados += XmlTag( "idLote", cLote )
::cXmlDados += cXml
// NEXT
::cXmlDados += [</enviNFe>]
::XmlSoapPost( cUF, cCertificado, WSPROJETONFE )
::cXmlRecibo := ::cXmlRetorno
RETURN ::cXmlRetorno
- chama ::GetWebService() pra obter o endereço pra onde vai ser enviado o XML
- chama XmlSoapPost() pra enviar.
GetWebService de acordo com o que está sendo feito, escolhe o endereço
XmlSoapPost()
Código: Selecionar todos
METHOD XmlSoapPost( cUF, cCertificado, cProjeto ) CLASS SefazClass
cCertificado := iif( cCertificado == NIL, ::cCertificado, cCertificado )
cUF := iif( cUF == NIL, ::cUF, cUF )
cProjeto := iif( cProjeto == NIL, ::cProjeto, cProjeto )
DO CASE
CASE Empty( ::cWebService )
::cXmlRetorno := "Erro SOAP: Não há endereço de webservice"
RETURN NIL
CASE Empty( ::cServico )
::cXmlRetorno := "Erro SOAP: Não há nome do serviço"
RETURN NIL
CASE Empty( ::cSoapAction )
::cXmlRetorno := "Erro SOAP: Não há endereço de SOAP Action"
RETURN NIL
//CASE Empty( ::cVersaoXml )
// ::cXmlRetorno := "Erro SOAP: Não há número de versão"
// RETURN NIL
ENDCASE
//IF Empty( cUF )
// ::cXmlRetorno := "Erro SOAP: Não há sigla de UF"
// RETURN NIL
//ENDIF
::XmlSoapEnvelope( cUF, cProjeto )
::MicrosoftXmlSoapPost()
IF Upper( Left( ::cXmlRetorno, 4 ) ) == "ERRO"
RETURN NIL
ENDIF
IF "<soap:Body>" $ ::cXmlRetorno .AND. "</soap:Body>" $ ::cXmlRetorno
::cXmlRetorno := XmlNode( ::cXmlRetorno, "soap:Body" )
ELSEIF "<soapenv:Body>" $ ::cXmlRetorno .AND. "</soapenv:Body>" $ ::cXmlRetorno
::cXmlRetorno := XmlNode( ::cXmlRetorno, "soapenv:Body" )
ELSE
::cXmlRetorno := "Erro SOAP: XML retorno não está no padrão " + ::cXmlRetorno
ENDIF
RETURN NIL
- Chama XmlSoapEnvelope() pra criar o envelope
- Chama MicrosoftXmlSoapPost() pra fazer a transmissão
XmlSoapPost()
Código: Selecionar todos
METHOD XmlSoapEnvelope( cUF, cProjeto ) CLASS SefazClass
cUF := iif( cUF == NIL, ::cUF, cUF )
cProjeto := iif( cProjeto == NIL, ::cProjeto, cProjeto )
::cXmlSoap := ""
::cXmlSoap += [<?xml version="1.0" encoding="utf-8"?>] // UTF-8
::cXmlSoap += [<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ]
::cXmlSoap += [xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">]
IF ::cSoapAction != "nfeDistDFeInteresse"
::cXmlSoap += [<soap12:Header>]
::cXmlSoap += [<] + cProjeto + [CabecMsg xmlns="] + ::cServico + [">]
::cXmlSoap += [<cUF>] + UFCodigo( cUF ) + [</cUF>]
::cXmlSoap += [<versaoDados>] + ::cVersaoXml + [</versaoDados>]
::cXmlSoap += [</] + cProjeto + [CabecMsg>]
::cXmlSoap += [</soap12:Header>]
ENDIF
::cXmlSoap += [<soap12:Body>]
IF ::cSoapAction == "nfeDistDFeInteresse"
::cXmlSoap += [<nfeDistDFeInteresse xmlns="] + ::cServico + [">]
::cXmlSoap += [<] + cProjeto + [DadosMsg>]
ELSE
::cXmlSoap += [<] + cProjeto + [DadosMsg xmlns="] + ::cServico + [">]
ENDIF
::cXmlSoap += ::cXmlDados
::cXmlSoap += [</] + cProjeto + [DadosMsg>]
IF ::cSoapAction == "nfeDistDFeInteresse"
::cXmlSoap += [</nfeDistDFeInteresse>]
ENDIF
::cXmlSoap += [</soap12:Body>]
::cXmlSoap += [</soap12:Envelope>]
RETURN ::cXmlSoap
E finalmente a comunicação MicrosoftXmlSoapPost()
Código: Selecionar todos
METHOD MicrosoftXmlSoapPost() CLASS SefazClass
LOCAL oServer, nCont, cRetorno := "Erro: No componente para SOAP"
LOCAL cSoapAction
//IF ::cSoapAction == "nfeDistDFeInteresse" .OR. ::cSoapAction == "nfeConsultaNFDest"
//cSoapAction := ::cServico + "/" + ::cSoapAction
//ELSE
cSoapAction := ::cSoapAction
//ENDIF
BEGIN SEQUENCE WITH { | e | Break( e ) }
oServer := win_OleCreateObject( "MSXML2.ServerXMLHTTP" )
IF ::cCertificado != NIL
//oServer:setOption( 2, oServer:getOption( 2 ) - SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID )
oServer:setOption( 3, "CURRENT_USER\MY\" + ::cCertificado )
ENDIF
oServer:Open( "POST", ::cWebService, .F. )
oServer:SetRequestHeader( "SOAPAction", cSoapAction )
oServer:SetRequestHeader( "Content-Type", "application/soap+xml; charset=utf-8" )
oServer:Send( ::cXmlSoap )
oServer:WaitForResponse( 500 )
cRetorno := oServer:ResponseBody
ENDSEQUENCE
IF ::lIsDebugMode
hb_MemoWrit( "xml1-soap.xml", ::cXmlSoap )
hb_MemoWrit( "xml2-action.xml", cSoapAction )
hb_MemoWrit( "xml3-url.xml", ::cWebService )
hb_MemoWrit( "xml4-retorno.xml", cRetorno )
ENDIF
IF ValType( cRetorno ) == "C"
::cXmlRetorno := cRetorno
ELSEIF cRetorno == NIL
::cXmlRetorno := "Erro SOAP: na comunicação"
ELSE
::cXmlRetorno := ""
FOR nCont = 1 TO Len( cRetorno )
::cXmlRetorno += Chr( cRetorno[ nCont ] )
NEXT
ENDIF
// IF .NOT. "<cStat>" $ cRetorno
// cRetorno := "<cStat>ERRO NO RETORNO</cStat>" + cRetorno
// ENDIF
RETURN NIL
A resposta da Sefaz fica em cXmlRetorno
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Então precisa consultar esse recibo, pra ver o que aconteceu no processamento da Sefaz, se deu tudo certo.
Mesma coisa de sempre: olhar o nome e os parâmetros pra ver o que precisa.
Código: Selecionar todos
METHOD NFeConsultaRecibo( cRecibo, cUF, cCertificado, cAmbiente )
recibo = número do recibo que veio no retorno anterior
UF = UF
certificado = nome do certificado
ambiente = ambiente "1" ou "2", produção ou homologação
Código: Selecionar todos
oSefaz := SefazClass():New()
oSefaz:NFeConsultaRecibo( "123", "SP", "nome do certificado", "1" )
? oSefaz:cXmlRetorno
Se tudo ok, cXmlRetorno contém o protocolo.
Só juntar a nota com o protocolo e temos a nota autorizada.
Nota: esqueci de mencionar que o xml da nota precisa ser assinado antes de enviar o lote.
Como é o xml da nota autorizada, que é enviado para clientes:
- o início do xml procNFE
- o xml da nota com assinatura, o mesmo que foi enviado no envialote
- o xml de retorno que foi recebido no consultarecibo
- o final do xml procNFE.
Supondo que fosse tudo às mil maravilhas, e pra não repetir parâmetros, uma emissão de notas poderia ser assim:
oSefaz := SefazClass():New()
oSefaz:cUF := "SP"
oSefaz:cAmbiente := "1"
oSefaz:cCertificado := "nome do certificado"
oSefaz:NfeLoteEnvia( cXml )
// precisa separar o número do recibo que veio em cXmlRetorno
oSefaz:NfeConsultaRecibo( cNumeroRecibo )
// Precisa verificar o status de resultado que veio em cXmlRetorno
IF cStatus == "101"
cXmlAutorizado := "ProcNfe....." + cXml + cProtocolo + "/procnfe"
ENDIF
[/code]
Resumindo é isso.
O que tem além disso:
- ao enviar o lote, verificar se retornou o recibo ok, ou se foi rejeitado
- usar esse número de recibo pra fazer a consulta da segunda etapa
- respeitar o intervalo de tempo permitido entre envio e consulta recibo
- verificar nessa segunda consulta, se retornou OK
- já aconteceu de retornar "em processamento", então tem que aguardar um pouco e consultar novamente.
- Se tudo ok, gerar o XML da nota autorizada (ou denegada).
Em caso de falha, uma segunda opção é consultar a nota pela chave de acesso, também retorna o protocolo, em um formato quase igual ao de consultar o recibo.
Se vai usar arquivo temporário pra salvar as etapas, ou MySQL, ou outra coisa, fica a critério de cada um.
A comunicação é sempre enviar um texto e receber outro. é formato xml mas não deixa de ser um texto.
Em caso de falha, é bom ver o texto de retorno.
Uma das opções é salvar arquivo temporário.
Não é obrigatório, mas por exemplo, como saber o número do recibo pra poder consultar? só se salvar isso em algum lugar, ou olhando o arquivo retornado no envio.
Pode ser interessante pra rastreamento salvar:
- O xml assinado
- O xml de retorno do envio do lote, porque nele consta o número do recibo e/ou a resposta sobre o envio do lote
- O xml de retorno do consultar recibo, porque ele contém o protocolo e/ou a resposta após análise da Sefaz
- O xml final, com certeza precisa salvar
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Simplificando fontes - hbnfe (Harbour -w3 -es2)
Isso não altera a comunicação com Sefaz, que obrigatoriamente é por XML.
Código: Selecionar todos
cXMl := ConverteTxtXml( cTxt )
Não precisa nem mexer na classe principal.
Código: Selecionar todos
CREATE CLASS SpedPorHash INHERIT SpedSefazClass
METHOD NFeLoteEnvia( cXml, cLote, cUF, cCertificado, cAmbiente )
END CLASS
METHOD NFeLoteEnvia( cXml, cLote, cUF, cCertificado, cAmbiente ) CLASS SpedPorHash
::SUPER:NFeLoteEnvia( cXml, cLote, cUF, cCertificado, cAmbiente )
oRetorno := Hash()
// grava em oRetorno
RETURN oRetorno
É aproveitar o trabalho de todos, pra todos.
Se optar por Hash, MySQL, INI, arquivo em disco, seja como for, a parte central é fixa, não tem porque fazer diferente.
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Simplificando fontes - hbnfe (Harbour -w3 -es2)
A função ConverteTxtXml() faz parte da sefazclasse ou do hbnfe? e onde está disponibilizado os fonte desta função?
Eduardo Rocha


