Adicionais

This commit is contained in:
2026-06-23 17:00:08 +00:00
parent 12d419de7c
commit d942694ec0
2 changed files with 506 additions and 102 deletions
+95 -102
View File
@@ -650,6 +650,75 @@ class EvolutionController {
}
}
/**
* Busca um cliente pelo número de telefone em TODOS os aliases disponíveis.
* Tenta primeiro o alias principal (mais rápido), depois os demais.
* Retorna { cliente, alias } ou null se não encontrado em nenhum banco.
*/
async function buscarClienteGlobal(numero, empresaId, aliasPrincipal) {
const todosAliases = db.listAliases();
const termo1 = numero;
const termo2 = numero.startsWith('55') ? numero.substring(2) : numero;
const ultimosDigitos = numero.slice(-8);
// Busca primeiro no alias principal (cache quente), depois nos outros
const aliasesOrdenados = [aliasPrincipal];
for (const a of todosAliases) {
if (a !== aliasPrincipal) aliasesOrdenados.push(a);
}
for (const aliasAtual of aliasesOrdenados) {
try {
// Tenta com número completo (DDI 55)
let clientes = await db.query(aliasAtual,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[termo1, termo1, termo1, empresaId]
);
// Tenta sem DDI
if (clientes.length === 0 && termo2 !== termo1) {
clientes = await db.query(aliasAtual,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[termo2, termo2, termo2, empresaId]
);
}
// Último recurso: últimos 8 dígitos
if (clientes.length === 0) {
clientes = await db.query(aliasAtual,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[ultimosDigitos, ultimosDigitos, ultimosDigitos, empresaId]
);
}
if (clientes.length > 0) {
console.log('[Webhook] Cliente encontrado no alias:', aliasAtual, '| ID:', clientes[0].CLI_CODIGO_ID);
return { cliente: clientes[0], alias: aliasAtual };
}
} catch (e) {
// Alias offline ou com erro — pula para o próximo
if (e.message && !e.message.includes('não encontrado')) {
console.log('[Webhook] Alias', aliasAtual, 'indisponível:', e.message.substring(0, 60));
}
}
}
console.log('[Webhook] Cliente NÃO encontrado em nenhum alias para número:', numero);
return null;
}
async function processWebhook(alias, body) {
try {
const data = body.data || body;
@@ -724,75 +793,34 @@ async function processWebhook(alias, body) {
const newId = (maxId[0]?.ID || 0) + 1;
const nomeContato = data.pushName || data.notifyName || sender || '';
// Busca cliente pelo número em múltiplos campos de telefone
// Tenta com o número completo (com DDI 55) e também sem o DDI
// Busca cliente pelo número em TODOS os aliases (multi-banco)
let clienteId = null;
let nomeCliente = null;
// Atualiza foto do contato se configurado (usa metodo estatico)
// A funcao local foi movida para EvolutionController.atualizarFotoContato
const termo1 = numero; // 5582996258669
const termo2 = numero.startsWith('55') ? numero.substring(2) : numero; // 8299625869
var aliasEfetivo = alias; // alias onde o cliente foi encontrado (pode ser diferente)
const clientes = await db.query(alias,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[termo1, termo1, termo1, empresaId]
);
// Se não achou com DDI, tenta sem DDI
if (clientes.length === 0 && termo2 !== termo1) {
const clientes2 = await db.query(alias,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[termo2, termo2, termo2, empresaId]
);
if (clientes2.length > 0) {
clientes.push(...clientes2);
}
}
// Último recurso: tenta os últimos 8 dígitos
if (clientes.length === 0) {
const ultimosDigitos = numero.slice(-8);
const clientes3 = await db.query(alias,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[ultimosDigitos, ultimosDigitos, ultimosDigitos, empresaId]
);
if (clientes3.length > 0) {
clientes.push(...clientes3);
}
}
if (clientes.length > 0) {
clienteId = clientes[0].CLI_CODIGO_ID;
nomeCliente = (clientes[0].CLI_NOME || '').trim();
const resultadoGlobal = await buscarClienteGlobal(numero, empresaId, alias);
if (resultadoGlobal) {
clienteId = resultadoGlobal.cliente.CLI_CODIGO_ID;
nomeCliente = (resultadoGlobal.cliente.CLI_NOME || '').trim();
aliasEfetivo = resultadoGlobal.alias;
// Atualiza foto do contato
EvolutionController.atualizarFotoContato(alias, clienteId, numero, empresaId).catch(function() {});
EvolutionController.atualizarFotoContato(aliasEfetivo, clienteId, numero, empresaId).catch(function() {});
}
// Usa nome do cliente do BD se encontrado, senão usa o nome do WhatsApp
const nomeFinal = nomeCliente || nomeContato;
await db.execute(alias, `
await db.execute(aliasEfetivo, `
INSERT INTO CHATC2_CONVERSAS (CON_CODIGO_ID, CON_EMPRESA_ID, CON_INSTANCIA_ID, CON_NUMERO,
CON_NOME_CONTATO, CON_CLIENTE_ID, CON_STATUS, CON_SITUACAO, CON_PRIMEIRA_MSG, CON_DT_ULTIMA_MSG)
VALUES (?, ?, ?, ?, ?, ?, 'E', 'A', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
`, [newId, empresaId, instanciaId, numero, nomeFinal, clienteId]);
console.log('[Webhook] Conversa criada no alias:', aliasEfetivo, '| ID:', newId);
conversa = await db.query(alias, 'SELECT * FROM CHATC2_CONVERSAS WHERE CON_CODIGO_ID = ?', [newId]);
conversa = await db.query(aliasEfetivo, 'SELECT * FROM CHATC2_CONVERSAS WHERE CON_CODIGO_ID = ?', [newId]);
conversa = conversa[0];
const config = await db.query(alias,
const config = await db.query(aliasEfetivo,
'SELECT CFE_SAUDACAO_ATIVA, CFE_SAUDACAO_MENSAGEM FROM CHATC2_CONFIGURACOES_EMPRESA WHERE CFE_EMPRESA_ID = ?',
[empresaId]
);
@@ -800,16 +828,16 @@ async function processWebhook(alias, body) {
if (config.length > 0 && config[0].CFE_SAUDACAO_ATIVA === 'S') {
const msgSaudacao = (config[0].CFE_SAUDACAO_MENSAGEM || '').trim();
if (msgSaudacao) {
const maxMsgId = await db.query(alias, 'SELECT MAX(CME_CODIGO_ID) AS ID FROM CHATC2_CONVERSAS_MENSAGENS');
await db.execute(alias, `
const maxMsgId = await db.query(aliasEfetivo, 'SELECT MAX(CME_CODIGO_ID) AS ID FROM CHATC2_CONVERSAS_MENSAGENS');
await db.execute(aliasEfetivo, `
INSERT INTO CHATC2_CONVERSAS_MENSAGENS (CME_CODIGO_ID, CME_CONVERSA_ID, CME_REMETENTE, CME_TEXTO, CME_TIPO, CME_SITUACAO, CME_DT_ENVIO)
VALUES (?, ?, 'S', ?, 'text', 'A', CURRENT_TIMESTAMP)
`, [(maxMsgId[0]?.ID || 0) + 1, conversa.CON_CODIGO_ID, msgSaudacao]);
await db.execute(alias, "UPDATE CHATC2_CONVERSAS SET CON_SAUDACAO_ENVIADA = 'S' WHERE CON_CODIGO_ID = ?", [conversa.CON_CODIGO_ID]);
await db.execute(aliasEfetivo, "UPDATE CHATC2_CONVERSAS SET CON_SAUDACAO_ENVIADA = 'S' WHERE CON_CODIGO_ID = ?", [conversa.CON_CODIGO_ID]);
// Envia saudação via Evolution API
try {
const inst = await db.query(alias,
const inst = await db.query(aliasEfetivo,
"SELECT * FROM CHATC2_INSTANCIAS WHERE INS_CODIGO_ID = ? AND INS_SITUACAO = 'A'", [instanciaId]);
if (inst.length > 0) {
await evolutionRequest(
@@ -827,10 +855,10 @@ async function processWebhook(alias, body) {
// Envia menu de triagem SEMPRE que for conversa nova
// (sendMenu internamente verifica se CFE_TRIAGEM_ATIVA = 'S')
try {
const triagemInst = await db.query(alias,
const triagemInst = await db.query(aliasEfetivo,
"SELECT * FROM CHATC2_INSTANCIAS WHERE INS_CODIGO_ID = ? AND INS_SITUACAO = 'A'", [instanciaId]);
if (triagemInst.length > 0) {
await TriageController.sendMenu(alias, conversa.CON_CODIGO_ID, empresaId, instanciaId, numero);
await TriageController.sendMenu(aliasEfetivo, conversa.CON_CODIGO_ID, empresaId, instanciaId, numero);
}
} catch(e) { console.error('[Webhook] Erro ao enviar triagem:', e.message); }
} else {
@@ -838,53 +866,18 @@ async function processWebhook(alias, body) {
// Se a conversa existente não tem cliente vinculado, tenta vincular agora
if (!conversa.CON_CLIENTE_ID) {
const termo1 = numero;
const termo2 = numero.startsWith('55') ? numero.substring(2) : numero;
const clientes = await db.query(alias,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[termo1, termo1, termo1, empresaId]
);
if (clientes.length === 0 && termo2 !== termo1) {
const clientes2 = await db.query(alias,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[termo2, termo2, termo2, empresaId]
);
if (clientes2.length > 0) clientes.push(...clientes2);
}
// Último recurso: tenta os últimos 8 dígitos
if (clientes.length === 0) {
const ultimosDigitos = numero.slice(-8);
const clientes3 = await db.query(alias,
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%'
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE2,''),'-',''),'(',''),')','') LIKE '%' || ? || '%')
AND CLI_EMPRESA_ID = ?`,
[ultimosDigitos, ultimosDigitos, ultimosDigitos, empresaId]
);
if (clientes3.length > 0) clientes.push(...clientes3);
}
if (clientes.length > 0) {
var cliId = clientes[0].CLI_CODIGO_ID;
const nomeCliente = (clientes[0].CLI_NOME || '').trim();
await db.execute(alias,
// Busca cliente em TODOS os aliases (multi-banco)
const resultadoGlobal = await buscarClienteGlobal(numero, empresaId, alias);
if (resultadoGlobal) {
var cliId = resultadoGlobal.cliente.CLI_CODIGO_ID;
const nomeCliente = (resultadoGlobal.cliente.CLI_NOME || '').trim();
var aliasEfetivo = resultadoGlobal.alias;
await db.execute(aliasEfetivo,
'UPDATE CHATC2_CONVERSAS SET CON_CLIENTE_ID = ?, CON_NOME_CONTATO = ? WHERE CON_CODIGO_ID = ?',
[cliId, nomeCliente, conversa.CON_CODIGO_ID]);
conversa.CON_CLIENTE_ID = cliId;
// Atualiza foto do contato
EvolutionController.atualizarFotoContato(alias, cliId, numero, empresaId).catch(function() {});
EvolutionController.atualizarFotoContato(aliasEfetivo, cliId, numero, empresaId).catch(function() {});
}
} else {
// Mesmo ja tendo cliente vinculado, tenta atualizar a foto