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
+411
View File
@@ -0,0 +1,411 @@
-- ============================================================
-- CHATC2 - MIGRAÇÕES DE BANCO DE DADOS (Firebird)
-- ============================================================
-- Execute este arquivo no seu banco .FDB usando:
-- isql -user SYSDBA -pass masterkey localhost:SEU_BANCO.FDB -i migracoes.sql
-- Ou cole no IBExpert / FlameRobin e execute statement por statement.
--
-- Cada bloco é idempotente: se a tabela/coluna já existe, o erro é ignorado.
-- ============================================================
-- ============================================================
-- TABELA DE CONTROLE (deve ser a primeira)
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_CONTROLE_MIGRACOES')) THEN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_CONTROLE_MIGRACOES (
MIG_ID INTEGER NOT NULL PRIMARY KEY,
MIG_DESCRICAO VARCHAR(200),
MIG_DATA_EXECUCAO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
MIG_STATUS CHAR(1) DEFAULT ''A''
)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 1: Campo USU_TIPO_CHAT em USUARIOS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'USUARIOS' AND RDB$FIELD_NAME = 'USU_TIPO_CHAT')) THEN
EXECUTE STATEMENT 'ALTER TABLE USUARIOS ADD USU_TIPO_CHAT CHAR(1) DEFAULT ''A''';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 2: Tabela CHATC2_INSTANCIAS (WhatsApp / Evolution API)
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_INSTANCIAS')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_INSTANCIAS (
INS_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
INS_EMPRESA_ID INTEGER NOT NULL,
INS_NOME VARCHAR(100),
INS_URL VARCHAR(500),
INS_API_KEY VARCHAR(500),
INS_INSTANCE_NAME VARCHAR(100),
INS_STATUS CHAR(1) DEFAULT ''D'',
INS_QR_CODE BLOB SUB_TYPE 0,
INS_DT_CONEXAO TIMESTAMP,
INS_DT_CADASTRO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INS_SITUACAO CHAR(1) DEFAULT ''A''
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_INSTANCIAS';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 3: Tabela CHATC2_EQUIPES
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_EQUIPES')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_EQUIPES (
EQU_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
EQU_EMPRESA_ID INTEGER NOT NULL,
EQU_NOME VARCHAR(100),
EQU_ORDEM INTEGER DEFAULT 0,
EQU_SITUACAO CHAR(1) DEFAULT ''A''
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_EQUIPES';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 4: Tabela CHATC2_USU_EQUIPES (usuários x equipes)
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_USU_EQUIPES')) THEN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_USU_EQUIPES (
EQU_EQUIPE_ID INTEGER NOT NULL,
EQU_USUARIO_ID INTEGER NOT NULL,
PRIMARY KEY (EQU_EQUIPE_ID, EQU_USUARIO_ID)
)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 5: Tabela CHATC2_ETIQUETAS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_ETIQUETAS')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_ETIQUETAS (
ETI_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
ETI_EMPRESA_ID INTEGER NOT NULL,
ETI_NOME VARCHAR(50),
ETI_COR VARCHAR(7) DEFAULT ''#667eea'',
ETI_SITUACAO CHAR(1) DEFAULT ''A''
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_ETIQUETAS';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 6: Tabela CHATC2_CONVERSAS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_CONVERSAS')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_CONVERSAS (
CON_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
CON_EMPRESA_ID INTEGER NOT NULL,
CON_INSTANCIA_ID INTEGER,
CON_CLIENTE_ID INTEGER,
CON_NUMERO VARCHAR(20),
CON_NOME_CONTATO VARCHAR(100),
CON_STATUS CHAR(1) DEFAULT ''E'',
CON_USUARIO_ID INTEGER,
CON_EQUIPE_ID INTEGER,
CON_DT_INICIO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CON_DT_FINAL TIMESTAMP,
CON_DT_ULTIMA_MSG TIMESTAMP,
CON_SAUDACAO_ENVIADA CHAR(1) DEFAULT ''N'',
CON_CSAT_ENVIADO CHAR(1) DEFAULT ''N'',
CON_PRIMEIRA_MSG TIMESTAMP,
CON_ORIGEM VARCHAR(20) DEFAULT ''whatsapp'',
CON_SITUACAO CHAR(1) DEFAULT ''A''
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CONVERSAS';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 7: Tabela CHATC2_CONVERSAS_MENSAGENS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_CONVERSAS_MENSAGENS')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_CONVERSAS_MENSAGENS (
CME_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
CME_CONVERSA_ID INTEGER NOT NULL,
CME_REMETENTE CHAR(1) DEFAULT ''C'',
CME_USUARIO_ID INTEGER,
CME_MENSAGEM BLOB SUB_TYPE 1,
CME_TEXTO VARCHAR(4000),
CME_TIPO VARCHAR(20) DEFAULT ''text'',
CME_DT_ENVIO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CME_PRIVADA CHAR(1) DEFAULT ''N'',
CME_LIDA CHAR(1) DEFAULT ''N'',
CME_MIDIA_ID INTEGER,
CME_SITUACAO CHAR(1) DEFAULT ''A''
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CONVERSAS_MENSAGENS';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 8: Tabela CHATC2_MENSAGENS_ATENDIMENTOS (mídias)
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_MENSAGENS_ATENDIMENTOS')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_MENSAGENS_ATENDIMENTOS (
MAT_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
MAT_CONVERSA_ID INTEGER,
MAT_MENSAGEM_ID INTEGER,
MAT_NOME_ARQUIVO VARCHAR(255),
MAT_TIPO_ARQUIVO VARCHAR(50),
MAT_ARQUIVO BLOB SUB_TYPE 0,
MAT_DT_CADASTRO TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
MAT_SITUACAO CHAR(1) DEFAULT ''A''
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_MENSAGENS_ATENDIMENTO';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 9: Tabela CHATC2_CONVERSAS_ETIQUETAS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_CONVERSAS_ETIQUETAS')) THEN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_CONVERSAS_ETIQUETAS (
CET_CONVERSA_ID INTEGER NOT NULL,
CET_ETIQUETA_ID INTEGER NOT NULL,
PRIMARY KEY (CET_CONVERSA_ID, CET_ETIQUETA_ID)
)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 10: Tabela CHATC2_CSAT_AVALIACOES
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_CSAT_AVALIACOES')) THEN
BEGIN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_CSAT_AVALIACOES (
CSA_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
CSA_CONVERSA_ID INTEGER,
CSA_EMPRESA_ID INTEGER,
CSA_CLIENTE_ID INTEGER,
CSA_NOTA INTEGER,
CSA_COMENTARIO VARCHAR(500),
CSA_DT_AVALIACAO TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)';
EXECUTE STATEMENT 'CREATE SEQUENCE GEN_CSAT_AVALIACOES';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 11: Tabela CHATC2_CONFIGURACOES_EMPRESA
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_CONFIGURACOES_EMPRESA')) THEN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_CONFIGURACOES_EMPRESA (
CFE_EMPRESA_ID INTEGER NOT NULL PRIMARY KEY,
CFE_INSTANCIA_PADRAO_ID INTEGER,
CFE_FOTO_CELULAR CHAR(1) DEFAULT ''N'',
CFE_SAUDACAO_ATIVA CHAR(1) DEFAULT ''S'',
CFE_SAUDACAO_MENSAGEM VARCHAR(500),
CFE_CSAT_ATIVO CHAR(1) DEFAULT ''N'',
CFE_CSAT_MENSAGEM VARCHAR(500) DEFAULT ''Avalie seu atendimento de 1 a 5 estrelas''
)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 12: EQU_ORDEM em CHATC2_EQUIPES
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_EQUIPES' AND RDB$FIELD_NAME = 'EQU_ORDEM')) THEN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_EQUIPES ADD EQU_ORDEM INTEGER DEFAULT 0';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 13: Campos de triagem em CHATC2_CONFIGURACOES_EMPRESA
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_CONFIGURACOES_EMPRESA' AND RDB$FIELD_NAME = 'CFE_TRIAGEM_ATIVA')) THEN
BEGIN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_ENVIAR_NOME_USUARIO CHAR(1) DEFAULT ''N''';
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_ATIVA CHAR(1) DEFAULT ''N''';
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_MSG_WELCOME VARCHAR(500)';
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_MSG_AFTER VARCHAR(500)';
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONFIGURACOES_EMPRESA ADD CFE_TRIAGEM_BOLETO_NUMERO VARCHAR(10) DEFAULT ''0''';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 14: CON_MENU_ESTADO em CHATC2_CONVERSAS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_CONVERSAS' AND RDB$FIELD_NAME = 'CON_MENU_ESTADO')) THEN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONVERSAS ADD CON_MENU_ESTADO VARCHAR(100)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 15: CON_ETIQUETAS_DESC em CHATC2_CONVERSAS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_CONVERSAS' AND RDB$FIELD_NAME = 'CON_ETIQUETAS_DESC')) THEN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONVERSAS ADD CON_ETIQUETAS_DESC VARCHAR(500)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 16: Tabela CHATC2_MENUS_EMPRESA (fluxo de atendimento)
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'CHATC2_MENUS_EMPRESA')) THEN
EXECUTE STATEMENT 'CREATE TABLE CHATC2_MENUS_EMPRESA (
MNE_CODIGO_ID INTEGER NOT NULL PRIMARY KEY,
MNE_EMPRESA_ID INTEGER,
MNE_EQUIPE_ID INTEGER,
MNE_MENU_PAI_ID INTEGER,
MNE_ORDEM INTEGER DEFAULT 0,
MNE_TITULO VARCHAR(100),
MNE_TIPO CHAR(1) DEFAULT ''M'',
MNE_TEXTO BLOB SUB_TYPE TEXT,
MNE_ACAO_ROTA VARCHAR(100),
MNE_ACAO_METODO VARCHAR(10),
MNE_ACAO_PROMPT VARCHAR(300),
MNE_SITUACAO CHAR(1) DEFAULT ''A''
)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 17: Novos campos em CHATC2_CONVERSAS
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_CONVERSAS' AND RDB$FIELD_NAME = 'CON_USUARIO_NOME')) THEN
BEGIN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONVERSAS ADD CON_USUARIO_NOME VARCHAR(100)';
EXECUTE STATEMENT 'ALTER TABLE CHATC2_CONVERSAS ADD CON_EQUIPE_NOME VARCHAR(100)';
END
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 18: Etiquetas nos menus de fluxo
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_MENUS_EMPRESA' AND RDB$FIELD_NAME = 'MNE_ETIQUETA_IDS')) THEN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_MENUS_EMPRESA ADD MNE_ETIQUETA_IDS VARCHAR(200)';
END;
^
COMMIT;
^
-- ============================================================
-- MIGRAÇÃO 19: Transcrição de áudio
-- ============================================================
EXECUTE BLOCK AS BEGIN
IF (NOT EXISTS(SELECT 1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'CHATC2_MENSAGENS_ATENDIMENTOS' AND RDB$FIELD_NAME = 'MAT_TRANSCRICAO')) THEN
EXECUTE STATEMENT 'ALTER TABLE CHATC2_MENSAGENS_ATENDIMENTOS ADD MAT_TRANSCRICAO BLOB SUB_TYPE TEXT';
END;
^
COMMIT;
^
-- ============================================================
-- REGISTRO DAS MIGRAÇÕES (marca como executadas)
-- ============================================================
EXECUTE BLOCK AS
DECLARE mig_id INTEGER;
DECLARE mig_desc VARCHAR(200);
BEGIN
-- Só insere se não existir (idempotente)
FOR SELECT MIG_ID, MIG_DESCRICAO FROM (
SELECT 1 AS MIG_ID, 'Campo USU_TIPO_CHAT em USUARIOS' AS MIG_DESCRICAO FROM RDB$DATABASE UNION ALL
SELECT 2, 'Tabela CHATC2_INSTANCIAS' FROM RDB$DATABASE UNION ALL
SELECT 3, 'Tabela CHATC2_EQUIPES' FROM RDB$DATABASE UNION ALL
SELECT 4, 'Tabela CHATC2_USU_EQUIPES' FROM RDB$DATABASE UNION ALL
SELECT 5, 'Tabela CHATC2_ETIQUETAS' FROM RDB$DATABASE UNION ALL
SELECT 6, 'Tabela CHATC2_CONVERSAS' FROM RDB$DATABASE UNION ALL
SELECT 7, 'Tabela CHATC2_CONVERSAS_MENSAGENS' FROM RDB$DATABASE UNION ALL
SELECT 8, 'Tabela CHATC2_MENSAGENS_ATENDIMENTOS' FROM RDB$DATABASE UNION ALL
SELECT 9, 'Tabela CHATC2_CONVERSAS_ETIQUETAS' FROM RDB$DATABASE UNION ALL
SELECT 10, 'Tabela CHATC2_CSAT_AVALIACOES' FROM RDB$DATABASE UNION ALL
SELECT 11, 'Tabela CHATC2_CONFIGURACOES_EMPRESA' FROM RDB$DATABASE UNION ALL
SELECT 12, 'EQU_ORDEM em CHATC2_EQUIPES' FROM RDB$DATABASE UNION ALL
SELECT 13, 'Campos de triagem em config' FROM RDB$DATABASE UNION ALL
SELECT 14, 'CON_MENU_ESTADO em conversas' FROM RDB$DATABASE UNION ALL
SELECT 15, 'CON_ETIQUETAS_DESC em conversas' FROM RDB$DATABASE UNION ALL
SELECT 16, 'Tabela CHATC2_MENUS_EMPRESA' FROM RDB$DATABASE UNION ALL
SELECT 17, 'CON_USUARIO_NOME e CON_EQUIPE_NOME' FROM RDB$DATABASE UNION ALL
SELECT 18, 'MNE_ETIQUETA_IDS nos menus' FROM RDB$DATABASE UNION ALL
SELECT 19, 'MAT_TRANSCRICAO nas mídias' FROM RDB$DATABASE
) AS migracoes
INTO :mig_id, :mig_desc
DO BEGIN
IF (NOT EXISTS(SELECT 1 FROM CHATC2_CONTROLE_MIGRACOES WHERE MIG_ID = :mig_id)) THEN
INSERT INTO CHATC2_CONTROLE_MIGRACOES (MIG_ID, MIG_DESCRICAO) VALUES (:mig_id, :mig_desc);
END
END;
^
COMMIT;
^
-- ============================================================
-- FIM
-- ============================================================
-- Após executar, verifique com:
-- SELECT * FROM CHATC2_CONTROLE_MIGRACOES ORDER BY MIG_ID;
-- Deve mostrar 19 migrações registradas.
+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) { async function processWebhook(alias, body) {
try { try {
const data = body.data || body; const data = body.data || body;
@@ -724,75 +793,34 @@ async function processWebhook(alias, body) {
const newId = (maxId[0]?.ID || 0) + 1; const newId = (maxId[0]?.ID || 0) + 1;
const nomeContato = data.pushName || data.notifyName || sender || ''; const nomeContato = data.pushName || data.notifyName || sender || '';
// Busca cliente pelo número em múltiplos campos de telefone // Busca cliente pelo número em TODOS os aliases (multi-banco)
// Tenta com o número completo (com DDI 55) e também sem o DDI
let clienteId = null; let clienteId = null;
let nomeCliente = null; let nomeCliente = null;
var aliasEfetivo = alias; // alias onde o cliente foi encontrado (pode ser diferente)
// Atualiza foto do contato se configurado (usa metodo estatico) const resultadoGlobal = await buscarClienteGlobal(numero, empresaId, alias);
// A funcao local foi movida para EvolutionController.atualizarFotoContato if (resultadoGlobal) {
const termo1 = numero; // 5582996258669 clienteId = resultadoGlobal.cliente.CLI_CODIGO_ID;
const termo2 = numero.startsWith('55') ? numero.substring(2) : numero; // 8299625869 nomeCliente = (resultadoGlobal.cliente.CLI_NOME || '').trim();
aliasEfetivo = resultadoGlobal.alias;
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();
// Atualiza foto do contato // 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 // Usa nome do cliente do BD se encontrado, senão usa o nome do WhatsApp
const nomeFinal = nomeCliente || nomeContato; 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, 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) CON_NOME_CONTATO, CON_CLIENTE_ID, CON_STATUS, CON_SITUACAO, CON_PRIMEIRA_MSG, CON_DT_ULTIMA_MSG)
VALUES (?, ?, ?, ?, ?, ?, 'E', 'A', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) VALUES (?, ?, ?, ?, ?, ?, 'E', 'A', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
`, [newId, empresaId, instanciaId, numero, nomeFinal, clienteId]); `, [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]; 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 = ?', 'SELECT CFE_SAUDACAO_ATIVA, CFE_SAUDACAO_MENSAGEM FROM CHATC2_CONFIGURACOES_EMPRESA WHERE CFE_EMPRESA_ID = ?',
[empresaId] [empresaId]
); );
@@ -800,16 +828,16 @@ async function processWebhook(alias, body) {
if (config.length > 0 && config[0].CFE_SAUDACAO_ATIVA === 'S') { if (config.length > 0 && config[0].CFE_SAUDACAO_ATIVA === 'S') {
const msgSaudacao = (config[0].CFE_SAUDACAO_MENSAGEM || '').trim(); const msgSaudacao = (config[0].CFE_SAUDACAO_MENSAGEM || '').trim();
if (msgSaudacao) { if (msgSaudacao) {
const maxMsgId = await db.query(alias, 'SELECT MAX(CME_CODIGO_ID) AS ID FROM CHATC2_CONVERSAS_MENSAGENS'); const maxMsgId = await db.query(aliasEfetivo, 'SELECT MAX(CME_CODIGO_ID) AS ID FROM CHATC2_CONVERSAS_MENSAGENS');
await db.execute(alias, ` 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) 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) VALUES (?, ?, 'S', ?, 'text', 'A', CURRENT_TIMESTAMP)
`, [(maxMsgId[0]?.ID || 0) + 1, conversa.CON_CODIGO_ID, msgSaudacao]); `, [(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 // Envia saudação via Evolution API
try { 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]); "SELECT * FROM CHATC2_INSTANCIAS WHERE INS_CODIGO_ID = ? AND INS_SITUACAO = 'A'", [instanciaId]);
if (inst.length > 0) { if (inst.length > 0) {
await evolutionRequest( await evolutionRequest(
@@ -827,10 +855,10 @@ async function processWebhook(alias, body) {
// Envia menu de triagem SEMPRE que for conversa nova // Envia menu de triagem SEMPRE que for conversa nova
// (sendMenu internamente verifica se CFE_TRIAGEM_ATIVA = 'S') // (sendMenu internamente verifica se CFE_TRIAGEM_ATIVA = 'S')
try { 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]); "SELECT * FROM CHATC2_INSTANCIAS WHERE INS_CODIGO_ID = ? AND INS_SITUACAO = 'A'", [instanciaId]);
if (triagemInst.length > 0) { 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); } } catch(e) { console.error('[Webhook] Erro ao enviar triagem:', e.message); }
} else { } else {
@@ -838,53 +866,18 @@ async function processWebhook(alias, body) {
// Se a conversa existente não tem cliente vinculado, tenta vincular agora // Se a conversa existente não tem cliente vinculado, tenta vincular agora
if (!conversa.CON_CLIENTE_ID) { if (!conversa.CON_CLIENTE_ID) {
const termo1 = numero; // Busca cliente em TODOS os aliases (multi-banco)
const termo2 = numero.startsWith('55') ? numero.substring(2) : numero; const resultadoGlobal = await buscarClienteGlobal(numero, empresaId, alias);
if (resultadoGlobal) {
const clientes = await db.query(alias, var cliId = resultadoGlobal.cliente.CLI_CODIGO_ID;
`SELECT CLI_CODIGO_ID, CLI_NOME FROM CLIENTES const nomeCliente = (resultadoGlobal.cliente.CLI_NOME || '').trim();
WHERE (REPLACE(REPLACE(REPLACE(COALESCE(CLI_CELULAR,''),'-',''),'(',''),')','') LIKE '%' || ? || '%' var aliasEfetivo = resultadoGlobal.alias;
OR REPLACE(REPLACE(REPLACE(COALESCE(CLI_FONE1,''),'-',''),'(',''),')','') LIKE '%' || ? || '%' await db.execute(aliasEfetivo,
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,
'UPDATE CHATC2_CONVERSAS SET CON_CLIENTE_ID = ?, CON_NOME_CONTATO = ? WHERE CON_CODIGO_ID = ?', 'UPDATE CHATC2_CONVERSAS SET CON_CLIENTE_ID = ?, CON_NOME_CONTATO = ? WHERE CON_CODIGO_ID = ?',
[cliId, nomeCliente, conversa.CON_CODIGO_ID]); [cliId, nomeCliente, conversa.CON_CODIGO_ID]);
conversa.CON_CLIENTE_ID = cliId; conversa.CON_CLIENTE_ID = cliId;
// Atualiza foto do contato // Atualiza foto do contato
EvolutionController.atualizarFotoContato(alias, cliId, numero, empresaId).catch(function() {}); EvolutionController.atualizarFotoContato(aliasEfetivo, cliId, numero, empresaId).catch(function() {});
} }
} else { } else {
// Mesmo ja tendo cliente vinculado, tenta atualizar a foto // Mesmo ja tendo cliente vinculado, tenta atualizar a foto