Pular para o conteúdo principal

Consultar CNPJ com ADVPL (Protheus)

· Leitura de 5 minutos
Carlos Tirabassi

O sistema Protheus da Totvs é o ERP líder do mercado brasileiro e pode ser integrado com a API do CNPJ.ws de maneira fácil e simples para consultar clientes ou fornecedores através do CNPJ.

O Protheus utiliza a linguagem proprietária da Totvs, o ADVPL (Advanced Protheus Language), que é uma linguagem de programação padrão xBase (Clipper, Visual Objects e depois Fivewin).

Para essa integração vamos construir uma classe genérica de comunicação que poderá ser usada em diversos tipos de projeto. Você também pode encontrar esse projeto no GitHub.

Lembrando que você pode usar nossa API gratuita para consultar CNPJ, mas com uma limitação de 3 consultas por minuto ou pode adquirir um dos nossos planos comerciais.

Com a integração podemos usar a API para consultar o endereço, inscrição estadual, situação cadastral, CNAE e muitas outras informações que podem ser importantes no momento do cadastro do cliente ou fornecedor, pessoa jurídica, através do CNPJ.

Integração CNPJ.ws com o ERP Totvs Protheus#

Vamos começar, abaixo a declaração da classe:

/src/cnpjws.prw
#include 'totvs.ch'#include 'protheus.ch'
class CNPJws    data lVerb    as Logical    data cURL     as String    data cToken   as String    data cErro    as String    data cRet     as String    data oRet     as String    data aHeaders as Array    data lRet     as Logical
  method new() CONSTRUCTOR    method consoleLog(cMsg,lErro)    method setError(oRest)    method consultarCNPJ(cCNPJ)    method getResponse()    method getError()endClass

Teremos 6 métodos na nossa classe:

  • new: Responsável por instanciar a classe;
  • setError: Método interno para geração dos erros;
  • consultarCNPJ: Responsável por fazer a consulta do CNPJ junto a API do CNPJ.ws;
  • getResponse: Retorna a resposta da API em formato JSON;
  • getError: Retorna a mensagem de erro;

Agora vamos desenvolver o método new, que é o nosso método construtor. Veja que esse método recebe o parâmetro lTest (o valor default é falso) e sim, vamos fazer testes com a nossa classe de integração.

Veja também que temos um parâmetro CN_TOKEN, devemos criá-lo caso estejamos usando a API Comercial (sem restrições) e preenchê-lo com o Token que foi enviado no seu e-mail.

/src/cnpjws.prw
method new(lTest) class CNPJws
    default lTest:= .f.
    ::cToken  := if(lTest, '', superGetMV('CN_TOKEN',.f.,''))    ::cURL    := if(empty(::cToken),'https://publica.cnpj.ws','https://comercial.cnpj.ws')    ::lVerb   := if(lTest, .t., superGetMV('CN_VERBO',.f.,.t.)) //Indica se ira imprimir todas as msgs no console    ::cErro   := ''    ::cRet    := ''    ::oRet    := nil    ::lRet    := .t.    ::aHeaders:= {"Content-Type: application/json; charset=utf-8"}
    if !empty(::cToken)        aAdd(::aHeaders,'x_api_token: ' + allTrim(::cToken))    endif
    ::consoleLog('Classe instanciada com sucesso!')
return Self

No método new nós usamos o método consoleLog, então vamos desenvolver ele agora. Esse método visa padronizar as mensagens emitidas pela classe.

Caso o parâmetro CN_VERBO esteja como .T. a classe irá imprimir todas as mensagens no console.log do Protheus.

/src/cnpjws.prw
method consoleLog(cMsg,lErro) class CNPJws    local cLog:= ''    default cMsg := ''    default lErro:= .f.
    if ::lVerb .or. lErro        cLog:= '[' + dtoc(date()) + ']'        cLog+= '[' + time() + ']'        cLog+= '[' + ProcName(1) + ']'        cLog+= '[' + cValToChar(ProcLine(1)) + ']'        cLog+= '['+allTrim(cMsg)+']'        if lErro            ::cErro:= cLog            ::lRet := .f.        endif        if ::lVerb .or. lErro            conout(cLog)        endif    endif
