Clipper On Line • Ver Tópico - NFS-e PMSP

NFS-e PMSP

Projeto Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

 

NFS-e PMSP

Mensagempor JoséQuintas » 24 Ago 2017 20:12

Exe que Assina o RPS.


Mas porque precisou disso?
E a rotina de assinatura que está dentro do fonte?

Dá pra eliminar estas funções:

METHOD DataToYYYY_MM_DD( dDAT, lTIME ) CLASS NFSE
   LOCAL cRET := AllTrim( Str( Year( dDAT ) ) ) + '-' + StrZero( Month( dDAT ), 2 ) + '-' + StrZero( Day( dDAT ), 2 )
   IF lTIME = NIL
      lTIME := .F.
   ENDIF
   IF lTIME
      cRET += 'T' + Left( Time(), 8 )
   ENDIF
   RETURN( cRET )

METHOD DataToYYYYMMDD( dDAT ) CLASS NFSE
   LOCAL cRET := AllTrim( Str( Year( dDAT ) ) ) + StrZero( Month( dDAT ), 2 ) + StrZero( Day( dDAT ), 2 )
   RETURN( cRET )


Mais fácil usar isto:
? Transform( Dtos( dDat ), "@R 9999-99-99" ) + "T" + Left( Time(), 8 )
? Dtos( dDat )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor eduardomc00 » 25 Ago 2017 08:40

Bom dia amigos.
Como eu disse, o código está sujo e feio :D :D

hbnfe.ch

#define _RECEPCAO             1
#define _RETRECEPCAO          2
#define _CANCELAMENTO         3
#define _INUTILIZACAO         4
#define _CONSULTAPROTOCOLO    5
#define _STATUSSERVICO        6
#define _CONSULTACADASTRO     7
#define _RECEPCAODEEVENTO     8
#define _EVENTO               9
#define _CONSULTANFEDEST      10
#define _DOWNLOADNFE          11
#define _RECPEVENTO           12

#define _MSXML2_DOMDocument          'MSXML2.DOMDocument.5.0'
#define _MSXML2_MXDigitalSignature   'MSXML2.MXDigitalSignature.5.0'
#define _MSXML2_XMLSchemaCache       'MSXML2.XMLSchemaCache.5.0'
#define _MSXML2_ServerXMLHTTP        'MSXML2.ServerXMLHTTP.5.0'

#define _LOGO_ESQUERDA            1
#define _LOGO_DIREITA             2
#define _LOGO_EXPANDIDO           3
#define _LOGO_TOPO                4

#define HBNFE_MXML            1
#define HBNFE_CURL            2

#define HBNFE_EXIGIDA         .T.
#define HBNFE_NAOEXIGIDA      .F.

#define _CAPICOM_STORE_OPEN_READ_ONLY                 0           // Somente Smart Card em Modo de Leitura

#define _CAPICOM_MEMORY_STORE                         0
#define _CAPICOM_LOCAL_MACHINE_STORE                  1
#define _CAPICOM_CURRENT_USER_STORE                   2
#define _CAPICOM_ACTIVE_DIRECTORY_USER_STORE          3
#define _CAPICOM_SMART_CARD_USER_STORE                4

#define _CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED           2
#define _CAPICOM_CERTIFICATE_FIND_SHA1_HASH           0           // Retorna os Dados Criptografados com Hash SH1
#define _CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY   6
#define _CAPICOM_CERTIFICATE_FIND_TIME_VALID          9           // Retorna Certificados Válidos
#define _CAPICOM_CERTIFICATE_FIND_KEY_USAGE           12          // Retorna Certificados que contém dados.
#define _CAPICOM_DIGITAL_SIGNATURE_KEY_USAGE          0x00000080  // Permitir o uso da Chave Privada para assinatura Digital
#define _CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME 0           // Este atributo contém o tempo em que a assinatura foi criada.
#define _CAPICOM_INFO_SUBJECT_SIMPLE_NAME             0           // Retorna o nome de exibição do certificado.
#define _CAPICOM_ENCODE_BASE64                        0           // Os dados são guardados como uma string base64-codificado.
#define _CAPICOM_E_CANCELLED                          -2138568446 // A operação foi cancelada pelo usuário.
#define _CERT_KEY_SPEC_PROP_ID                        6
#define _CAPICOM_CERT_INFO_ISSUER_EMAIL_NAME          0
#define _SIG_KEYINFO                                  2
#include "wsoft.ch"

#xcommand EXECUTE ;
    FILE <executable> ;
    [ DEFAULT <default> ] ;
    WAIT ;
    [ WHILE <while> ] ;
    [ INTERVAL <msec> ] ;
