topsapp: adicionado opção de abrir suporte
Signed-off-by: Rodrigo B. de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
1337e1c2d0
commit
3d35fc24cc
9 files changed
+1600
-1
No files matched your search
@@ -4,6 +4,7 @@ const { TopSappManager } = require('../topsapp');
|
||||
const FiberhomeManager = require('../fiberhome/manager');
|
||||
const config = require('../config/config');
|
||||
const logger = require('../utils/logger');
|
||||
const DateProcessor = require('../utils/dateProcessor');
|
||||
|
||||
class BotHandler {
|
||||
constructor(bot) {
|
||||
@@ -12,7 +13,9 @@ class BotHandler {
|
||||
this.ssh = new SSHManager();
|
||||
this.topsapp = new TopSappManager();
|
||||
this.fiberhome = new FiberhomeManager();
|
||||
this.dateProcessor = new DateProcessor();
|
||||
this.userSessions = new Map(); // Armazena sessões de usuário
|
||||
this.suporteSessions = new Map(); // Armazena sessões de suporte em andamento
|
||||
|
||||
logger.info('BotHandler inicializado');
|
||||
console.log('🎯 BotHandler inicializado');
|
||||
@@ -55,6 +58,12 @@ class BotHandler {
|
||||
}
|
||||
|
||||
try {
|
||||
// Verificar se há uma sessão de suporte ativa
|
||||
const processouSuporte = await this.processarMensagemSuporte(msg);
|
||||
if (processouSuporte) {
|
||||
return; // Mensagem foi processada pelo fluxo de suporte
|
||||
}
|
||||
|
||||
// Verificar se o usuário está em uma sessão esperando input
|
||||
const userSession = this.userSessions.get(userId);
|
||||
if (userSession) {
|
||||
@@ -215,6 +224,13 @@ class BotHandler {
|
||||
await this.handleFiberhomeStatus(chatId);
|
||||
break;
|
||||
|
||||
case 'abrir_suporte':
|
||||
case 'adicionar_suporte':
|
||||
case 'criar_suporte':
|
||||
console.log(`🎫 Iniciando processo de abertura de suporte`);
|
||||
await this.iniciarProcessoSuporte(chatId, user.id, target);
|
||||
break;
|
||||
|
||||
case 'conectar':
|
||||
await this.handleConnect(chatId, target);
|
||||
break;
|
||||
@@ -336,6 +352,29 @@ Digite /help para ver todos os comandos disponíveis!
|
||||
• "liberar 123.456.789-10"
|
||||
• "status topsapp"
|
||||
|
||||
🎫 TOPSAPP - ABERTURA DE SUPORTE:
|
||||
• "abrir suporte"
|
||||
• "criar suporte para João Silva"
|
||||
• "novo chamado"
|
||||
• "suporte cliente 123.456.789-10"
|
||||
|
||||
🔄 PROCESSO INTERATIVO DE SUPORTE:
|
||||
1️⃣ Busca do cliente (nome ou CPF)
|
||||
2️⃣ Seleção do serviço
|
||||
3️⃣ Escolha da categoria do problema
|
||||
4️⃣ Seleção do técnico responsável
|
||||
5️⃣ Agendamento de data/hora para visita
|
||||
6️⃣ Descrição detalhada do problema
|
||||
7️⃣ Confirmação e criação do protocolo
|
||||
|
||||
📅 EXEMPLOS DE DATA/HORA:
|
||||
• "amanhã às 14h"
|
||||
• "sexta-feira 09:00"
|
||||
• "15/08 às 16h30"
|
||||
• "hoje 18h"
|
||||
• "em 3 dias às 10h"
|
||||
• "segunda-feira 08:30"
|
||||
|
||||
📋 DADOS CADASTRAIS COMPLETOS:
|
||||
• Informações pessoais do cliente
|
||||
• CPF, telefone, endereço completo
|
||||
@@ -1031,6 +1070,12 @@ Digite /help para ver todos os comandos disponíveis!
|
||||
this.userSessions.set(callbackQuery.from.id, {
|
||||
type: 'waiting_username_disconnect'
|
||||
});
|
||||
} else if (data.startsWith('suporte_cliente_')) {
|
||||
console.log(`🔍 Condição suporte_cliente_ atendida`);
|
||||
await this.handleSuporteClienteCallback(callbackQuery, data);
|
||||
} else if (data.startsWith('suporte_servico_')) {
|
||||
console.log(`🔍 Condição suporte_servico_ atendida`);
|
||||
await this.handleSuporteServicoCallback(callbackQuery, data);
|
||||
} else {
|
||||
console.log(`❓ Callback não reconhecido: ${data}`);
|
||||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Comando não reconhecido');
|
||||
@@ -4003,6 +4048,132 @@ Digite /help para ver todos os comandos disponíveis!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback para selecionar cliente para suporte
|
||||
*/
|
||||
async handleSuporteClienteCallback(callbackQuery, data) {
|
||||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||||
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const userId = callbackQuery.from.id;
|
||||
|
||||
const parts = data.split('_');
|
||||
const clienteIndex = parseInt(parts[2]);
|
||||
|
||||
console.log(`🎫 Cliente selecionado para suporte: índice ${clienteIndex}`);
|
||||
|
||||
// Encontrar sessão ativa para este usuário
|
||||
const sessaoAtiva = Array.from(this.suporteSessions.values()).find(
|
||||
session => session.chatId === chatId && session.userId === userId
|
||||
);
|
||||
|
||||
if (!sessaoAtiva) {
|
||||
await this.bot.editMessageText(
|
||||
'❌ **Sessão expirada**\n\nPor favor, inicie novamente com o comando "abrir suporte".',
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sessaoAtiva.dados || !sessaoAtiva.dados.clientesEncontrados || clienteIndex >= sessaoAtiva.dados.clientesEncontrados.length) {
|
||||
await this.bot.editMessageText(
|
||||
'❌ **Cliente inválido**\n\nPor favor, tente novamente.',
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Selecionar cliente
|
||||
sessaoAtiva.dados.clienteSelecionado = sessaoAtiva.dados.clientesEncontrados[clienteIndex];
|
||||
sessaoAtiva.etapa = 'selecionar_servico';
|
||||
|
||||
console.log(`✅ Cliente selecionado: ${sessaoAtiva.dados.clienteSelecionado.nome}`);
|
||||
|
||||
// Atualizar mensagem para mostrar cliente selecionado
|
||||
await this.bot.editMessageText(
|
||||
`✅ **Cliente selecionado:**\n${sessaoAtiva.dados.clienteSelecionado.nome}\n\n🔍 Buscando serviços...`,
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
}
|
||||
);
|
||||
|
||||
// Continuar para próxima etapa
|
||||
await this.processarEtapaSelecionarServico(sessaoAtiva.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback para selecionar serviço para suporte
|
||||
*/
|
||||
async handleSuporteServicoCallback(callbackQuery, data) {
|
||||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||||
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const userId = callbackQuery.from.id;
|
||||
|
||||
const parts = data.split('_');
|
||||
const servicoIndex = parseInt(parts[2]);
|
||||
|
||||
console.log(`🎫 Serviço selecionado para suporte: índice ${servicoIndex}`);
|
||||
|
||||
// Encontrar sessão ativa para este usuário
|
||||
const sessaoAtiva = Array.from(this.suporteSessions.values()).find(
|
||||
session => session.chatId === chatId && session.userId === userId
|
||||
);
|
||||
|
||||
if (!sessaoAtiva) {
|
||||
await this.bot.editMessageText(
|
||||
'❌ **Sessão expirada**\n\nPor favor, inicie novamente com o comando "abrir suporte".',
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sessaoAtiva.dados || !sessaoAtiva.dados.servicos || servicoIndex >= sessaoAtiva.dados.servicos.length) {
|
||||
await this.bot.editMessageText(
|
||||
'❌ **Serviço inválido**\n\nPor favor, tente novamente.',
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Selecionar serviço
|
||||
sessaoAtiva.dados.servicoSelecionado = sessaoAtiva.dados.servicos[servicoIndex];
|
||||
sessaoAtiva.etapa = 'selecionar_categoria';
|
||||
|
||||
console.log(`✅ Serviço selecionado: ${sessaoAtiva.dados.servicoSelecionado.nome}`);
|
||||
|
||||
// Atualizar mensagem para mostrar serviço selecionado
|
||||
await this.bot.editMessageText(
|
||||
`✅ **Serviço selecionado:**\n${sessaoAtiva.dados.servicoSelecionado.nome}\n\n🔍 Buscando categorias de suporte...`,
|
||||
{
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
parse_mode: 'Markdown'
|
||||
}
|
||||
);
|
||||
|
||||
// Continuar para próxima etapa
|
||||
await this.processarEtapaSelecionarCategoria(sessaoAtiva.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback para mostrar dados cadastrais do cliente
|
||||
*/
|
||||
@@ -4580,6 +4751,702 @@ Digite /help para ver todos os comandos disponíveis!
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iniciar processo interativo de abertura de suporte
|
||||
*/
|
||||
async iniciarProcessoSuporte(chatId, userId, target = '') {
|
||||
if (!this.topsapp.isReady()) {
|
||||
await this.bot.sendMessage(chatId,
|
||||
`❌ **TopSapp não configurado**\n\n` +
|
||||
`⚠️ O sistema TopSapp não está configurado. Entre em contato com o administrador.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Criar sessão de suporte
|
||||
const sessionId = `${userId}_${chatId}_${Date.now()}`;
|
||||
const suporteSession = {
|
||||
id: sessionId,
|
||||
chatId,
|
||||
userId,
|
||||
etapa: 'buscar_cliente',
|
||||
dados: {},
|
||||
iniciado: new Date()
|
||||
};
|
||||
|
||||
this.suporteSessions.set(sessionId, suporteSession);
|
||||
|
||||
await this.bot.sendMessage(chatId,
|
||||
`🎫 **Abertura de Suporte**\n\n` +
|
||||
`🔍 **Etapa 1:** Identificar Cliente\n\n` +
|
||||
`Por favor, digite o **nome** ou **CPF** do cliente para quem deseja abrir o suporte:`,
|
||||
{ parse_mode: 'Markdown' }
|
||||
);
|
||||
|
||||
// Se foi fornecido um target, usar como busca inicial
|
||||
if (target && target.trim()) {
|
||||
await this.processarEtapaSuporteBuscarCliente(sessionId, target.trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processar mensagem dentro do fluxo de suporte
|
||||
*/
|
||||
async processarMensagemSuporte(msg) {
|
||||
const chatId = msg.chat.id;
|
||||
const userId = msg.from.id;
|
||||
const text = msg.text;
|
||||
|
||||
// Encontrar sessão ativa para este usuário
|
||||
const sessaoAtiva = Array.from(this.suporteSessions.values()).find(
|
||||
session => session.chatId === chatId && session.userId === userId
|
||||
);
|
||||
|
||||
if (!sessaoAtiva) {
|
||||
return false; // Não há sessão ativa
|
||||
}
|
||||
|
||||
try {
|
||||
switch (sessaoAtiva.etapa) {
|
||||
case 'buscar_cliente':
|
||||
await this.processarEtapaSuporteBuscarCliente(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'selecionar_cliente':
|
||||
await this.processarEtapaSelecionarCliente(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'selecionar_servico':
|
||||
await this.processarEtapaSelecionarServico(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'selecionar_categoria':
|
||||
await this.processarEtapaSelecionarCategoria(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'selecionar_tecnico':
|
||||
await this.processarEtapaSelecionarTecnico(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'definir_data_hora':
|
||||
await this.processarEtapaDefinirDataHora(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'adicionar_descricao':
|
||||
await this.processarEtapaAdicionarDescricao(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
case 'confirmar':
|
||||
await this.finalizarCriacaoSuporte(sessaoAtiva.id, text);
|
||||
break;
|
||||
|
||||
default:
|
||||
await this.bot.sendMessage(chatId, '❌ Etapa desconhecida. Reiniciando processo...');
|
||||
this.suporteSessions.delete(sessaoAtiva.id);
|
||||
break;
|
||||
}
|
||||
|
||||
return true; // Mensagem foi processada pelo fluxo de suporte
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Erro no processamento de suporte:', error);
|
||||
await this.bot.sendMessage(chatId,
|
||||
`❌ **Erro no processamento**\n\n` +
|
||||
`⚠️ ${error.message}\n\n` +
|
||||
`🔄 Reiniciando processo de suporte...`
|
||||
);
|
||||
this.suporteSessions.delete(sessaoAtiva.id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 1: Buscar cliente
|
||||
*/
|
||||
async processarEtapaSuporteBuscarCliente(sessionId, query) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
await this.bot.sendMessage(session.chatId, `🔍 Buscando cliente: "${query}"...`);
|
||||
|
||||
try {
|
||||
const resultado = await this.topsapp.buscarCliente(query);
|
||||
|
||||
if (!resultado.success) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro na busca**\n\n` +
|
||||
`⚠️ ${resultado.error}\n\n` +
|
||||
`Por favor, tente novamente com outro nome ou CPF:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultado.clientes || resultado.clientes.length === 0) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Nenhum cliente encontrado**\n\n` +
|
||||
`🔍 Não foi encontrado nenhum cliente com: "${query}"\n\n` +
|
||||
`Por favor, tente novamente com outro nome ou CPF:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.clientesEncontrados = resultado.clientes;
|
||||
|
||||
if (resultado.clientes.length === 1) {
|
||||
// Apenas um cliente encontrado, selecionar automaticamente
|
||||
session.dados.clienteSelecionado = resultado.clientes[0];
|
||||
session.etapa = 'selecionar_servico';
|
||||
await this.processarEtapaSelecionarServico(sessionId);
|
||||
} else {
|
||||
// Múltiplos clientes, deixar usuário escolher
|
||||
session.etapa = 'selecionar_cliente';
|
||||
await this.mostrarOpcoesClientes(session);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro na busca**\n\n` +
|
||||
`⚠️ ${error.message}\n\n` +
|
||||
`Por favor, tente novamente:`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostrar opções de clientes encontrados
|
||||
*/
|
||||
async mostrarOpcoesClientes(session) {
|
||||
let message = `👥 **Clientes encontrados:**\n\n`;
|
||||
|
||||
const buttons = [];
|
||||
|
||||
session.dados.clientesEncontrados.forEach((cliente, index) => {
|
||||
const status = this.topsapp.interpretarStatusCliente ?
|
||||
this.topsapp.interpretarStatusCliente(cliente) :
|
||||
cliente.status;
|
||||
const statusEmoji = status === 1 ? '🟢' : '🔴';
|
||||
|
||||
message += `**${index + 1}.** ${statusEmoji} ${cliente.nome}\n`;
|
||||
message += ` 📄 CPF: ${cliente.cpf || 'N/A'}\n`;
|
||||
message += ` 🆔 ID: ${cliente.id}\n\n`;
|
||||
|
||||
// Adicionar botão para seleção direta
|
||||
buttons.push([{
|
||||
text: `${index + 1}. ${cliente.nome}`,
|
||||
callback_data: `suporte_cliente_${index}`
|
||||
}]);
|
||||
});
|
||||
|
||||
message += `Selecione o cliente clicando no botão ou digite o **número** (1-${session.dados.clientesEncontrados.length}):`;
|
||||
|
||||
const keyboard = {
|
||||
inline_keyboard: buttons
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(session.chatId, message, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: keyboard
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 2: Selecionar cliente específico
|
||||
*/
|
||||
async processarEtapaSelecionarCliente(sessionId, input) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
const numero = parseInt(input.trim());
|
||||
|
||||
if (isNaN(numero) || numero < 1 || numero > session.dados.clientesEncontrados.length) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Número inválido**\n\n` +
|
||||
`Por favor, digite um número entre 1 e ${session.dados.clientesEncontrados.length}:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.clienteSelecionado = session.dados.clientesEncontrados[numero - 1];
|
||||
session.etapa = 'selecionar_servico';
|
||||
await this.processarEtapaSelecionarServico(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 3: Selecionar serviço
|
||||
*/
|
||||
async processarEtapaSelecionarServico(sessionId, input = null) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
const cliente = session.dados.clienteSelecionado;
|
||||
|
||||
if (!input) {
|
||||
// Primeira vez nesta etapa - buscar serviços
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`🔍 Buscando serviços do cliente **${cliente.nome}**...`,
|
||||
{ parse_mode: 'Markdown' }
|
||||
);
|
||||
|
||||
try {
|
||||
const resultado = await this.topsapp.obterServicosCliente(cliente.id);
|
||||
|
||||
console.log(`🔍 Handler - Resultado completo:`, {
|
||||
success: resultado.success,
|
||||
servicosCount: resultado.servicos?.length,
|
||||
total: resultado.total,
|
||||
debug: resultado.debug
|
||||
});
|
||||
|
||||
if (!resultado.success) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao buscar serviços**\n\n` +
|
||||
`⚠️ ${resultado.error}\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultado.servicos || resultado.servicos.length === 0) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Nenhum serviço encontrado**\n\n` +
|
||||
`O cliente não possui serviços cadastrados.\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.servicos = resultado.servicos;
|
||||
await this.mostrarOpcoesServicos(session);
|
||||
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao buscar serviços**\n\n` +
|
||||
`⚠️ ${error.message}\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
}
|
||||
} else {
|
||||
// Usuário selecionou um serviço
|
||||
const numero = parseInt(input.trim());
|
||||
|
||||
if (isNaN(numero) || numero < 1 || numero > session.dados.servicos.length) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Número inválido**\n\n` +
|
||||
`Por favor, digite um número entre 1 e ${session.dados.servicos.length}:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.servicoSelecionado = session.dados.servicos[numero - 1];
|
||||
session.etapa = 'selecionar_categoria';
|
||||
await this.processarEtapaSelecionarCategoria(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostrar opções de serviços
|
||||
*/
|
||||
async mostrarOpcoesServicos(session) {
|
||||
let message = `📋 **Serviços disponíveis:**\n\n`;
|
||||
|
||||
const buttons = [];
|
||||
|
||||
session.dados.servicos.forEach((servico, index) => {
|
||||
const statusEmoji = servico.statusNumerico === 1 ? '🟢' : '🔴';
|
||||
|
||||
message += `**${index + 1}.** ${statusEmoji} ${servico.nome}\n`;
|
||||
message += ` 🆔 ID: ${servico.id}\n`;
|
||||
if (servico.valorMensal) message += ` 💰 Valor: R$ ${servico.valorMensal}\n`;
|
||||
message += `\n`;
|
||||
|
||||
// Adicionar botão para seleção direta
|
||||
buttons.push([{
|
||||
text: `${index + 1}. ${servico.nome}`,
|
||||
callback_data: `suporte_servico_${index}`
|
||||
}]);
|
||||
});
|
||||
|
||||
message += `Selecione o serviço clicando no botão ou digite o **número** (1-${session.dados.servicos.length}):`;
|
||||
|
||||
const keyboard = {
|
||||
inline_keyboard: buttons
|
||||
};
|
||||
|
||||
await this.bot.sendMessage(session.chatId, message, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: keyboard
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 4: Selecionar categoria
|
||||
*/
|
||||
async processarEtapaSelecionarCategoria(sessionId, input = null) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
if (!input) {
|
||||
// Primeira vez nesta etapa - buscar categorias
|
||||
await this.bot.sendMessage(session.chatId, `🔍 Buscando categorias de suporte...`);
|
||||
|
||||
try {
|
||||
const resultado = await this.topsapp.obterSuporteCategorias();
|
||||
|
||||
console.log(`🔍 Handler - Resultado categorias:`, {
|
||||
success: resultado.success,
|
||||
dataType: typeof resultado.data,
|
||||
dataLength: resultado.data?.dados?.length,
|
||||
error: resultado.error
|
||||
});
|
||||
|
||||
if (!resultado.success) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao buscar categorias**\n\n` +
|
||||
`⚠️ ${resultado.error}\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultado.data?.dados || resultado.data.dados.length === 0) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Nenhuma categoria encontrada**\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.categorias = resultado.data.dados;
|
||||
await this.mostrarOpcoesCategorias(session);
|
||||
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao buscar categorias**\n\n` +
|
||||
`⚠️ ${error.message}\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
}
|
||||
} else {
|
||||
// Usuário selecionou uma categoria
|
||||
const numero = parseInt(input.trim());
|
||||
|
||||
if (isNaN(numero) || numero < 1 || numero > session.dados.categorias.length) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Número inválido**\n\n` +
|
||||
`Por favor, digite um número entre 1 e ${session.dados.categorias.length}:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.categoriaSelecionada = session.dados.categorias[numero - 1];
|
||||
session.etapa = 'selecionar_tecnico';
|
||||
await this.processarEtapaSelecionarTecnico(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostrar opções de categorias
|
||||
*/
|
||||
async mostrarOpcoesCategorias(session) {
|
||||
let message = `📁 **Categorias de suporte:**\n\n`;
|
||||
|
||||
// Verificar se categorias é um array válido
|
||||
if (!Array.isArray(session.dados.categorias)) {
|
||||
console.error(`❌ session.dados.categorias não é um array:`, {
|
||||
type: typeof session.dados.categorias,
|
||||
value: session.dados.categorias
|
||||
});
|
||||
throw new Error(`Dados de categorias inválidos: ${typeof session.dados.categorias}`);
|
||||
}
|
||||
|
||||
session.dados.categorias.forEach((categoria, index) => {
|
||||
message += `**${index + 1}.** ${categoria.descricao}\n`;
|
||||
});
|
||||
|
||||
message += `\nDigite o **número** da categoria do suporte (1-${session.dados.categorias.length}):`;
|
||||
|
||||
await this.bot.sendMessage(session.chatId, message, { parse_mode: 'Markdown' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 5: Selecionar técnico
|
||||
*/
|
||||
async processarEtapaSelecionarTecnico(sessionId, input = null) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
if (!input) {
|
||||
// Primeira vez nesta etapa - buscar técnicos
|
||||
await this.bot.sendMessage(session.chatId, `🔍 Buscando técnicos disponíveis...`);
|
||||
|
||||
try {
|
||||
// Tentar obter técnicos primeiro, se falhar, usar operadores
|
||||
let resultado = await this.topsapp.obterTecnicos();
|
||||
|
||||
if (!resultado.success || !resultado.data || resultado.data.length === 0) {
|
||||
// Fallback para operadores
|
||||
resultado = await this.topsapp.obterOperadores();
|
||||
}
|
||||
|
||||
if (!resultado.success) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao buscar técnicos**\n\n` +
|
||||
`⚠️ ${resultado.error}\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultado.data?.dados || resultado.data.dados.length === 0) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Nenhum técnico encontrado**\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.tecnicos = resultado.data.dados;
|
||||
await this.mostrarOpcoesTecnicos(session);
|
||||
|
||||
} catch (error) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao buscar técnicos**\n\n` +
|
||||
`⚠️ ${error.message}\n\n` +
|
||||
`🔄 Reiniciando processo...`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
}
|
||||
} else {
|
||||
// Usuário selecionou um técnico
|
||||
const numero = parseInt(input.trim());
|
||||
|
||||
if (isNaN(numero) || numero < 1 || numero > session.dados.tecnicos.length) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Número inválido**\n\n` +
|
||||
`Por favor, digite um número entre 1 e ${session.dados.tecnicos.length}:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.tecnicoSelecionado = session.dados.tecnicos[numero - 1];
|
||||
session.etapa = 'definir_data_hora';
|
||||
await this.processarEtapaDefinirDataHora(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostrar opções de técnicos
|
||||
*/
|
||||
async mostrarOpcoesTecnicos(session) {
|
||||
let message = `👨🔧 **Técnicos disponíveis:**\n\n`;
|
||||
|
||||
// Validar se técnicos é um array
|
||||
if (!Array.isArray(session.dados.tecnicos)) {
|
||||
console.error(`❌ session.dados.tecnicos não é um array:`, {
|
||||
type: typeof session.dados.tecnicos,
|
||||
value: session.dados.tecnicos
|
||||
});
|
||||
throw new Error(`Dados de técnicos inválidos: ${typeof session.dados.tecnicos}`);
|
||||
}
|
||||
|
||||
session.dados.tecnicos.forEach((tecnico, index) => {
|
||||
message += `**${index + 1}.** ${tecnico.nome || tecnico.tecnico}\n`;
|
||||
if (tecnico.email) message += ` 📧 ${tecnico.email}\n`;
|
||||
message += `\n`;
|
||||
});
|
||||
|
||||
message += `Digite o **número** do técnico responsável (1-${session.dados.tecnicos.length}):`;
|
||||
|
||||
await this.bot.sendMessage(session.chatId, message, { parse_mode: 'Markdown' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 6: Definir data e hora
|
||||
*/
|
||||
async processarEtapaDefinirDataHora(sessionId, input = null) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
if (!input) {
|
||||
// Primeira vez nesta etapa
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`📅 **Data e horário para visita**\n\n` +
|
||||
`Digite quando você gostaria que o técnico fizesse a visita.\n\n` +
|
||||
`**Exemplos:**\n` +
|
||||
`• "amanhã às 14h"\n` +
|
||||
`• "sexta-feira 09:00"\n` +
|
||||
`• "15/08 às 16h30"\n` +
|
||||
`• "hoje 18h"\n` +
|
||||
`• "em 3 dias às 10h"\n\n` +
|
||||
`📝 Digite a data e horário:`,
|
||||
{ parse_mode: 'Markdown' }
|
||||
);
|
||||
} else {
|
||||
// Processar texto de data/hora
|
||||
const resultado = this.dateProcessor.processarTexto(input);
|
||||
|
||||
if (!resultado.success) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Não consegui entender a data/hora**\n\n` +
|
||||
`⚠️ ${resultado.error}\n\n` +
|
||||
`**Exemplos válidos:**\n` +
|
||||
`• "amanhã às 14h"\n` +
|
||||
`• "sexta-feira 09:00"\n` +
|
||||
`• "15/08 às 16h30"\n\n` +
|
||||
`Por favor, tente novamente:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Verificar se a data não é no passado
|
||||
if (resultado.data < new Date()) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Data no passado**\n\n` +
|
||||
`A data especificada (${this.dateProcessor.formatarData(resultado.data)}) já passou.\n\n` +
|
||||
`Por favor, especifique uma data futura:`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.dataHora = resultado.data;
|
||||
session.dados.dataHoraTexto = input;
|
||||
session.etapa = 'adicionar_descricao';
|
||||
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`✅ **Data/hora confirmada:**\n${this.dateProcessor.formatarData(resultado.data)}\n\n` +
|
||||
`📝 **Última etapa:** Descrição do problema\n\n` +
|
||||
`Digite uma descrição detalhada do problema ou serviço que precisa ser realizado:`,
|
||||
{ parse_mode: 'Markdown' }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Etapa 7: Adicionar descrição
|
||||
*/
|
||||
async processarEtapaAdicionarDescricao(sessionId, descricao) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
if (!descricao || descricao.trim().length < 10) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Descrição muito curta**\n\n` +
|
||||
`Por favor, forneça uma descrição mais detalhada (mínimo 10 caracteres):`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
session.dados.descricao = descricao.trim();
|
||||
|
||||
// Mostrar resumo e confirmar
|
||||
await this.mostrarResumoSuporte(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostrar resumo do suporte antes de criar
|
||||
*/
|
||||
async mostrarResumoSuporte(session) {
|
||||
const dados = session.dados;
|
||||
|
||||
let resumo = `📋 **Resumo do Suporte**\n\n`;
|
||||
resumo += `👤 **Cliente:** ${dados.clienteSelecionado.nome}\n`;
|
||||
resumo += `🆔 **ID Cliente:** ${dados.clienteSelecionado.id}\n`;
|
||||
resumo += `📋 **Serviço:** ${dados.servicoSelecionado.descricao || dados.servicoSelecionado.plano}\n`;
|
||||
resumo += `🆔 **ID Serviço:** ${dados.servicoSelecionado.id}\n`;
|
||||
resumo += `📁 **Categoria:** ${dados.categoriaSelecionada.descricao}\n`;
|
||||
resumo += `👨🔧 **Técnico:** ${dados.tecnicoSelecionado.nome || dados.tecnicoSelecionado.tecnico}\n`;
|
||||
resumo += `📅 **Data/Hora:** ${this.dateProcessor.formatarData(dados.dataHora)}\n`;
|
||||
resumo += `📝 **Descrição:** ${dados.descricao}\n\n`;
|
||||
resumo += `Confirma a abertura do suporte? (sim/não)`;
|
||||
|
||||
await this.bot.sendMessage(session.chatId, resumo, { parse_mode: 'Markdown' });
|
||||
|
||||
session.etapa = 'confirmar';
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizar criação do suporte
|
||||
*/
|
||||
async finalizarCriacaoSuporte(sessionId, confirmacao) {
|
||||
const session = this.suporteSessions.get(sessionId);
|
||||
if (!session) return;
|
||||
|
||||
const confirmar = confirmacao.toLowerCase().trim();
|
||||
|
||||
if (!['sim', 's', 'yes', 'y', 'confirmar', 'ok'].includes(confirmar)) {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Suporte cancelado**\n\n` +
|
||||
`O processo foi cancelado. Use o comando "abrir suporte" para tentar novamente.`
|
||||
);
|
||||
this.suporteSessions.delete(sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.bot.sendMessage(session.chatId, `⏳ Criando suporte...`);
|
||||
|
||||
try {
|
||||
const dados = session.dados;
|
||||
const dadosSuporte = {
|
||||
idCliente: dados.clienteSelecionado.id,
|
||||
idServico: dados.servicoSelecionado.id,
|
||||
idCategoria: dados.categoriaSelecionada.id,
|
||||
contato: dados.clienteSelecionado.nome,
|
||||
contatoTelefone: dados.clienteSelecionado.telefone || '',
|
||||
descricao: `${dados.descricao}\n\nData/Hora agendada: ${this.dateProcessor.formatarData(dados.dataHora)}\nTécnico: ${dados.tecnicoSelecionado.nome || dados.tecnicoSelecionado.tecnico}`,
|
||||
outrasInformacoes: `Criado via Bot Telegram\nData original: ${dados.dataHoraTexto}`
|
||||
};
|
||||
|
||||
const resultado = await this.topsapp.adicionarSuporte(dadosSuporte);
|
||||
|
||||
if (resultado.success) {
|
||||
const protocolo = resultado.data?.protocolo || 'N/A';
|
||||
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`✅ **Suporte criado com sucesso!**\n\n` +
|
||||
`🎫 **Protocolo:** ${protocolo}\n` +
|
||||
`👤 **Cliente:** ${dados.clienteSelecionado.nome}\n` +
|
||||
`📋 **Serviço:** ${dados.servicoSelecionado.descricao || dados.servicoSelecionado.plano}\n` +
|
||||
`📁 **Categoria:** ${dados.categoriaSelecionada.descricao}\n` +
|
||||
`👨🔧 **Técnico:** ${dados.tecnicoSelecionado.nome || dados.tecnicoSelecionado.tecnico}\n` +
|
||||
`📅 **Data/Hora:** ${this.dateProcessor.formatarData(dados.dataHora)}\n\n` +
|
||||
`🎯 O suporte foi registrado no sistema!`,
|
||||
{ parse_mode: 'Markdown' }
|
||||
);
|
||||
|
||||
logger.info('Suporte criado via bot', {
|
||||
protocolo,
|
||||
cliente: dados.clienteSelecionado.nome,
|
||||
usuario: session.userId
|
||||
});
|
||||
} else {
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao criar suporte**\n\n` +
|
||||
`⚠️ ${resultado.error}\n\n` +
|
||||
`Tente novamente mais tarde.`
|
||||
);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Erro ao criar suporte:', error);
|
||||
await this.bot.sendMessage(session.chatId,
|
||||
`❌ **Erro ao criar suporte**\n\n` +
|
||||
`⚠️ ${error.message}\n\n` +
|
||||
`Tente novamente mais tarde.`
|
||||
);
|
||||
}
|
||||
|
||||
// Limpar sessão
|
||||
this.suporteSessions.delete(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BotHandler;
|
||||
Reference in new issue
Block a user