Simplificando fontes - hbnfe (Harbour -w3 -es2)

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
sygecom
Administrador
Administrador
Mensagens: 7131
Registrado em: 21 Jul 2006 10:12
Localização: Alvorada-RS
Contato:

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por sygecom »

José,
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.
Leonardo Machado
xHarbour.org + Hwgui + PostgreSql
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Tive uma idéia de como explicar o porquê:

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 )
Olhando bem o fonte acima. Pra que gravar o 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 )
Novamente. Pra que gravar o 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 )
Isso resume bem o que pode ser alterado.
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.
José M. C. Quintas
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/
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por asimoes »

Quintas,

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
►Harbour 3.x | Minigui xx-x | HwGui◄
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)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Atenção na mensagem:

Código: Selecionar todos

DEMO.PRG(31) Warning W0032 Variable 'NPOS' is assigned but not used in function
'MAIN(23)'
Até mostrei um exemplo desse tipo durante o post.
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
Não precisa atribuir zero na variável, porque já atribui 5 na linha de baixo.

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.
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

É difícil simplificar sem usar alguma coisa avançada.
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
O que seriam estas variáveis:

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 invés de copiar todo fonte para cada processo, mais fácil usar essa cláusula INHERIT, de herança.
Ao fazer isso, todas essas variáveis, e até métodos, serão automaticamente inclusos em cada processo.
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Outra parte, que vai fazer o oposto: multiplicar métodos:

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.
José M. C. Quintas
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/
Avatar do usuário
dbsh
Usuário Nível 3
Usuário Nível 3
Mensagens: 128
Registrado em: 14 Jul 2004 14:19
Localização: ES

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por dbsh »

Excelente sua explicação, parabéns.

para quem não utiliza ainda, e tiver dificuldade, poderá usar:

coloque no arquivo .HBP
afetara todos PRG

Código: Selecionar todos

-w3
-es2
muda somente no PRG
sem precisar mudar no .HBP

Código: Selecionar todos

#pragma /w2  //de 0 a 3
#pragma /es2  //de 0 a 2
010011110010000001110011011101010110001101100101011100110111001101101111001000001110100100100000011000110110111101101110011100110111010001110010011101011110110101100100011011110010000001100001001000000110111001101111011010010111010001100101
01001101011000010111001001100011011011110111001100100000010000010110111001110100011011110110111001101001011011110010000001000100011001010010000001000010011011110110111001101001
0101010001100101011011000011101000100000001010000011001000110111001010010011100100101101001110010011100000110100001100110010110100110101001100100011100100110000
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por asimoes »

Quintas,

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
►Harbour 3.x | Minigui xx-x | HwGui◄
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)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Só agora vi sua mensagem.

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
Vantagens:
- 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.
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Voltando à hbnfe:

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 )
Pra usar, só olhar acima, a definição do método.
O nome da classe é SpedSefazClass.

Então:

Código: Selecionar todos

oClasse := SpedSefazClass():New()
oClasse:CteConsulta( "351510.....", "certificado", "1" )
? oClasse:cXmlResposta
Só isso mesmo, e ainda dá pra simplificar mais.
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.
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Vamos à minha classe novamente...

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 ""
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

2) Próximo passo é enviar o XML pra Fazenda

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 )
Pode ser configurada UF, certificado, ambiente na classe principal, ou usar o método passando como parâmetro.

Código: Selecionar todos

oSefaz := SpedSefazClass():New()
oSefaz:NfeLoteEnvia( cXml, "1", "SP", "nomecertificado", "1" )
Lote enviado.
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
- "preenche" as variáveis necessárias.
- 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
- Confirma se os parâmetros estão corretos
- 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
- Coloca na variável cXmlSoap o que vai ser usado pra comunicação, que é o texto do envelope contendo o XML dentro.

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
Ela pega toda informação que foi preenchida e usa pra fazer a comunicação.
A resposta da Sefaz fica em cXmlRetorno
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

3) Uma vez enviado o XML e recebido o retorno, nesse retorno contém o protocolo, que vai ser usado pra consulta.
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 )
manual disso?
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 repete tudo que foi mostrado para o método anterior.

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
José M. C. Quintas
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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por JoséQuintas »

Quer trabalhar com TXT?
Isso não altera a comunicação com Sefaz, que obrigatoriamente é por XML.

Código: Selecionar todos

cXMl := ConverteTxtXml( cTxt )
Quer retorno em HASH?
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
É todo mundo usando a mesma classe principal, mesmo que um trabalhe diferente do outro.
É 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.
José M. C. Quintas
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/
aedurocha
Usuário Nível 1
Usuário Nível 1
Mensagens: 22
Registrado em: 31 Ago 2011 20:28
Localização: Iguatu-Ceara

Simplificando fontes - hbnfe (Harbour -w3 -es2)

Mensagem por aedurocha »

Olá José Quitas

A função ConverteTxtXml() faz parte da sefazclasse ou do hbnfe? e onde está disponibilizado os fonte desta função?

Eduardo Rocha
Responder