Skip to content

Estrutura

O sistema utiliza a API do CNPJÁ para consultar e obter dados de empresas em tempo real a partir de um número de CNPJ. Essa integração é fundamental para agilizar o cadastro de novos clientes, preenchendo automaticamente informações como razão social e endereço.

Visão Geral

A integração foi projetada para automatizar o preenchimento de dados em diversos cenários:

  1. Página de Inscrição (Landing Page): Quando um novo cliente digita o CNPJ, o sistema busca os dados na API e preenche o formulário de cadastro.
  2. Criação de Endereço a partir do CNPJ: Action dedicada (CreateAddressFromCnpj) que busca e cria um endereço completo a partir do CNPJ.
  3. Enriquecimento de Dados: Qualquer parte do sistema pode utilizar a integração para obter dados atualizados de empresas.

Componentes Principais

A funcionalidade é centralizada em um serviço que abstrai a comunicação com a API, sendo consumido por outros componentes da aplicação.

Cnpja

Este é o serviço principal responsável por toda a comunicação com a API do CNPJÁ.

  • Localização: app/Integrations/Cnpja/Cnpja.php

Responsabilidades:

  • Autenticação: Envia o token de autorização no cabeçalho de cada requisição.
  • Consulta: Monta e executa a requisição para o endpoint office/{cnpj} da API, incluindo o parâmetro registrations=BR para obter as inscrições estaduais.
  • Cache: Armazena as respostas da API em cache por uma hora (ONE_HOUR = 3600 segundos) para evitar consultas repetidas e economizar créditos. A chave do cache é padronizada como cnpj_response_{cnpj}.
  • Controle de Rate Limit: Utiliza o RateLimiter do Laravel para garantir que o sistema não exceda o limite de requisições por minuto definido no arquivo de configuração (services.cnpja.attempts).
  • Tratamento de Dados: Normaliza a resposta da API em um array padronizado, incluindo:
    • CNPJ
    • Inscrição Estadual (filtrada pelo estado do endereço principal)
    • Razão Social
    • Telefone (concatenação de área + número)
    • Endereço completo (rua, número, complemento, bairro, cidade, estado, CEP)
  • Logging: Todas as requisições e respostas são logadas para facilitar a depuração.
  • Tratamento de Erros: Retorna null se o CNPJ for inválido ou se a API retornar erro.
php
// app/Integrations/Cnpja/Cnpja.php

public function fetchCnpjData(string $cnpj): ?array
{
    $cnpj = format($cnpj)->onlyNumbers();

    return Cache::remember("cnpj_response_{$cnpj}", self::ONE_HOUR, function () use ($cnpj) {
        $key = 'rate_limit:cnpj_api';

        while ($this->limiter->tooManyAttempts($key, config('services.cnpja.attempts'))) {
            sleep(config('services.cnpja.attempts'));
        }

        $this->limiter->hit($key, self::ONE_MINUTE);

        $response = Http::withHeaders([
            'Authorization' => $this->token,
        ])->get(config('services.cnpja.url') . "office/{$cnpj}?registrations=BR");

        // ... Tratamento da resposta e normalização ...

        return [
            'cnpj'               => $data['taxId'] ?? null,
            'state_registration' => $stateRegistration ?? null,
            'legal_name'         => $data['company']['name'] ?? null,
            'phone'              => $phone,
            'address'            => [
                'street'       => $data['address']['street'] ?? null,
                'number'       => $data['address']['number'] ?? null,
                'complement'   => $data['address']['details'] ?? null,
                'neighborhood' => $data['address']['district'] ?? null,
                'city'         => $data['address']['city'] ?? null,
                'state'        => $data['address']['state'] ?? null,
                'zip'          => $data['address']['zip'] ?? null,
            ],
        ];
    });
}

LandingPage (Livewire Component)

Este componente de front-end utiliza o serviço Cnpja para proporcionar uma experiência de usuário fluida na página de inscrição.

  • Localização: app/Livewire/LandingPage.php

