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 ProtheusVamos começar, abaixo a declaração da classe:
#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.
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.
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:
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:
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:
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:
method getError() class CNPJwsreturn ::cErro
Legal, construímos nossa classe, agora é um bom momento para desenvolvermos uma rotina para utilizarmos nossa classe:
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!