=> ;
WaitRunTerm ( <executable> , <default> , 5 , <{while}> , <msec> )

#xcommand EXECUTE ;
    FILE <executable> ;
    [ DEFAULT <default> ] ;
    WAIT ;
    [ WHILE <while> ] ;
    [ INTERVAL <msec> ] ;
    MAXIMIZE ;
=> ;
WaitRunTerm ( <executable> , <default> , 3 , <{while}> , <msec> )

#xcommand EXECUTE ;
    FILE <executable> ;
    [ DEFAULT <default> ] ;
    WAIT ;
    [ WHILE <while> ] ;
    [ INTERVAL <msec> ] ;
    MINIMIZE ;
=> ;
WaitRunTerm ( <executable> , <default> , 6 , <{while}> , <msec> )

#xcommand EXECUTE ;
    FILE <executable> ;
    [ DEFAULT <default> ] ;
    WAIT ;
    [ WHILE <while> ] ;
    [ INTERVAL <msec> ] ;
    HIDE ;
=> ;
WaitRunTerm ( <executable> , <default> , 0 , <{while}> , <msec> )

#xcommand EXECUTE ;
    [ OPERATION <operation> ] ;
    FILE <file> ;
    [ PARAMETERS <parameters> ] ;
    [ DEFAULT <default> ] ;
=> ;
_Execute ( , <operation> , <file> , <parameters> , <default> , 5 )

#xcommand EXECUTE ;
    [ OPERATION <operation> ] ;
    FILE <file> ;
    [ PARAMETERS <parameters> ] ;
    [ DEFAULT <default> ] ;
    MAXIMIZE ;
=> ;
_Execute ( , <operation> , <file> , <parameters> , <default> , 3 )

#xcommand EXECUTE ;
    [ OPERATION <operation> ] ;
    FILE <file> ;
    [ PARAMETERS <parameters> ] ;
    [ DEFAULT <default> ] ;
    MINIMIZE ;
=> ;
_Execute ( , <operation> , <file> , <parameters> , <default> , 6 )

#xcommand EXECUTE ;
    [ OPERATION <operation> ] ;
    FILE <file> ;
    [ PARAMETERS <parameters> ] ;
    [ DEFAULT <default> ] ;
    HIDE ;
=> ;
_Execute ( , <operation> , <file> , <parameters> , <default> , 0 )
eduardomc00
Usuário Nível 1

Usuário Nível 1
 
Mensagens: 43
Data de registro: 07 Out 2014 18:29
Cidade/Estado: São Paulo
Curtiu: 3 vezes
Mens.Curtidas: 0 vez

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 10:50

Ok.

Esta parte é legal, descomplicando um pouco o METHOD de assinatura, que aparentemente não é usada, já que usa programa externo...

METHOD Assina_XML() CLASS NFSE

   LOCAL oDOMDoc, oXmldsig, oCert, oStoreMem, dsigKey, signedKey
   LOCAL aRETORNO := Hash()
   LOCAL cXML, cXMLSig
   LOCAL PosIni, PosFim, nP, nResult
   LOCAL nHandle

   aRETORNO[ 'STATUS' ] := .F.
   aRETORNO[ 'MSG' ] := ''

   IF ::Xml = NIL .OR. Empty( ::Xml )
      aRETORNO[ 'MSG' ] := 'Arquivo XML com o registro do cabeçalho e RPS não informado.'
   ENDIF
   cXML := MemoRead( ::Xml )
   FErase( ::Xml )

   cXML := StrTran( cXML, '<Signature></Signature>', '<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">' + ;
      '<SignedInfo>' + ;
      '<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />' + ;
      '<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />' + ;
      '<Reference URI="">' + ;
      '<Transforms>' + ;
      '<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />' + ;
      '<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />' + ;
      '</Transforms>' + ;
      '<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />' + ;
      '<DigestValue>' + ;
      '</DigestValue>' + ;
      '</Reference>' + ;
      '</SignedInfo>' + ;
      '<SignatureValue>' + ;
      '</SignatureValue>' + ;
      '<KeyInfo>' + ;
      '<X509Data>' + ;
      '<X509Certificate>' + ;
      '</X509Certificate>' + ;
      '</X509Data>' + ;
      '</KeyInfo>' + ;
      '</Signature>' )

