30 dias com o WebService

30 dias com o WebServiceEm julho de 2012 fui convidado para desenvolver um aplicativo consumidor de um WebService para produção de Notas Fiscais de Serviço Eletrônicas (NFS-e). A questão é que, mesmo conhecendo o Delphi e seus recursos, eu ainda não tinha experiência com desenvolvimento de aplicativos para acesso de WebServices e com documentos fiscais eletrônicos. A saída foi obter o máximo de informações na internet e com outros profissionais para que o desenvolvimento não ficasse engessado.


WebService é o nome dado a uma tecnologia que permite a integração de diferentes aplicações pela internet por meio de arquivos XML. A grande vantagem de se utilizar um WebService é a agilidade na comunicação, bem como uma padronização dos serviços disponibilizados. O objetivo é automatizar o processamento de um pacote de dados e receber a resposta de forma rápida.
Um bom exemplo de um WebService é a consulta de logradouros através do site dos Correios. Acho que você já deve ter conhecido algum sistema onde o usuário digita o CEP do cliente e todos os dados do endereço são automaticamente preenchidos. Pois então, no momento que o usuário digita o CEP, o sistema faz uma comunicação com o site dos Correios através de um WebService, informando apenas o CEP dentro de um arquivo XML.
A empresa que mantém a funcionalidade do WebService da Prefeitura de Ribeirão Preto é a GINFES, que também atua em outros municípios.

Para consumir um WebService pelo Delphi, o primeiro passo é obter o endereço WSDL, fornecido pela própria empresa que mantém o WebService ativo. O Delphi, desde a versão 7, dispõe de uma ferramenta nativa para importação de endereços WSDL, chamado WSDL Importer:

Ferramenta WSDL Importer do Delphi
Ferramenta WSDL Importer do Delphi

 

Essa ferramenta trata de interpretar o endereço WSDL (ou arquivo WSDL, caso seja baixado para o computador), e criar uma unit com o cabeçalho das funções disponibilizadas pelo WebService, prontas para serem chamadas. O WebService da GINFES, por exemplo, fornece quatro funções: envio de RPS, consulta de lote, consulta de NFS-e e cancelamento de NFS-e. Que bom, já veio tudo pronto! Então, só preciso chamar a função e passar os parâmetros necessários! Espere aí… eu disse “parâmetros”?

Sim. As funções do WebService exigem que um arquivo XML seja obrigatoriamente passado como parâmetro, obedecendo uma estrutura pré-definida pelos desenvolvedores do WebService. Como já sabemos, um arquivo XML consiste em uma hierarquia de tags (que lembram HTML) para armazenar valores.
A GINFES disponibiliza alguns arquivos conhecidos como XML Schema (com extensão XSD) para definição de regras de validação, ou seja, o desenvolvedor deve seguir essas regras para que o WebService receba e processe o arquivo XML corretamente. Após aplicar essas regras, é possível validar a estrutura final do arquivo XML pelo site do W3C.

Exemplo de arquivo XSD
Exemplo de um arquivo XSD

Bom, agora nós temos o endereço do WebService e a forma como o arquivo XML deve ser criado, então já podemos utilizar as funções, certo? Ainda não.
Como se trata de uma operação fiscal, é necessário que o usuário tenha em mãos um Certificado Digital – dispositivo ou arquivo que contém informações sobre entidade emissora (como se fosse o CPF de uma Pessoa Física) – no qual se divide em dois padrões:

  • A1: arquivo de computador
  • A3: dispositivo portátil (cartão ou token USB)

Certificado Digital A3
Certificado Digital do tipo A3

A escolha do padrão a ser utilizado fica a critério da empresa. No meu caso, utilizei um Certificado Digital A3 e um leitor de cartões da empresa Perto. A princípio, tive alguns problemas com a leitura do cartão, devido à incompatibilidade da leitora. Foi necessário comprar uma leitora mais recente para que o cartão fosse corretamente reconhecido.

