From 2679e86e2e494c2f0982c666c6f4e9c9a287afed Mon Sep 17 00:00:00 2001 From: "gabriel.amancio" Date: Thu, 8 Jan 2026 14:01:03 -0300 Subject: [PATCH] =?UTF-8?q?FEAT:=20Adi=C3=A7=C3=A3o=20de=20parametros=20qu?= =?UTF-8?q?e=20ainda=20n=C3=A3o=20estavam=20indo=20para=20o=20prospecto,?= =?UTF-8?q?=20e=20fallback=20de=20consultas=20de=20CEP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adicionado valor de ID de CRM fixo e ID de origem-cliente fixo para envio do prospecto. - Criado fallback das APIs de consulta de CEP, se caso o ViaCEP falhar, o CepRest assume, mantendo o fluxo fluido. - 5s de timeout adicionados nas requisições para o ViaCep e CepRest. - Logs mais estruturados adicionados. --- .../contratacao/contratacao.controller.js | 6 +- src/modules/contratacao/contratacao.model.js | 36 +++-- .../contratacao/contratacao.service.js | 148 ++++++++++-------- src/shared/apis/cepRestService.js | 2 +- src/shared/apis/viaCepService.js | 2 +- 5 files changed, 116 insertions(+), 78 deletions(-) diff --git a/src/modules/contratacao/contratacao.controller.js b/src/modules/contratacao/contratacao.controller.js index 195331a..603a8d0 100644 --- a/src/modules/contratacao/contratacao.controller.js +++ b/src/modules/contratacao/contratacao.controller.js @@ -3,7 +3,7 @@ const logger = require('../../shared/utils/logger.js'); async function handleViabilidade(req, res) { const rawViabilidadeData = req.body; - + logger.info('Recebida requisição de viabilidade', { rawViabilidadeData }); try { const resultadoViabilidade = await contratacaoService.verificarViabilidade(rawViabilidadeData); return res.json(resultadoViabilidade); @@ -20,6 +20,10 @@ async function handleCriarProspecto(req, res) { try { const resultado = await contratacaoService.criarProspecto(prospectData); + if (resultado.status === 'error') { + logger.error('Erro ao criar prospecto', { resultado }); + return res.status(500).json({ error: resultado.msg || "Erro ao criar o prospecto." }); + } logger.info('Prospecto criado com sucesso', { resultado }); return res.json({ message: 'Prospecto criado com sucesso', data: resultado }); diff --git a/src/modules/contratacao/contratacao.model.js b/src/modules/contratacao/contratacao.model.js index 186185c..8a86b83 100644 --- a/src/modules/contratacao/contratacao.model.js +++ b/src/modules/contratacao/contratacao.model.js @@ -73,20 +73,29 @@ class ClientModelPj { } class ProspectModel { - constructor(cep, servico, nomeRazaoSocial, cpfCnpj, telefone, email, tipoPessoa, bairro, endereco, numero, nomeMae, idCrm, complemento, dataNascimento) { + // ordem: cep, servico, nomeRazaoSocial, cpfCnpj, telefone, email, tipoPessoa, + // bairro, endereco, numero, nomeMae, idCrm, complemento, dataNascimento + constructor(cep, servico, nomeRazaoSocial, cpfCnpj, telefone, email, tipoPessoa, bairro, endereco, numero, nomeMae, complemento, dataNascimento) { this.cep = cep; this.servico = servico; this.cpf_cnpj = cpfCnpj; this.telefone = telefone; this.nome_razaosocial = nomeRazaoSocial; + // manter ambos formatos (snake e camel) para compatibilidade + this.tipo_pessoa = tipoPessoa; this.tipoPessoa = tipoPessoa; + this.bairro = bairro; this.endereco = endereco; this.numero = numero; this.email = email; + + this.nome_mae = nomeMae; this.nomeMae = nomeMae; - this.id_crm = idCrm; + this.complemento = complemento; + + this.data_nascimento = dataNascimento; this.dataNascimento = dataNascimento; } @@ -97,18 +106,19 @@ class ProspectModel { id_servico: this.servico.id_servico ?? this.servico.id ?? null, valor: this.servico.valor ?? null } : null, + nome_razaosocial: this.nome_razaosocial, cpf_cnpj: this.cpf_cnpj, telefone: this.telefone, - nome_razaosocial: this.nome_razaosocial, - tipo_pessoa: this.tipoPessoa, - bairro: this.bairro, - numero: this.numero, - endereco: this.endereco, email: this.email, - nome_mae: this.nomeMae, - id_crm: this.id_crm, + tipo_pessoa: this.tipo_pessoa, + bairro: this.bairro, + endereco: this.endereco, + numero: this.numero, + nome_mae: this.nome_mae, + id_crm: 4, + data_nascimento: this.data_nascimento, complemento: this.complemento, - data_nascimento: this.dataNascimento + id_origem_cliente: 51 }; } pjToJSON() { @@ -122,11 +132,13 @@ class ProspectModel { cpf_cnpj: this.cpf_cnpj, telefone: this.telefone, email: this.email, - tipo_pessoa: this.tipoPessoa, + tipo_pessoa: this.tipo_pessoa, + id_crm: 4, bairro: this.bairro, endereco: this.endereco, numero: this.numero, - complemento: this.complemento + complemento: this.complemento, + id_origem_cliente: 51 }; } } diff --git a/src/modules/contratacao/contratacao.service.js b/src/modules/contratacao/contratacao.service.js index 2416bde..11f2d4e 100644 --- a/src/modules/contratacao/contratacao.service.js +++ b/src/modules/contratacao/contratacao.service.js @@ -1,11 +1,11 @@ const geogridService = require("../../shared/apis/geogridService.js"); const googleService = require("../../shared/apis/googleService.js"); -// const cepRestService = require("../../shared/apis/cepRestService.js"); +const cepRestService = require("../../shared/apis/cepRestService.js"); const hubsoftService = require("../../shared/apis/hubsoftService.js"); const logger = require('../../shared/utils/logger.js'); const repository = require('./contratacao.repository.js'); const viaCepService = require("../../shared/apis/viaCepService.js"); -const {ViabilidadeModel, ClientModelPf, ClientModelPj, ProspectModel} = require('./contratacao.model'); +const { ViabilidadeModel, ClientModelPf, ClientModelPj, ProspectModel } = require('./contratacao.model'); // utilitário para ler chaves do payload tolerante a ":" e espaços const getPayloadValue = (obj, key) => { @@ -37,37 +37,46 @@ class ServiceError extends Error { async function verificarViabilidade(rawViabilidadeData) { const rawCep = rawViabilidadeData.cep; const rawNumero = rawViabilidadeData.numero; + const source = rawViabilidadeData.source || ''; + + let address; + let addressString; if (!rawCep || !rawNumero) { logger.warn('CEP ou número não fornecidos na verificação de viabilidade.'); throw new ServiceError('CEP e número são obrigatórios.', 400); } - - // Consulta o endereço completo usando a API externa de CEP - const addressData = await viaCepService.getConsultaCep(rawCep); - if (!addressData) { - logger.warn('Endereço não encontrado ou resposta inválida do serviço de CEP', { cep: rawCep, response: addressData }); - throw new ServiceError('Endereço não encontrado para o CEP fornecido.', 404); + + // Obtém o endereço completo usando a API de CEP (viaCEP e cepRestService como fallback) + try { + address = await viaCepService.getConsultaCep(rawCep); + + if (!address || !address.logradouro) { + throw new Error('Resposta inválida do viaCEP'); + } + logger.info('Endereço obtido com sucesso via viaCEP', { address }); + + } catch (err) { + address = await cepRestService.getConsultaCep(rawCep); + if (!address || !address.logradouro) { + throw new Error('Resposta inválida do cepRestService'); + } + logger.info('Endereço obtido com sucesso via cepRestService', { address }); } - logger.info('Endereço obtido com sucesso via CEP', { data: addressData }); - const { logradouro, bairro, localidade: city, uf: state, cep } = addressData; // FIX: Usar address.data para desestruturar - const addressString = `${logradouro}, ${rawNumero}, ${bairro}, ${city}, ${state}, ${cep}`; - logger.info('String de endereço montada para geocodificação', { addressString }); + if (!address) { + throw new ServiceError('Não foi possível obter endereço para o CEP informado.', 502); + } - // const address = await cepRestService.getConsultaCep(rawCep); - // // FIX: Revertendo para a verificação correta da resposta do cepRestService - // if (!address) { - // logger.warn('Endereço não encontrado ou resposta inválida do serviço de CEP', { cep: rawCep, response: address }); - // throw new ServiceError('Endereço não encontrado para o CEP fornecido.', 404); - // } - // logger.info('Endereço obtido com sucesso via CEP', { data: address }); + // Obtém as coordenadas geográficas do endereço usando o Google Geocoding API + + const { logradouro, bairro, localidade: city, uf: state, cep } = address; + + addressString = `${logradouro}, ${rawNumero}, ${bairro}, ${city}, ${state}, ${cep}`; + logger.info('Endereço montado para geocodificação', { addressString }); + - // const { logradouro, bairro, localidade: city, uf: state, cep } = address; // FIX: Usar address.data para desestruturar - // const addressString = `${logradouro}, ${rawNumero}, ${bairro}, ${city}, ${state}, ${cep}`; - // logger.info('String de endereço montada para geocodificação', { addressString }); - const coords = await googleService.geocodeWithGoogle(addressString); if (!coords) { logger.error('Não foi possível obter coordenadas do Google Geocoding', { addressString }); @@ -97,15 +106,20 @@ async function verificarViabilidade(rawViabilidadeData) { logger.warn('Dados de viabilidade não contêm informação de distância', { viabilidadeData: viabilidade.data }); } + + const viabilidadeResult = new ViabilidadeModel(rawViabilidadeData.nome, rawViabilidadeData.email, rawViabilidadeData.telefone, logradouro, rawNumero, bairro, city, state, cep, naoDedicado, dedicado, distancia || null); - await repository.insertViabilidadeData(viabilidadeResult) - .then(() => { - logger.info('Dados de viabilidade inseridos no repositório com sucesso', { viabilidadeResult }); - }) - .catch((err) => { - logger.error('Erro ao inserir dados de viabilidade no repositório', { message: err.message, stack: err.stack }); - }); + if (source) { + return viabilidadeResult; + } + + try { + await repository.insertViabilidadeData(viabilidadeResult); + logger.info('Viabilidade salva com sucesso'); + } catch (err) { + logger.error('Erro ao salvar viabilidade', err); + } return viabilidadeResult; } @@ -115,11 +129,11 @@ async function criarProspecto(rawProspectData) { const payload = (rawProspectData && rawProspectData.prospectData) ? rawProspectData.prospectData : rawProspectData; const planos = { - '100 Mega + Super WiFi': { id_servico: '22'}, - '200 Mega + Super WiFi': { id_servico: '94'}, - '500 Mega + Super WiFi': { id_servico: '96'}, - '700 Mega + Super WiFi': { id_servico: '97'}, - '1 Gb + Super WiFi': { id_servico: '32'}, + '100 Mega + Super WiFi': { id_servico: '22' }, + '200 Mega + Super WiFi': { id_servico: '94' }, + '500 Mega + Super WiFi': { id_servico: '96' }, + '700 Mega + Super WiFi': { id_servico: '97' }, + '1 Gb + Super WiFi': { id_servico: '32' }, }; const planoKey = getPayloadValue(payload, 'Descrição'); @@ -144,47 +158,55 @@ async function criarProspecto(rawProspectData) { throw new ServiceError('Plano inválido ou não encontrado.', 400); } + //função que troca a / da data de nascimento por - + const formatDate = (dateStr) => { + if (!dateStr) return ""; + return dateStr.replace(/\//g, '-'); + }; + + const dataNascimento = formatDate(getPayloadValue(payload, 'Data de nascimento') || ""); + if (payload["CPF:"] === "") { // Pessoa Jurídica const prospectData = new ProspectModel( getPayloadValue(payload, 'CEP'), - servico, // passa o objeto { id_servico, valor } - getPayloadValue(payload, 'Razão Social'), - getPayloadValue(payload, 'CNPJ'), - celular, - getPayloadValue(payload, 'E-mail'), - "pj", - getPayloadValue(payload, 'Bairro'), - getPayloadValue(payload, 'Logradouro'), - getPayloadValue(payload, 'Número'), - 4, // ID fixo do CRM Vendas - getPayloadValue(payload, 'Complemento') || "" + servico, // objeto { id_servico, valor } + getPayloadValue(payload, 'Razão Social'), // nomeRazaoSocial + getPayloadValue(payload, 'CNPJ'), // cpfCnpj + celular, // telefone + getPayloadValue(payload, 'E-mail'), // email + "pj", // tipoPessoa + getPayloadValue(payload, 'Bairro'), // bairro + getPayloadValue(payload, 'Logradouro'), // endereco + getPayloadValue(payload, 'Número'), // numero + "", // nomeMae (não aplicável para PJ) + getPayloadValue(payload, 'Complemento') || "", // complemento + "" // dataNascimento (não aplicável) ); console.log(prospectData); // serializa para JSON plano conforme toJSON() const prospectPayload = (typeof prospectData.pjToJSON === 'function') ? prospectData.pjToJSON() : JSON.parse(JSON.stringify(prospectData)); - + await hubsoftService.criarProspectHubsoft(prospectPayload); return prospectPayload; } else { - // clientData não sendo usado, pois o e-mail está sendo enviado pelo frontend. + // Pessoa Física const prospectData = new ProspectModel( getPayloadValue(payload, 'CEP'), - servico, // passa o objeto { id_servico, valor } - getPayloadValue(payload, 'Nome completo'), - getPayloadValue(payload, 'CPF'), - celular, - getPayloadValue(payload, 'E-mail'), - "pf", - getPayloadValue(payload, 'Bairro'), - getPayloadValue(payload, 'Logradouro'), - getPayloadValue(payload, 'Número'), - getPayloadValue(payload, 'Nome da mãe') || "", - 4, // ID fixo do CRM Vendas - getPayloadValue(payload, 'Complemento') || "", - getPayloadValue(payload, 'Data de nascimento') || "" + servico, // objeto { id_servico, valor } + getPayloadValue(payload, 'Nome completo'), // nomeRazaoSocial + getPayloadValue(payload, 'CPF'), // cpfCnpj + celular, // telefone + getPayloadValue(payload, 'E-mail'), // email + "pf", // tipoPessoa + getPayloadValue(payload, 'Bairro'), // bairro + getPayloadValue(payload, 'Logradouro'), // endereco + getPayloadValue(payload, 'Número'), // numero + getPayloadValue(payload, 'Nome da mãe') || "", // nomeMae + getPayloadValue(payload, 'Complemento') || "", // complemento + dataNascimento // dataNascimento ); console.log(prospectData); // serializa para JSON plano conforme toJSON() @@ -193,10 +215,10 @@ async function criarProspecto(rawProspectData) { : JSON.parse(JSON.stringify(prospectData)); // envia objeto plano ao hubsoft (o hubsoftService já monta { prospectData }) - await hubsoftService.criarProspectHubsoft(prospectPayload); + const result = await hubsoftService.criarProspectHubsoft(prospectPayload); logger.info('Criando prospecto PF', { prospectPayload }); - return prospectPayload; + return result; } } catch (error) { logger.error('Erro ao criar prospecto', { message: error.message, stack: error.stack }); diff --git a/src/shared/apis/cepRestService.js b/src/shared/apis/cepRestService.js index becd00e..a1bca5c 100644 --- a/src/shared/apis/cepRestService.js +++ b/src/shared/apis/cepRestService.js @@ -19,7 +19,7 @@ const getConsultaCep = async (rawCep) => { try { const cepRestUrl = 'https://api.cep.rest/'; - const address = await axios.post(cepRestUrl, { cep }); + const address = await axios.post(cepRestUrl, { cep }, { timeout: 5000 }); console.log(address.data); // Tratamento de resposta conforme diferentes estruturas possíveis diff --git a/src/shared/apis/viaCepService.js b/src/shared/apis/viaCepService.js index 1ab802e..213d383 100644 --- a/src/shared/apis/viaCepService.js +++ b/src/shared/apis/viaCepService.js @@ -14,7 +14,7 @@ const getConsultaCep = async (rawCep) => { } try { const viaCepUrl = `https://viacep.com.br/ws/${cep}/json/`; - const response = await axios.get(viaCepUrl); + const response = await axios.get(viaCepUrl, { timeout: 5000 }); if (response.data.erro) { logger.warn('CEP não encontrado na API ViaCEP', { cep }); return null; // Controller tratará como 'Endereço não encontrado'