// Inicializa o objeto do DOMDocument
   BEGIN SEQUENCE WITH __BreakBlock()
      oDOMDoc := win_oleCreateObject( _MSXML2_DOMDOCUMENT )
   RECOVER
      aRETORNO[ 'MSG' ] := 'Nao foi possível carregar ' + _MSXML2_DOMDOCUMENT
      RETURN aRETORNO
   ENDSEQUENCE
   oDOMDoc:async = .F.
   oDOMDoc:resolveExternals := .F.
   oDOMDoc:validateOnParse = .T.
   oDOMDoc:preserveWhiteSpace = .T.

// inicializa o objeto do MXDigitalSignature
   BEGIN SEQUENCE WITH __BreakBlock()
      oXmldsig := win_oleCreateObject( _MSXML2_MXDIGITALSIGNATURE )
   RECOVER
      aRETORNO[ 'MSG' ] := 'Nao foi possível carregar ' + _MSXML2_MXDIGITALSIGNATURE
      RETURN aRETORNO
   ENDSEQUENCE

   nHandle := FCreate( ::ohbNFe:pastaEnvRes + "\edunfs.xml" )
   FWrite( nHandle, cXML )
   FClose( nHandle )

// carrega o arquivo XML para o DOM
   oDOMDoc:LoadXML( cXML )
   IF oDOMDoc:parseError:errorCode <> 0
      aRETORNO[ 'MSG' ] := ' Assinar: Não foi possível carregar o documento pois ele não corresponde ao seu Schema' + hb_Eol() + ;
         ' Linha: '       + Str( oDOMDoc:parseError:line ) + hb_eol() + ;
         ' Caractere na linha: ' + Str( oDOMDoc:parseError:linepos ) + hb_eol() + ;
         ' Causa do erro: '   + oDOMDoc:parseError:reason + hb_eol() + ;
         ' code: '       + Str( oDOMDoc:parseError:errorCode )
      RETURN aRETORNO
   ENDIF

// Localiza as assinaturas no XML
   oDOMDoc:SETPROPERTY( 'SelectionNamespaces', "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'" )
   oXmldsig:signature := oDOMDoc:selectSingleNode( './/ds:Signature' )
   IF ( oXmldsig:signature = nil )
      aRETORNO[ 'MSG' ] := 'É preciso carregar o template antes de assinar.'
      RETURN aRETORNO
   ENDIF

// carrega o objeto do certificado digital
   oCert := ::ohbNFe:pegaObjetoCertificado( ::ohbNFe:cSerialCert )

   IF oCert == Nil
      aRETORNO[ 'MSG' ] := 'Certificado não encontrado, Favor revisar a instalação do Certificado'
      RETURN aRETORNO
   ENDIF

// cria o objeto de Store da capicom
   oStoreMem := win_oleCreateObject( 'CAPICOM.Store' )

// Aloca o certificado na memoria
   BEGIN SEQUENCE WITH __BreakBlock()
      oStoreMem:open( _CAPICOM_MEMORY_STORE, 'Memoria', _CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED )
   RECOVER // CATCH oError
      aRETORNO[ 'MSG' ] := 'Falha ao alocar o certificado na memoria ' + hb_eol() + ;
         'Error: '  + Transform( oError:GenCode, nil ) + ';' + hb_eol() + ;
         'SubC: '   + Transform( oError:SubCode, nil ) + ';' + hb_eol() + ;
         'OSCode: '  + Transform( oError:OsCode, nil ) + ';' + hb_eol() + ;
         'SubSystem: ' + Transform( oError:SubSystem, nil ) + ';' + hb_eol() + ;
         'Mensangem: ' + oError:Description
      RETURN aRETORNO
   ENDSEQUENCE

// Aloca o certificado na Capicom
   BEGIN SEQUENCE WITH __BreakBlock()
      oStoreMem:Add( oCert )
   RECOVER // CATCH oError
      aRETORNO[ 'MSG' ] := 'Falha ao aloca o certificado na memoria da Capicom ' + hb_eol() + ;
         'Error: '  + Transform( oError:GenCode, nil ) + ';' + hb_eol() + ;
         'SubC: '   + Transform( oError:SubCode, nil ) + ';' + hb_eol() + ;
         'OSCode: '  + Transform( oError:OsCode, nil ) + ';' + hb_eol() + ;
         'SubSystem: ' + Transform( oError:SubSystem, nil ) + ';' + hb_eol() + ;
         'Mensangem: ' + oError:Description
      RETURN aRETORNO
   ENDSEQUENCE
   oXmldsig:store := oStoreMem