Apesar da segurança em transferir o arquivo utilizando um Certificado Digital, o WebService ainda exige que o arquivo XML seja digitalmente assinado. Uma Assinatura Digital, em breves palavras, trata-se de uma garantia de que a empresa (emissora do arquivo) é autêntica e que o arquivo gerado é válido. Para ficar mais fácil de entender, pense em um contrato qualquer que exija a assinatura do contratante. Sem a assinatura o contrato não tem validade, correto? Da mesma forma, se o arquivo XML não for assinado, também não terá validade e não poderá ser processado.

Eis que esse foi um dos meus grandes desafios: descobrir como assinar um arquivo pelo Delphi. Passei horas ligando para outros profissionais e tentando descobrir algo na internet, até que finalmente encontrei um site que fazia referência a uma empresa especializada em documentos eletrônicos: A FlexDocs. Após vários contatos, a empresa me disponibilizou uma DLL com uma série de funções, entre elas a geração da Assinatura Digital.

Para utilizar essa DLL no Delphi, primeiramente é preciso importá-la através do menu “Component” > “Import Component”. Ao abrir a janela de importação, deve-se selecionar opção “Import a Type Library” e clicar em “Next”. A próxima tela exibe todas as bibliotecas já registradas no Delphi. Para registrar uma nova biblioteca, clique em Add e carregue a DLL. Seguindo estes passos finalmente consegui criar uma unit com as funções da DLL para gerar a assinatura digital no arquivo.

Nome       := '';
Mensagem   := '';
NFSE_Util  := NFSe_Util_TLB.CoUtil.Create;
Retorno    := NFSE_Util.PegaNomeCertificado(Nome, Mensagem);
Assinatura := NFSE_Util.Assinar(XML_Envio, '', '', Nome, i, Mensagem);

 

O próximo passo era começar a realizar os testes.
Como tudo na informática não funciona da primeira vez, no meu caso não foi diferente, rsrs. Recebi diversas mensagens acusando erros na estrutura do arquivo (o famoso código E160) e outros erros relacionados à validação dos campos, como valores de impostos, descontos e caracteres especiais na descrição do item. O tamanho do campo também é uma restrição do WebService, e foi um dos problemas que me arrancou os cabelos (rsrs) até descobrir que o endereço do tomador estava com dois caracteres excedidos no tamanho.

Ao realizar os testes, me deparei com mais um imprevisto: o arquivo XML era enviado ao WebService e permanecia em uma fila de espera por aproximadamente 20 segundos até que fosse processado. A solução foi programar o aplicativo para aguardar este tempo e realizar uma consulta do lote enviado. Dessa forma, o aplicativo poderia obter o número da NFS-e gerada automaticamente, ótimo! O problema é que em horários de pico este tempo é variável, dependendo da quantidade de arquivos na fila a serem processados. Quando isso ocorria, eu recebia o código E4 indicando que o RPS (arquivo) não foi processado. Portanto, tive que pensar em outra solução.
Logo, ao invés de aguardar apenas 20 segundos, decidi mover a linha de consulta do lote para dentro de um laço de repetição. Se o aplicativo recebesse o código E4, a consulta era feita novamente, caso contrário o arquivo foi processado com sucesso. Apesar de parecer simples, devo assumir que deu um trabalhão, rsrs.

Infelizmente me desliguei da empresa, mas o aplicativo ainda continua sendo utilizado. Desenvolver este aplicativo foi uma grande experiência, embora eu acredite que muitos também já passaram por isso, haha. Aproveitando este artigo, gostaria de agradecer ao Elton Welsch do suporte da GINFES por atender minhas inúmeras ligações, a empresa FlexDocs pela atenção e pela disponibilização da DLL, e também a Maria Rita, Product Owner que me guiou no desenvolvimento deste aplicativo.
Bom, e no fim das contas, o resultado foi este:

 

