Consult CNPJ with ADVPL (Protheus)

Consult CNPJ in Protheus using the CNPJ.ws API with ADVPL

The Totvs Protheus system is the leading ERP in the Brazilian market and can be easily and simply integrated with the CNPJ.ws API to consult customers or suppliers through the CNPJ.

Protheus uses Totvs' proprietary language, ADVPL (Advanced Protheus Language), which is a standard xBase programming language (Clipper, Visual Objects, and later Fivewin).

For this integration, we will build a generic communication class that can be used in various types of projects. You can also find this project on GitHub.

Remember that you can use our free API to consult CNPJ, but with a limitation of 3 queries per minute, or you can purchase one of our commercial plans.

With the integration, we can use the API to query the address, state registration, registration status, CNAE, and many other information that may be important when registering a customer or supplier, a legal entity, through the CNPJ.

Integration of CNPJ.ws with Totvs Protheus ERP

Let's get started, below is the class declaration:

#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

We will have 6 methods in our class:

  • new: Responsible for instantiating the class;

  • setError: Internal method for generating errors;

  • consultarCNPJ: Responsible for querying the CNPJ using the CNPJ.ws API;

  • getResponse: Returns the API response in JSON format;

  • getError: Returns the error message;

Now let's develop the new method, which is our constructor method. Note that this method receives the parameter lTest (the default value is false) and yes, we will run tests with our integration class.

Also note that we have a CN_TOKEN parameter, which we must create if we are using the Commercial API (without restrictions) and fill it with the Token that was sent to your email.

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

In the new method we use the consoleLog method, so let's develop it now. This method aims to standardize the messages emitted by the class.

If the CN_VERBO parameter is set to .T., the class will print all messages in the Protheus console.log.

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

Below is the setError method used by the class to generate error messages:

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

Now, let's develop the method responsible for communicating with the CNPJ.ws API, the consultarCNPJ method. Here we will use the FWREST class to communicate with the API. This method receives the CNPJ as a parameter and performs the query in the API.

The method returns a boolean, if everything goes well it will return true, if an error occurs the return will be false, see below:

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

Below we have the method responsible for returning the JSON that the CNPJ.ws API returned in the query:

method getResponse() class CNPJws
return ::oRet

Below we have the method responsible for returning the error message if the query is not successful:

method getError() class CNPJws
return ::cErro

Great, we have built our class, now is a good time to develop a routine to use our class:

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

If you need support to implement this integration in your environment, we recommend Apply System, our partner, which has consultants specialized in system integration!

This post is quite long, isn't it? So I will leave a part 2 using TL++ to create a test for the integration class, but the source code is already on GitHub if you want to take a look!

To learn more about our plans and payment methods, visit CNPJ.ws.

See you soon!

Last updated

Was this helpful?