FEAT: Adição de parametros que ainda não estavam indo para o prospecto, e fallback de consultas de CEP.
- 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.
This commit is contained in:
parent
26fc47f989
commit
2679e86e2e
@ -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 });
|
||||
|
||||
|
||||
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 });
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user