Consultar CNPJ con ADVPL (Protheus)

Consultar CNPJ en Protheus utilizando la API de CNPJ.ws con ADVPL

El sistema Protheus de Totvs es el ERP líder del mercado brasileño y puede ser integrado con la API de CNPJ.ws de manera fácil y simple para consultar clientes o proveedores a través del CNPJ.

El Protheus utiliza el lenguaje propietario de Totvs, el ADVPL (Advanced Protheus Language), que es un lenguaje de programación estándar xBase (Clipper, Visual Objects y después Fivewin).

Para esta integración vamos a construir una clase genérica de comunicación que podrá ser usada en diversos tipos de proyecto. También puedes encontrar este proyecto en GitHub.

Recordando que puedes usar nuestra API gratuita para consultar CNPJ, pero con una limitación de 3 consultas por minuto o puedes adquirir uno de nuestros planes comerciales.

Con la integración podemos usar la API para consultar la dirección, inscripción estatal, situación cadastral, CNAE y muchas otras informaciones que pueden ser importantes en el momento del registro del cliente o proveedor, persona jurídica, a través del CNPJ.

Integración CNPJ.ws con el ERP Totvs Protheus

Vamos a comenzar, abajo la declaración de la clase:

#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

Tendremos 6 métodos en nuestra clase:

  • new: Responsable de instanciar la clase;

  • setError: Método interno para generación de errores;

  • consultarCNPJ: Responsable de hacer la consulta del CNPJ junto a la API del CNPJ.ws;

  • getResponse: Retorna la respuesta de la API en formato JSON;

  • getError: Retorna el mensaje de error;

Ahora vamos a desarrollar el método new, que es nuestro método constructor. Observa que este método recibe el parámetro lTest (el valor predeterminado es falso) y sí, vamos a hacer pruebas con nuestra clase de integración.

Observa también que tenemos un parámetro CN_TOKEN, debemos crearlo en caso de que estemos usando la API Comercial (sin restricciones) y llenarlo con el Token que fue enviado a tu correo electrónico.

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

En el método new usamos el método consoleLog, entonces vamos a desarrollarlo ahora. Este método busca padronizar los mensajes emitidos por la clase.

En caso de que el parámetro CN_VERBO esté como .T., la clase imprimirá todos los mensajes en el console.log del 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

Abajo el método setError usado por la clase para generar los mensajes de error:

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

Ahora sí, vamos desarrollar el método responsable de comunicarse con la API del CNPJ.ws, el método consultarCNPJ. Aquí vamos a utilizar la clase FWREST para hacer la comunicación con la API, este método recibe el CNPJ como parámetro y hace la consulta en la API.

El método retorna un booleano, en caso de que todo salga bien, retornará true, en caso de error, retornará false, vea abajo:

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

Abajo tenemos el método responsable por retornar el JSON que la API del CNPJ.ws retornó en la consulta:

method getResponse() class CNPJws
return ::oRet

Abajo tenemos el método responsable por retornar el mensaje de error en caso de que la consulta no tenga éxito:

method getError() class CNPJws
return ::cErro

Legal, construimos nuestra clase, ahora es un buen momento para desarrollar una rutina para utilizar nuestra clase:

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 necesites apoyo para implementar esta integración en tu base, te recomendamos Apply System, nuestra socia, que cuenta con consultores especializados en la integración entre sistemas.

Este post quedó largo, ¿verdad? Entonces voy a dejar para hacer una parte 2 utilizando TL++ para crear una prueba para la clase de integración, pero los fuentes ya están en GitHub por si quieres echar un vistazo.

Para saber más sobre nuestros planes y formas de pago accede a CNPJ.ws.

¡Hasta luego!

Última actualización

¿Te fue útil?