// Cria chave CSP
   BEGIN SEQUENCE WITH __BreakBlock()
      dsigKey := oXmldsig:createKeyFromCSP( oCert:PrivateKey:ProviderType, oCert:PrivateKey:ProviderName, oCert:PrivateKey:ContainerName, 0 )
   RECOVER
      aRETORNO[ 'MSG' ] := 'Erro ao criar a chave do CSP, talvez o certificado não esteja instalado corretamente.'
      RETURN aRETORNO
   ENDSEQUENCE
   IF ( dsigKey = nil )
      aRETORNO[ 'MSG' ] := 'Erro ao criar a chave do CSP.'
      RETURN aRETORNO
   ENDIF

// Assina a chave do CSP
   BEGIN SEQUENCE WITH __BreakBlock()
      signedKey := oXmldsig:Sign( dsigKey, 2 )
   RECOVER
      aRETORNO[ 'MSG' ] := 'Erro ao assinar a chave do CSP, talvez o certificado não esteja instalado corretamente.'
      RETURN aRETORNO
   ENDSEQUENCE
   IF signedKey = NIL
      aRETORNO[ 'MSG' ] := 'Assinatura Falhou.'
      RETURN( aRetorno )
   ENDIF

// Trata o formato da estrutura do XML
   cXMLSig := StrTran( StrTran( oDOMDoc:xml, Chr( 10 ) ), Chr( 13 ) )
   PosIni := At( '<SignatureValue>', cXMLSig ) + Len( '<SignatureValue>' )
   cXMLSig := SUBS( cXMLSig, 1, PosIni - 1 ) + StrTran( SUBS( cXMLSig, PosIni, Len( cXMLSig ) ), ' ', '' )
   PosIni := At( '<X509Certificate>', cXMLSig ) - 1
   nP   := At( '<X509Certificate>', cXMLSig )
   nResult := 0
   DO WHILE nP <> 0
      nResult := nP
      nP = WAT( '<X509Certificate>', cXMLSig, nP + 1 )
   ENDDO
   PosFim := nResult
   cXMLSig := SUBS( cXMLSig, 1, PosIni ) + SUBS( cXMLSig, PosFim, Len( cXMLSig ) )
   cXMLsig := StrTran( cXMLsig, 'Id="rps:1"', '' )

// grava o arquivo no disco
   nHandle := FCreate( ::Xml )
   FWrite( nHandle, cXMLSig )
   FClose( nHandle )

   aRETORNO[ 'STATUS' ] := .T.
   aRETORNO[ 'XML' ] := ::Xml
   aRETORNO[ 'MSG' ] := 'XML assinado com sucesso em ' + ::Xml

   RETURN aRETORNO


Dá pra descomplicar, apenas uma prévia do que está diferente:

METHOD AssinaXml() CLASS NFSE
   IF ::Xml = NIL .OR. Empty( ::Xml )
      aRETORNO[ 'MSG' ] := 'Arquivo XML com o registro do cabeçalho e RPS não informado.'
   ENDIF
   cXML := MemoRead( ::Xml )
   FErase( ::Xml )
   nHandle := FCreate( ::ohbNFe:pastaEnvRes + "\edunfs.xml" )
   FWrite( nHandle, cXML )
   FClose( nHandle )
   cRetorno := AssinaXml( @cXml, cCertificado )
// grava o arquivo no disco
   nHandle := FCreate( ::Xml )
   FWrite( nHandle, cXMLSig )
   FClose( nHandle )


Com isso, a classe nem usa mais CAPICOM.
Lógico, quem usa é a rotina de assinatura (igual na SefazClass)

Esta aqui também:
METHOD ctPegaCNCertificado() CLASS NFSE

   LOCAL oStore, oCertificados
   LOCAL cSubjectName := '', cCN := ''
   LOCAL mI

   BEGIN SEQUENCE WITH __BreakBlock()
      oStore := win_oleCreateObject( "CAPICOM.Store" )
   END SEQUENCE

   IF oStore = Nil
      RETURN ''
   ENDIF

   oStore:open( _CAPICOM_CURRENT_USER_STORE, 'My', _CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED )
   oCertificados := oStore:Certificates()
   FOR mI = 1 TO oCertificados:Count()
      IF oCertificados:Item( mI ):SerialNumber = ::ohbNFe:cSerialCert
         cSubjectName := oCertificados:Item( mI ):SubjectName
      ENDIF
   NEXT
   cCN := ''
   FOR mI := At( "CN=", cSubjectName ) + 3 TO Len( cSubjectName )
      IF SUBS( cSubjectName, mI, 1 ) == ","
         EXIT
      ENDIF
      cCN += SUBS( cSubjectName, mI, 1 )
   NEXT
   oCertificados := Nil
   oStore := Nil

   RETURN cCN


Vamos pensar....
Se é pra manter o serial do certificado, pra depois pegar o NOME, então é só trabalhar diretamente com o nome, e não com o serial...
(igual na SefazClass)