return

Abaixo o método setError usado pela classe para gerar as mensagens de erro:

/src/cnpjws.prw
method setError(oRest,cPath) class CNPJws    local cLog      := ''    local cAux      := ''    local cStatus   := ''
    default cPath := ''
    ::oRet := nil    ::cRet:= oRest:GetResult()
    if valType(::cRet) <> 'C'        ::cRet:= ''    endif
    if !empty(::cRet)        ::cRet:= FWNoAccent(DecodeUtf8(::cRet))        if empty(::cRet)            ::cRet:= FWNoAccent(oRest:GetResult())        endif    endif
    cAux:= FWNoAccent(DecodeUtf8(oRest:GetLastError()))    if empty(cAux)        cAux:= FWNoAccent(oRest:GetLastError())    endif
    cStatus:= oRest:GetHTTPCode()    cLog+= 'Host: ' + ::cURL + CRLF    cLog+= 'Operacao: ' + ProcName(1) + ' ' + cPath + CRLF    cLog+= 'HTTP Code: ' + cStatus + CRLF    cLog+= 'Erro: ' + cAux + CRLF    cLog+= 'Resultado: ' + ::cRet + CRLF
    ::consoleLog(cLog,.T.)
return

Agora sim, vamos desenvolver o método responsável por se comunicar com a API do CNPJ.ws, o método consultarCNPJ. Aqui vamos utilizar a classe FWREST para fazer a comunicação com a API, esse método receber o CNPJ como parâmetro e faz a consulta na API.

O método retorna um boolean, caso de tudo certo ele vai retornar true, caso ocorra um erro o retorno será falso, veja abaixo:

/src/cnpjws.prw
method consultarCNPJ(cCNPJ) class CNPJws    local oRest := FWRest():New(::cURL)    local cPath := ''
    ::cRet := ''    ::oRet := nil    ::lRet := .t.    ::cErro:= ''
    cPath+=  allTrim(cCNPJ)    oRest:setPath(cPath)
    if oRest:Get(::aHeaders)        if !empty(oRest:GetResult())            ::cRet:= FWNoAccent(DecodeUtf8(oRest:GetResult()))            if empty(::cRet)                ::cRet:= FWNoAccent(oRest:GetResult())            endif            ::cRet:= strTran(::cRet,'\/','/')            ::cRet:= strtran(::cRet,":null",': " "')            ::cRet:= strtran(::cRet,'"self"','"_self"')            ::oRet:= JsonObject():new()            ::oRet:fromJson(::cRet)            ::lRet := .t.            ::cErro:= ''        else            ::oRet := nil            ::cErro:= ''            ::lRet := .t.        endif        ::consoleLog('Sucesso! ' + cPath)    else        ::setError(oRest,cPath)    endif
    FreeObj(oRest)
return ::lRet

Abaixo temos o método responsável por retornar o JSON que a API do CNPJ.ws retornou na consulta:

/src/cnpjws.prw
method getResponse() class CNPJwsreturn ::oRet

Abaixo temos o método responsável por retornar a mensagem de erro caso a consulta não obtenha sucesso:

/src/cnpjws.prw
method getError() class CNPJwsreturn ::cErro

Legal, construímos nossa classe, agora é um bom momento para desenvolvermos uma rotina para utilizarmos nossa classe:

/src/cnpjws.prw
user function tstCNPJ()    local oCNPJ:= nil    local oJSON:= nil
    RpcSetType(3)    if !RpcSetEnv('99','01')        return    endif            oCNPJ:= CNPJws():new()//Instancia a classe
    if oCNPJ:consultarCNPJ('40154884000153')        oJSON:= oCNPJ:getResponse()    endif
    RPCClearEnv()
return

Caso precise de apoio para implementar essa integração na sua base, nós recomendamos a Apply System, nossa parceira, que possui consultores especializados na integração entre sistemas!

Esse post ficou grande, não é? Então vou deixar para fazer uma parte 2 utilizando o TL++ para criarmos um teste para a classe de integração, porém os fontes já estão no GitHub caso queira dar uma olhada!

Até mais!