Usando classe para assinar nfse - São Paulo
Enviado: 21 Mar 2023 10:00
Mestre,
ShellExecute(0, [open], [AssinaRPS.EXE],,, 1)
este trecho o amigo Eduardo, fez esse executável em c# para assinar a tag assinatura, como não consegui nenhuma informação de como converter para harbour estou usando por eqto este executável externamente.
Já juntei um pouco conforme o código abaixo
ShellExecute(0, [open], [AssinaRPS.EXE],,, 1)
este trecho o amigo Eduardo, fez esse executável em c# para assinar a tag assinatura, como não consegui nenhuma informação de como converter para harbour estou usando por eqto este executável externamente.
Já juntei um pouco conforme o código abaixo
Código: Selecionar todos
#include "hbclass.ch"
*#define WS_NFE_STATUSSERVICO 17 /// não descobri onde usar
#define WS_CANCELAMENTONFE 1
#define WS_ENVIOLOTERPS 2
#define WS_ENVIORPS 3 /// acrescentei
#define WS_CONSULTARPS 4 /// acrescentei
#define WS_AMBIENTE_HOMOLOGACAO "2" /// sp, foz não tem mais o ambiente de homologação
#define WS_AMBIENTE_PRODUCAO "1"
#ifndef XML_UTF8
#define XML_UTF8 [<?xml version="1.0" encoding="UTF-8"?>]
#endif
CREATE CLASS NfseClasse //// mudei nome pois estava conflitando com a sefazclass
/* configuração */
VAR cAmbiente INIT WS_AMBIENTE_PRODUCAO
VAR cUF INIT "SP" // Modificada conforme método
VAR cCertificado INIT "" // Nome do certificado
VAR nTempoEspera INIT 7 // intervalo entre envia lote e consulta recibo
/* XMLs de cada etapa */
VAR cXmlDocumento INIT "" // O documento oficial, com ou sem assinatura, depende do documento
VAR cXmlEnvio INIT "" // usado pra criar/complementar XML do documento
VAR cXmlSoap INIT "" // XML completo enviado pra Sefaz, incluindo informações do envelope
VAR cXmlRetorno INIT "Erro Desconhecido" // Retorno do webservice e/ou rotina
VAR cXmlProtocolo INIT "" // XML protocolo (obtido no consulta recibo e/ou envio de outros docs)
VAR cXmlAutorizado INIT "" // XML autorizado, caso tudo ocorra sem problemas
VAR cStatus INIT Space(3) // Status obtido da resposta final da Fazenda
/* uso interno */
VAR cSoapService INIT "" // webservice Serviço
VAR cSoapAction INIT "" // webservice Action
VAR cSoapURL INIT "" // webservice Endereço
*** acrescentei
VAR lComUri INIT .F. // Não tem tag cUri
VAR cPassword INIT "" // Senha de arquivo PFX
VAR cMotivo INIT "" // Motivo constante no Recibo
VAR nCodigoMunicipio INIT 3550308 // São Paulo
METHOD EnvioLoteRPS( cXml, cCertificado, cAmbiente )
***** acrescentei
METHOD EnvioRPS( cXml, cCertificado, cAmbiente )
METHOD CancelamentoRPS( cXml, cCertificado, cAmbiente )
METHOD ConsultaRPS( cXml, cCertificado, cAmbiente )
/* Uso interno */
METHOD Setup( cCertificado, cAmbiente, nWsServico )
METHOD XmlSoapEnvelope()
METHOD XmlSoapPost()
METHOD MicrosoftXmlSoapPost()
***** acrescentei
METHOD AssinaXml(cXml)
METHOD Gera_Chave_SHA1(cString)
ENDCLASS
** alterei foz máximo 20 rps por lote
METHOD EnvioLoteRPS( cXml, cCertificado, cAmbiente ) CLASS NfseClasse
::Setup( cCertificado, cAmbiente, WS_ENVIOLOTERPS )
::cXmlEnvio := ::AssinaXml( cXml )
::cXmlEnvio := ::cXmlDocumento
::XmlSoapPost()
RETURN ::cXmlRetorno
** acrescentei
METHOD EnvioRPS( cXml, cCertificado, cAmbiente ) CLASS NfseClasse
::Setup( cCertificado, cAmbiente, WS_ENVIORPS )
::cXmlEnvio := ::AssinaXml( cXml )
::cXmlEnvio := ::cXmlDocumento
::XmlSoapPost()
RETURN ::cXmlRetorno
** acrescentei
METHOD CancelamentoRPS( cXml, cCertificado, cAmbiente ) CLASS NfseClasse
::Setup( cCertificado, cAmbiente, WS_CANCELAMENTONFE )
::cXmlEnvio := ::AssinaXml( cXml )
::cXmlEnvio := ::cXmlDocumento
::XmlSoapPost()
RETURN ::cXmlRetorno
** acrescentei
METHOD ConsultaRPS( cXml, cCertificado, cAmbiente ) CLASS NfseClasse
::Setup( cCertificado, cAmbiente, WS_CONSULTARPS )
::cXmlEnvio := ::AssinaXml( cXml )
::cXmlEnvio := ::cXmlDocumento
::XmlSoapPost()
RETURN ::cXmlRetorno
METHOD Setup( cCertificado, cAmbiente, nWsServico ) CLASS NfseClasse
LOCAL nPos, aSoapList
If ::nCodigoMunicipio == 3550308 // sp
aSoapList := { ;
{ WS_CANCELAMENTONFE, "CancelamentoNFe", "http://www.prefeitura.sp.gov.br/nfe/ws/cancelamentoNFe", "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx" }, ;
{ WS_ENVIOLOTERPS , "EnvioLoteRPS" , "http://www.prefeitura.sp.gov.br/nfe/ws/envioLoteRPS" , "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx" }, ;
{ WS_ENVIORPS , "EnvioRPS" , "http://www.prefeitura.sp.gov.br/nfe/ws/envioRPS" , "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx" }, ;
{ WS_CONSULTARPS , "ConsultaLote" , "http://www.prefeitura.sp.gov.br/nfe/ws/consultaLote" , "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx" } }
ElseIf ::nCodigoMunicipio == 4108304 // foz do iguaçu
aSoapList := { ;
{ WS_CANCELAMENTONFE, "CancelamentoNFSE" , "http://tempuri.org/CancelamentoNFSE" , "http://nfse.pmfi.pr.gov.br/nfsews/nfse.asmx" }, ;
{ WS_ENVIOLOTERPS , "EnviaLotesParaProcessamento", "http://tempuri.org/EnviaLotesParaProcessamento", "http://nfse.pmfi.pr.gov.br/nfsews/nfse.asmx" }, ;
{ WS_ENVIORPS , "RecebeLoteRPS" , "http://tempuri.org/RecebeLoteRPS" , "http://nfse.pmfi.pr.gov.br/nfsews/nfse.asmx" }, ;
{ WS_CONSULTARPS , "ConsultarLoteRPS" , "http://tempuri.org/ConsultarLoteRPS" , "http://nfse.pmfi.pr.gov.br/nfsews/nfse.asmx" } }
Endif
* sp e foz, apesar de ter endereço de homologação, estão desativados, conforme o suporte dos mesmos
::cCertificado := iif( cCertificado == Nil, ::cCertificado, cCertificado )
::cAmbiente := iif( cAmbiente == Nil, ::cAmbiente, cAmbiente )
IF nWsServico == Nil
RETURN Nil
ENDIF
IF ( nPos := hb_AScan( aSoapList, { | oElement | oElement[ 1 ] == nWsServico } ) ) != 0
::cSoapService := aSoapList[ nPos, 2 ]
::cSoapAction := aSoapList[ nPos, 3 ]
::cSoapURL := aSoapList[ nPos, 4 ]
ENDIF
RETURN Nil
METHOD XmlSoapPost() CLASS NfseClasse
DO CASE
CASE Empty( ::cSoapURL )
::cXmlRetorno := "Erro SOAP: Não há endereço de webservice"
RETURN Nil
CASE Empty( ::cSoapService )
::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
ENDCASE
::XmlSoapEnvelope()
::MicrosoftXmlSoapPost()
IF Upper( Left( ::cXmlRetorno, 4 ) ) == "ERRO"
RETURN Nil
ENDIF
RETURN Nil
METHOD XmlsoapEnvelope() CLASS NfseClasse
::cXmlsoap := XML_UTF8
::cXmlsoap += [<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ]
::cXmlsoap += [xmlns:xsd="http://www.w3.org/2001/XMLSchema" ]
::cXmlsoap += [xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">]
::cXmlSoap += [<soap12:Body>]
If ::nCodigoMunicipio == 3550308 // sp
::cXmlSoap += [<] + ::cSoapService + [Request xmlns="http://www.prefeitura.sp.gov.br/nfe">]
::cXmlSoap += [<VersaoSchema>1</VersaoSchema>]
::cXmlSoap += [<MensagemXML>]
::cXmlSoap += "<![CDATA[ " + ::cXmlEnvio + " ]]>"
::cXmlSoap += [</MensagemXML>]
::cXmlSoap += [</] + ::cSoapService + [Request>]
ElseIf ::nCodigoMunicipio == 4108304 // foz do iguaçu
::cXmlSoap += [<] + ::cSoapService + [ xmlns="http://tempuri.org/">]
::cXmlSoap += [<xml>] + ::cXmlEnvio + [</xml>]
::cXmlSoap += [</] + ::cSoapService + [>]
Endif
::cXmlSoap += [</soap12:Body>]
::cXmlSoap += [</soap12:Envelope>]
RETURN Nil
METHOD MicrosoftXmlSoapPost() CLASS NfseClasse
LOCAL oServer, nCont, cRetorno
LOCAL cSoapAction
cSoapAction := ::cSoapAction
BEGIN SEQUENCE WITH __BreakBlock()
::cXmlRetorno := "Erro: Criando objeto MSXML2.ServerXMLHTTP"
oServer := win_OleCreateObject( "MSXML2.ServerXMLHTTP" )
::cXmlRetorno := "Erro: No uso do objeto MSXML2.ServerXmlHTTP"
IF ::cCertificado != Nil
oServer:setOption( 3, "CURRENT_USER\MY\" + ::cCertificado )
ENDIF
::cXmlRetorno := "Erro: Na conexão com webservice " + ::cSoapURL
oServer:Open( "POST", ::cSoapURL, .F. )
oServer:SetRequestHeader( "SOAPAction", cSoapAction )
oServer:SetRequestHeader( "Content-Type", "application/soap+xml; charset=utf-8" )
oServer:Send( ::cXmlSoap )
oServer:WaitForResponse( 500 )
cRetorno := oServer:ResponseBody
IF ValType( cRetorno ) == "C"
::cXmlRetorno := cRetorno
ELSEIF cRetorno == Nil
::cXmlRetorno := "Erro: Sem retorno do webservice"
ELSE
::cXmlRetorno := ""
FOR nCont = 1 TO Len( cRetorno )
::cXmlRetorno += Chr( cRetorno[ nCont ] )
NEXT
ENDIF
ENDSEQUENCE
IF "<soap:Body>" $ ::cXmlRetorno .AND. "</soap:Body>" $ ::cXmlRetorno
::cXmlRetorno := XmlNode( ::cXmlRetorno, "soap:Body" ) // hb_UTF8ToStr()
ELSEIF "<soapenv:Body>" $ ::cXmlRetorno .AND. "</soapenv:Body>" $ ::cXmlRetorno
::cXmlRetorno := XmlNode( ::cXmlRetorno, "soapenv:Body" ) // hb_UTF8ToStr()
ELSE
::cXmlRetorno := "Erro SOAP: XML retorno não contém soapenv:Body " + ::cXmlRetorno
ENDIF
RETURN Nil
**************** acrescentei
METHOD AssinaXml(cXml) CLASS NfseClasse
::cXmlDocumento:= cXml
::cXmlRetorno := CapicomAssinaXml( @::cXmlDocumento, ::cCertificado,,::cPassword, ::lComUri )
IF ::cXmlRetorno != "OK"
::cStatus := "999"
::cMotivo := ::cXmlRetorno
::cXmlRetorno := [<erro text="] + "*erro* " + ::cXmlRetorno + ["</erro>]
ENDIF
RETURN ::cXmlRetorno
METHOD Gera_Chave_SHA1(cString) Class NfseClasse
Local nHandle:= Fcreate([StringParaAssinar.txt]), cRet:= []
* Fwrite(nHandle, ::ohbNFe:cSerialCert + hb_OsNewLine() + cString)
Fwrite(nHandle, Upper([4b8db3b9d22a50b5]) + hb_OsNewLine() + cString)
Fclose(nHandle)
ShellExecute(0, [open], [AssinaRPS.EXE],,, 1)
cRet:= Hb_Memoread([StringAssinada.txt])
cRet:= Strtran(cRet, CHR(13), [])
cRet:= Strtran(cRet, CHR(10), [])
Ferase([StringParaAssinar.txt])
Ferase([StringAssinada.txt])
Return(cRet)
********************* Retira Acentos e Letras de uma String ********************
Function fRetiraAcento(cStr)
Local aLetraCAc:= {[Á],[À],[Ä],[Ã],[Â],[É],[È],[Ë],[Ê],[&],[Í],[Ì],[Ï],[Î],[Ó],[Ò],[Ö],[Õ],[Ô],[Ú],[Ù],[Ü],[Û],[Ç],[Ñ],[Ý],[á],[à],[ä],[ã],[â],[é],[è],[ë],[ƒ],[ê],[í],[ì],[ï],[î],[ó],[ò],[ö],[õ],[ô],[ú],[ù],[ü],[û],[ç],[ñ],[ý],[ÿ],[º] ,[ª] ,[‡],[Æ],[¡],[£],[ÿ],[ ],[á],[ ] ,[ ],[ ],[‚],[ˆ],[“],[¢],[…],[°],[A³],[A§],[Au],[Ai],[A©],[Ao.]}
Local aLetraSAc:= {[A],[A],[A],[A],[A],[E],[E],[E],[E],[E],[I],[I],[I],[I],[O],[O],[O],[O],[O],[U],[U],[U],[U],[C],[N],[Y],[a],[a],[a],[a],[a],[e],[e],[e],[a],[e],[i],[i],[i],[i],[o],[o],[o],[o],[o],[u],[u],[u],[u],[c],[n],[y],[y],[o.],[a.],[c],[a],[i],[u],[a],[a],[a],[E ],[a],[ ],[e],[e],[o],[o],[a],[],[o],[c],[a],[a],[e],[u]}, i
hb_Default(@cStr, [])
For i:= 1 To Len(aLetraCAc)
cStr:= StrTran(cStr, aLetraCAc[i], aLetraSAc[i])
Next
Return (cStr)
********************* Fim da Função Retira Acentos e Letras de uma String ******