É chato dizer isso, mas....
Tudo que usa HBNFE como modelo fica ruim, esqueçam os fontes da HBNFE.
É muito trabalho pra pouca coisa.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 11:00

Esta parte também, já falei disso aqui no fórum.

   BEGIN SEQUENCE WITH __BreakBlock()

      oDOMDoc := win_oleCreateObject( _MSXML2_DOMDOCUMENT )
      oDOMDoc:async = .F.
      oDOMDoc:validateOnParse = .T.
      oDOMDoc:resolveExternals := .F.
      oDOMDoc:preserveWhiteSpace = .T.
      oDOMDoc:LoadXML( cXML )

   RECOVER

      aRETORNO[ 'MSG' ] := 'Não foi possível carregar o documento XML'
      RETURN aRETORNO

   ENDSEQUENCE

   IF oDOMDoc:parseError:errorCode <> 0

      aRETORNO[ 'MSG' ] := 'Não foi possível carregar o documento pois ele não corresponde ao seu Schema' + hb_eol() + ;
         ' Linha: ' + Str( oDOMDoc:parseError:line )                   + hb_eol() + ;
         ' Caractere na linha: ' + Str( oDOMDoc:parseError:linepos )           + hb_eol() + ;
         ' Causa do erro: ' + oDOMDoc:parseError:reason                 + hb_eol() + ;
         ' Code: ' + Str( oDOMDoc:parseError:errorCode )
      RETURN aRETORNO

   ENDIF

   BEGIN SEQUENCE WITH __BreakBlock()

      oServerWS:send( oDOMDoc:xml )



Tudo isso é perda de tempo.
Está pegando o componente DOMDOC pra colocar o XML lá, e depois pegar o XML de volta.

Tudo isso, equivale a isto:
oServerWs:Send( cXml )

Não tem que ficar testando seu XML na rotina de envio.
Tem que gerar o XML certo.
E isso nem sequer é uma validação de XML, é só um teste básico.
Teste básico se faz quando está se criando a rotina de gerar XML pela primeira vez.

Isso sem mencionar que tem esta outra:
METHOD ValidaXML()

Se passou no teste completo, pra que fazer o teste básico depois?
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor eduardomc00 » 25 Ago 2017 11:09

josé bom dia!! :D

Há muitas coisas que estão desnecessárias.
O Problema é tempo pra parar e resolver isso.
com a NF-e 4.0 eu pretendo dar uma revisada nesse e no projeto da própria NF-e.
Vamos ver kkkk

Mas se tivr como, me manda a Sefazclass no meu e-mail ? eduardo.mc.00@uol.com.br

Eu ficaria muito feliz kkkk

Obrigado pelos retornos.
eduardomc00
Usuário Nível 1

Usuário Nível 1
 
Mensagens: 43
Data de registro: 07 Out 2014 18:29
Cidade/Estado: São Paulo
Curtiu: 3 vezes
Mens.Curtidas: 0 vez

NFS-e PMSP

Mensagempor eduardomc00 » 25 Ago 2017 11:12

Ahhhh, se quiserem.

aqui estão os códigos do EXE em C#:

Program.cs:

static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            /*
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
             
            */
            if (System.IO.File.Exists(@"StringParaAssinar.txt"))
            {
                string[] lines = System.IO.File.ReadAllLines(@"StringParaAssinar.txt");
                string[] aDados = new string[2];
               
                aDados[0] = lines[0]; // Numero de Série Certificado;
                aDados[1] = lines[1]; // String a Assinar.
                // MessageBox.Show(aDados[0]);
                // MessageBox.Show(aDados[1]);
                AssinarRPS assina = new AssinarRPS();
                String assinatura = assina.AssinarRPSSP(aDados[0], aDados[1]);
                // MessageBox.Show(assinatura);

                //Declaração do método StreamWriter passando o caminho e nome do arquivo que deve ser salvo
                StreamWriter writer = new StreamWriter(@"StringAssinada.txt");
                //Escrevendo o Arquivo e pulando uma linha
                writer.WriteLine(assinatura);
                //Fechando o arquivo
                writer.Close();
                //Limpando a referencia dele da memória
                writer.Dispose();

               
            }
        }
    }


ASSINARPS.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;

namespace WindowsFormsApplication1
{
    public class AssinarRPS
    {
        public AssinarRPS() { }

        public string AssinarRPSSP(string serial, string original)
        {
            //X509Store store = new X509Store(StoreLocation.LocalMachine);
            X509Store store = new X509Store();
            store.Open(OpenFlags.ReadOnly);
            string sn = serial, criptografada; //" put here your certificate serial number ";
            criptografada = "";
            X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindBySerialNumber, serial, true);
            X509Certificate2 cert = null;