Funcionamento:

  1. O usuário digita o CNPJ no campo client.cnpj.
  2. O evento afterStateUpdated é disparado no onBlur do campo, que por sua vez emite um evento Livewire chamado fillDataFromCnpj.
  3. Um indicador de carregamento (components.loading-cnpj) é exibido na tela.
  4. O método fillDataFromCnpj é executado:
    • Primeiro, ele verifica se o CNPJ já pertence a um cliente existente no banco de dados local.
    • Se não existir, ele invoca o CnpjConsultService para buscar os dados na API.
    • Com os dados em mãos, ele preenche automaticamente os campos do formulário, como Razão Social, Inscrição Estadual e Endereço.
    • Caso a API retorne um erro ou o CNPJ seja inválido, uma mensagem de erro é exibida para o usuário.
php
// app/Livewire/LandingPage.php

#[\Livewire\Attributes\On('fillDataFromCnpj')]
public function fillDataFromCnpj(string $onlyDigits): void
{
    // ...
    $client = Client::where('cnpj', $onlyDigits)->first();

    if ($client) {
        // Preenche com dados locais
    } else {
        // Busca na API CNPJÁ
        $cnpjData = app(Cnpja::class)->fetchCnpjData($onlyDigits);
        if (empty($cnpjData['cnpj'])) {
            $this->addError('data.client.cnpj',  __('validation.custom.cnpj.invalid'));
            // ...
            return;
        }
        // Preenche o formulário com os dados da API
    }

    $this->form->fill(['client' => $clientData]);
    // ...
}

CreateAddressFromCnpj

Esta action é responsável por criar um endereço completo a partir de um CNPJ. Utiliza o padrão de Actions do Laravel.

  • Localização: app/Actions/Address/CreateAddressFromCnpj.php

Funcionamento:

  1. Utiliza o serviço Cnpja para buscar os dados do CNPJ.
  2. Se o CNPJ for inválido ou a API retornar erro, retorna null.
  3. Se houver dados de cidade e estado, busca ou cria o registro de City no banco de dados.
  4. Utiliza a action CreateAddress para criar o endereço com os dados obtidos.
  5. Retorna um array contendo o endereço criado e a inscrição estadual.

Retorno:

  • Array [Address $address, ?string $stateRegistration] em caso de sucesso
  • null se o CNPJ for inválido

Uso:

php
// Pode ser executado de forma síncrona
[$address, $stateRegistration] = CreateAddressFromCnpj::run($cnpj);

// Ou de forma assíncrona como Job
CreateAddressFromCnpj::dispatch($cnpj);

Exemplo de implementação:

php
// app/Actions/Address/CreateAddressFromCnpj.php

public function handle(string $cnpj): ?array
{
    $cnpjService = app(Cnpja::class);
    $cnpjData = $cnpjService->fetchCnpjData($cnpj);

    if (blank($cnpjData)) {
        return null;
    }

    $cityId = null;

    $checkCity = filled($cnpjData['address']['city'] ?? null)
        && filled($cnpjData['address']['state'] ?? null);

    if ($checkCity) {
        $state = State::where('abbreviation', $cnpjData['address']['state'])->first();

        if ($state) {
            $city = City::firstOrCreate([
                'name'     => $cnpjData['address']['city'],
                'state_id' => $state->id,
            ]);

            $cityId = $city->id;
        }
    }

    $addressData = data_get($cnpjData, 'address', []);

    return [CreateAddress::run([
        'postal_code'  => data_get($addressData, 'zip'),
        'street'       => data_get($addressData, 'street'),
        'neighborhood' => data_get($addressData, 'neighborhood'),
        'number'       => data_get($addressData, 'number'),
        'complement'   => data_get($addressData, 'complement'),
        'city_id'      => $cityId,
    ]), data_get($cnpjData, 'state_registration')];
}

Configuração

Para que a integração funcione corretamente, as seguintes variáveis de ambiente devem ser configuradas no arquivo .env:

dotenv
CNPJA_URL=https://api.cnpja.com/
CNPJA_TOKEN=sua_chave_de_api
CNPJA_ATTEMPTS=3
  • CNPJA_URL: A URL base da API.
  • CNPJA_TOKEN: Sua chave de API obtida no painel do CNPJÁ.
  • CNPJA_ATTEMPTS: O número de tentativas por minuto permitidas pelo RateLimiter (geralmente 3, conforme a documentação da API).

Essas variáveis são consumidas através do arquivo de configuração config/services.php.