Informativo SMARAPD sobre a utilização de WebService no sistema SMARaa

Informativo da empresa SMARAPD (Clique para ampliar)

 

Ainda está encontrando dificuldades sobre este assunto?
Confiira o FAQ do WebService da GINFES aqui no blog.

Abraços e até a próxima!


 

Compartilhe!
Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Pin on PinterestEmail this to someone

10 comentários

  1. Não é querendo fazer jabá não mas tem uma empresa de Maringá-PR, a qual tive o prazer de trabalhar, que desenvolve um componente de emissão de NFS-e e já tem mais de 50 cidades homologadas.

    1. Olá, Edvandro!
      Trabalhei na SMARAPD em 2012 e desenvolvi um consumidor do WebService da GINFES de Ribeirão Preto para envio de Notas Fiscais de Serviço Eletrônicas. É sobre este WebService que você se refere?

      Abraço!

    2. boa tarde.
      a SMARAPD está com webservice prórprio. Não estou conseguindo consumir ele.
      Desenvolvo em Delphi 2010

  2. Boa tarde,

    estou tentando consumir o webService da empresa WebISS via delphi xe2, quando envio lote juntamente com o RPS, retorna a seguinte informação: É necessário um certificado para concluir a autenticação do cliente.

    O RPS está assinado por um certificado e não estou conseguindo entender o motivo deste erro.

    1. Olá, Carlos, tudo bem?
      Infelizmente só trabalhei com o WebService da GINFES. Não tenho conhecimento das regras e estruturas da WebISS.
      Mesmo assim, eu sugiro que você entre em contato com a WebISS informando o erro, solicitando um suporte. Foi assim que eu consegui desvendar vários detalhes da GINFES.

      Abraço!

  3. André, parabéns pelos seus posts.
    Estou com um problema na passagem de parâmetros para consumir um WebService, gostaria de pudesse me ajudar. É o seguinte, os parâmetros mesmo sendo do mesmo tipo, não roda e informa tipos incompatíveis.
    Agradeço a atenção.

    METODO DO WSDL

    CartaoDisponivelParameter = class(WebServiceBaseParameter)
    private
      FcodigoEntidade: Integer;
      Fcpf: string;
      FsequencialOrgao: Integer;
    published
      property codigoEntidade:  Integer  read FcodigoEntidade write FcodigoEntidade;
      property cpf:             string   read Fcpf write Fcpf;
      property sequencialOrgao: Integer  read FsequencialOrgao write FsequencialOrgao;
    end;

    RETORNO DO WSD

    CartaoDisponivelRetorno = class(TRemotable)
    private
      FcartoesRetorno: ArrayOfCartaoRetorno;
      FformasEnvio: ArrayOfFormaEnvioRetorno;
    public
      destructor Destroy; override;
    published
      property cartoesRetorno: ArrayOfCartaoRetorno      read FcartoesRetorno write FcartoesRetorno;
      property formasEnvio:    ArrayOfFormaEnvioRetorno  read FformasEnvio write FformasEnvio;
    end;>/pre>
    
    MEU METODO
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
          Servico : SaqueComplementarWebService;
          lista : array[1..7] of string;
    begin
          Servico := GetSaqueComplementarWebService();
          lista := Servico.buscarCartoesDisponiveis(3,'64584947368',0);
          memo1.Text := lista;
    end;

    ERRO AO EXECUTAR

    Compiling Fase02.dproj (Debug configuration)
    [DCC Error] Unit1.pas(35): E2010 Incompatible types: 'CartaoDisponivelParameter' and 'Integer'
    [DCC Error] Unit1.pas(35): E2034 Too many actual parameters
    [DCC Fatal Error] Fase02.dpr(6): F2063 Could not compile used unit 'Unit1.pas'
    Failed

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Preencha o campo abaixo * Time limit is exhausted. Please reload CAPTCHA.