            Console.WriteLine(coll.Count);

            if (coll.Count > 0 && coll[0] != null)
            {
                cert = coll[0];
            }
            else return "Erro ao assinar RPS";

            //recebe o certificado e a string a ser assinada
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

            //pega a chave privada do certificado digital
            rsa = cert.PrivateKey as RSACryptoServiceProvider;

            //cria o array de bytes e realiza a conversao da string em array de bytes
            byte[] sAssinaturaByte = enc.GetBytes(original);

            RSAPKCS1SignatureFormatter rsaf = new RSAPKCS1SignatureFormatter(rsa);
            SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();

            //cria a variavel hash que armazena o resultado do sha1
            byte[] hash;
            hash = sha1.ComputeHash(sAssinaturaByte);

            //definimos o metodo a ser utilizado na criptografia e assinamos
            rsaf.SetHashAlgorithm("SHA1");
            sAssinaturaByte = rsaf.CreateSignature(hash);

            //por fim fazemos a conversao do array de bytes para string
            criptografada = Convert.ToBase64String(sAssinaturaByte);
            return criptografada;

        }
    }
}   

eduardomc00
Usuário Nível 1

Usuário Nível 1
 
Mensagens: 43
Data de registro: 07 Out 2014 18:29
Cidade/Estado: São Paulo
Curtiu: 3 vezes
Mens.Curtidas: 0 vez

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 11:23

Então a rotina de assinatura do fonte que postou realmente não funciona ok?

Só pegar da SefazClass que funciona.

A única informação necessária é o inicio/fim dos blocos a assinar, e aonde vai ser colocada a assinatura.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 11:26

com a NF-e 4.0 eu pretendo dar uma revisada nesse e no projeto da própria NF-e.
Vamos ver kkkk


não se esqueça daqui

https://github.com/JoseQuintas/sefazclass
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 11:57

Aliás... vamos inverter agora....
Deixar o seu fonte como origem de informações e começar um do zero, baseado na SefazClass.
Talvez ajude a todos, a entender tudo...
Fazer "de trás pra frente".
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor eduardomc00 » 25 Ago 2017 12:26

Com certeza, inclusive a mim.

Vou migrar o meu Sistema para a SefazClass. Assim falamos a mesma língua.
eduardomc00
Usuário Nível 1

Usuário Nível 1
 
Mensagens: 43
Data de registro: 07 Out 2014 18:29
Cidade/Estado: São Paulo
Curtiu: 3 vezes
Mens.Curtidas: 0 vez

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 13:02

começar com uma sefazclass "pelada", ou pelo menos reduzida.

/*
ZE_SPEDSEFAZCLASS - Rotinas pra comunicação com SEFAZ
José Quintas
*/

#include "hbclass.ch"

#define WS_NFE_STATUSSERVICO         17

#define WS_AMBIENTE_HOMOLOGACAO      "2"
#define WS_AMBIENTE_PRODUCAO         "1"

#ifndef XML_UTF8
   #define XML_UTF8                     [<?xml version="1.0" encoding="UTF-8"?>]
#endif

CREATE CLASS 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
   VAR    cUFTimeZone    INIT "SP"                    // Para DateTimeXml() Obrigatório definir UF default
   /* 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

   METHOD NFeConsultaProtocolo( cChave, cCertificado, cAmbiente )

   /* Uso interno */
   METHOD SetSoapURL( nWsServico )
   METHOD XmlSoapEnvelope()
   METHOD XmlSoapPost()
   METHOD MicrosoftXmlSoapPost()

   METHOD Setup( cUF, cCertificado, cAmbiente, nWsServico )

   ENDCLASS

METHOD NFeConsultaProtocolo( cChave, cCertificado, cAmbiente ) CLASS SefazClass

   ::Setup( ::UFSigla( Substr( cChave, 1, 2 ) ), cCertificado, cAmbiente, WS_NFE_STATUSSERVICO )

   ::cSoapVersion := "3.10"
   ::cXmlEnvio    := [<consSitNFe versao="] + ::cSoapVersion + [" xmlns="http://www.portalfiscal.inf.br/nfe">]
   ::cXmlEnvio    +=    XmlTag( "tpAmb", ::cAmbiente )
   ::cXmlEnvio    +=    XmlTag( "xServ", "CONSULTAR" )
   ::cXmlEnvio    +=    XmlTag( "chNFe", cChave )
   ::cXmlEnvio    += [</consSitNFe>]
   IF ! Substr( cChave, 21, 2 ) $ "55,65"
      ::cXmlRetorno := "*ERRO* Chave não se refere a NFE"
   ELSE
      ::XmlSoapPost()
   ENDIF
   ::cStatus := XmlNode( ::cXmlRetorno, "cStat" )
   ::cMotivo := XmlNode( ::cXmlRetorno, "xMotivo" )

   RETURN ::cXmlRetorno

