# Consultar CNPJ com ADVPL (Protheus)

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](https://github.com/cnpj-ws/protheus).

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:

```javascript
#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.

```javascript
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.

```javascript
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:

```javascript
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](https://tdn.engpro.totvs.com.br/display/framework/FWRest?focusedCommentId=446697540) 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:

```javascript
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***](https://www.cnpj.ws) retornou na consulta:

```javascript
method getResponse() class CNPJws
return ::oRet
```

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

```javascript
method getError() class CNPJws
return ::cErro
```

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

```javascript
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](https://applysystem.com.br/site/), 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](https://github.com/cnpj-ws/protheus) caso queira dar uma olhada!

Para saber mais sobre nossos planos e formas de pagamento acesse [CNPJ.ws](https://www.cnpj.ws/).

Até mais!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cnpj.ws/blog/integracao-protheus.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