METHOD Setup( cUF, cCertificado, cAmbiente, nWsServico ) CLASS SefazClass

   LOCAL nPos, aSoapList := { ;
      { "**", WS_NFE_STATUSSERVICO,      "nfeConsultaNFDest",    "http://www.portalfiscal.inf.br/nfe/wsdl/NfeConsultaDest/nfeConsultaNFDest" }, ;
      { "BA", WS_NFE_STATUSSERVICO,     "nfeStatusServicoNF",   "http://www.portalfiscal.inf.br/nfe/wsdl/NfeStatusServico" } }

   ::cUF          := iif( cUF == NIL, ::cUF, cUF )
   ::cCertificado := iif( cCertificado == NIL, ::cCertificado, cCertificado )
   ::cAmbiente    := iif( cAmbiente == NIL, ::cAmbiente, cAmbiente )

   IF nWsServico == NIL
      RETURN NIL
   ENDIF
   IF ( nPos := AScan( aSoapList, { | oElement | oElement[ 1 ] $ ::cUF .AND. oElement[ 2 ] == nWsServico } ) ) != 0
      ::cSoapAction  := aSoapList[ nPos, 4 ]
      ::cSoapService := aSoapList[ nPos, 5 ]
   ELSEIF ( nPos := AScan( aSoapList, { | oElement | oElement[ 1 ] == "**" .AND. oElement[ 2 ] == nWsServico } ) ) != 0
      ::cSoapAction  := aSoapList[ nPos, 4 ]
      ::cSoapService := aSoapList[ nPos, 5 ]
   ENDIF
   ::SetSoapURL( nWsServico )

   RETURN NIL

METHOD SetSoapURL( nWsServico ) CLASS SefazClass

   ::cSoapURL := ""
   DO CASE
   CASE nWsServico == WS_NFE_STATUSSERVICO .AND. ::cUF == "ES" ; ::cSoapURL := "https://app.sefaz.es.gov.br/ConsultaCadastroService/CadConsultaCadastro2.asmx"
   ENDCASE
   IF Empty( ::cSoapURL )
      DO CASE
      CASE ::cUF == "SP" ;  ::cSoapURL := SoapURL_SP( ::cAmbiente, nWsServico, ::cVersao )
      ENDCASE
   ENDIF

   RETURN NIL

METHOD XmlSoapPost() CLASS SefazClass

   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 SefazClass

   ::cXmlSoap    := XML_UTF8
   ::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">]
   ::cXmlSoap    +=    [<soap12:Body>]
   ::cXmlSoap    += ::cXmlEnvio
   ::cXmlSoap    +=    [</] + ::cProjeto + [DadosMsg>]
   ::cXmlSoap    +=    [</soap12:Body>]
   ::cXmlSoap    += [</soap12:Envelope>]

   RETURN NIL

METHOD MicrosoftXmlSoapPost() CLASS SefazClass

   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
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 13:09

Ponto mais interno: comunicação MicrosoftXMLSOAPPost()

METHOD MicrosoftXmlSoapPost() CLASS SefazClass

   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


Temos ali SOAPUrl e SOAPAction

O da NFSE

      oServerWS:open( 'POST', cUrlWS, .F. )
      IF .F. // WSet( LPK_B_PC_TEC ) // NÆo est funcionando
         oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/testeenvio' )
      ELSE
         IF cMethod == 'cancelar'
            oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/cancelamentoNFe' )
         ELSE
            oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/envioLoteRPS' )
         ENDIF
      ENDIF


Então primeira coisa, definir esses dois serviços. WS_CANCELAMENTONFE e WS_ENVIOLOTERPS

E dá pra definir o envelope em XMLSoapEnvelope()
que seria esta parte
   cXML := '<?xml version="1.0" encoding="utf-8"?>' + ;
      '<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + ;
      'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' + ;
      'xmlns:soap12="http://schemas.xmlsoap.org/soap/envelope/">' + ;
      '<soap12:Body>' + ;
      '<' + cNameSpace + ' xmlns="http://www.prefeitura.sp.gov.br/nfe">' + ;
      '<VersaoSchema>1</VersaoSchema>' + ;
      '<MensagemXML> ' + ;
      '<![CDATA[ ' + cXML + ' ]]>' + ;
      '</MensagemXML>' + ;
      '</' + cNameSpace + '>' + ;
      '</soap12:Body>' + ;
      '</soap12:Envelope>'


Aqui já notei uma pequena diferença, que pode fazer diferença.
cXML := '<?xml version="1.0" encoding="utf-8"?>' + ;

UTF-8 está em minúsculas. Tem UF que rejeita isso, pode ser igual em prefeituras.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 13:30

acho que encontrei um dos seus problemas

      IF .F. // WSet( LPK_B_PC_TEC ) // NÆo est funcionando
         oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/testeenvio' )
      ELSE
         IF cMethod == 'cancelar'
            oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/cancelamentoNFe' )
         ELSE
            oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/envioLoteRPS' )
         ENDIF
      ENDIF


A SOAP Action é uma "divisão" da URL (endereço).
Se altera um, altera o outro.
Name space idem.

E mais outro:
      cNameSpace := "CancelamentoNFeRequest"
         IF cMethod == 'cancelar'
            oServerWS:setRequestHeader( 'SOAPAction', 'http://www.prefeitura.sp.gov.br/nfe/ws/cancelamentoNFe' )


maiúscula/minúscula
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor JoséQuintas » 25 Ago 2017 14:02

Um primeiro protótipo.

https://github.com/JoseQuintas/nfse-sp-eduardo/blob/master/NFSEClass.prg

No passo a passo:

Configura, assina, envia e mostra o retorno - destaque que vai configurar pra WS_ENVIOLOTERPS

METHOD EnvioLoteRPS( cXml, cCertificado, cAmbiente ) CLASS SefazClass

   ::Setup( cCertificado, cAmbiente, WS_ENVIOLOTERPS )
   ::cXmlEnvio := ::AssinaXml( cXml )
   ::XmlSoapPost()

   RETURN ::cXmlRetorno


Configuração, pega na lista referente a WS_ENVIOLOTERPS

   LOCAL nPos, aSoapList := { ;
      { WS_CANCELAMENTONFE,  "CancelamentoNFe", "http://www.prefeitura.sp.gov.br/nfe/ws/cancelamentoNFe", "https://naosei" }, ;
      { WS_ENVIOLOTERPS,     "EnvioLoteRPS",    "http://www.prefeitura.sp.gov.br/nfe/ws/envioLoteRPS", "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx" } }

   IF ( nPos := AScan( aSoapList, { | oElement | oElement[ 1 ] == nWsServico } ) ) != 0
      ::cSoapService := aSoapList[ nPos, 2 ]
      ::cSoapAction  := aSoapList[ nPos, 3 ]
      ::cSoapURL     := aSoapList[ nPos, 4 ]
   ENDIF


A comunicação, além de alguns testes preliminares, coloca no envelope e envia.

METHOD XmlSoapPost() CLASS SefazClass

   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


O envelope, usando as informações obtidas no setup
METHOD XmlSoapEnvelope() CLASS SefazClass

   ::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://schemas.xmlsoap.org/soap/envelope/">]
   ::cXmlSoap    +=    [<soap12:Body>]
   ::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>]
   ::cXmlSoap    +=   [</soap12:Body>]
   ::cXmlSoap    += [</soap12:Envelope>]

   RETURN NIL


E finalmente a comunicação propriamente dita, exatamente a mesma rotina da SefazClass.
Apenas faz uso da URL, Certificado, SOAP Action e entrega o XML.
E deixa o retorno disponível em ::cXmlRetorno

METHOD MicrosoftXmlSoapPost() CLASS SefazClass

   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


Falta: assinatura
O detalhe da assinatura, é identificar os blocos e colocar na lista em ze_SpedAssinaXml da SefazClass.
Se for do tipo que assina CADA RPS e mais o XML final, é assinar um RPS de cada vez, e só depois assinar o final.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"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 de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18152
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1215 vezes

NFS-e PMSP

Mensagempor eduardomc00 » 25 Ago 2017 15:58

Tem vezes que estamos tão perdido que uma pessoa de fora enxerga coisas óbvias que não vemos. kkkkkkk :D :D

Eu fiz um teste com o meu código do jeito que ta, e funcionou no A3 tbm ! na máquina do financeiro :-o :-o :-o

está bem mais bonito o código assim !
eduardomc00
Usuário Nível 1

Usuário Nível 1
 
Mensagens: 43
Data de registro: 07 Out 2014 18:29
Cidade/Estado: São Paulo
Curtiu: 3 vezes
Mens.Curtidas: 0 vez

Anterior Próximo



Retornar para Harbour

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 5 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro