From 470ae863531e1a1c95407f1577fe5c2106b56b17 Mon Sep 17 00:00:00 2001 From: adriano Date: Fri, 14 Jul 2023 15:54:27 -0300 Subject: [PATCH] =?UTF-8?q?atualiza=C3=A7=C3=A3o:=20nas=20buscas,=20atribu?= =?UTF-8?q?ir=20chat=20a=20uma=20fila=20quando=20iniciada=20pelo=20atenden?= =?UTF-8?q?te.=20Controle=20para=20evitar=20loop=20infinito=20de=20bot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/controllers/HitController.ts | 318 ++++++++---------- backend/src/controllers/old_HitController.ts | 237 +++++++++++++ backend/src/helpers/MostRepeatedPhrase.ts | 58 ++++ .../helpers/whatsappQueueMatchingUserQueue.ts | 26 ++ backend/src/routes/hitRoutes.ts | 4 +- .../TicketServices/CreateTicketService.ts | 14 +- .../FindOrCreateTicketServiceBot.ts | 145 ++++++++ .../ShowTicketServiceByContactId.ts | 4 +- .../WbotServices/wbotMessageListener.ts | 144 +++++--- 9 files changed, 710 insertions(+), 240 deletions(-) create mode 100644 backend/src/controllers/old_HitController.ts create mode 100644 backend/src/helpers/MostRepeatedPhrase.ts create mode 100644 backend/src/helpers/whatsappQueueMatchingUserQueue.ts create mode 100644 backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts diff --git a/backend/src/controllers/HitController.ts b/backend/src/controllers/HitController.ts index f2e9c7b..031042f 100644 --- a/backend/src/controllers/HitController.ts +++ b/backend/src/controllers/HitController.ts @@ -14,6 +14,8 @@ import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage"; import { Op, where, Sequelize } from "sequelize"; import ShowTicketServiceByContactId from "../services/TicketServices/ShowTicketServiceByContactId"; import hitPortalMonitoring from "../helpers/HitPortalMonitoring"; +import FindOrCreateTicketServiceBot from "../services/TicketServices/FindOrCreateTicketServiceBot"; +import Contact from "../models/Contact"; // type IndexQuery = { @@ -21,217 +23,161 @@ import hitPortalMonitoring from "../helpers/HitPortalMonitoring"; // }; export const hit = async (req: Request, res: Response): Promise => { - - // const { - // centro_custo, - // } = req.body as IndexQuery; - - console.log('req.boy: ', req.body) - console.log('req.boy: ', req.body['centro_custo']) - console.log('ACTION: ', req.body['action']) - - if (req.headers["auth"] === '0424bd59b807674191e7d77572075f33') { - - let contact = null - - try { - - contact = await ContactByCustomField(req.body['centro_custo']) - - } catch (error) { - - console.log('There was an error on try get centro_custo info: ', error) - - } - if (req.body['action'] === 'atdfechou') { + console.log('req.body: ', req.body) - console.log('FECHOU') + if (req.headers["auth"] === '0424bd59b807674191e7d77572075f33') { - try { - - console.log('atdfechou ----------> THE CONTACT: ', contact) - - if (contact) { - - let data = req.body - let str = '' - let str2 = '' - - // const exclude = ["action", "centro_custo", "n_chamado_web", "historico"]; - - // for (const key in data) { - - // if (exclude.includes(`${key}`)) { - // continue - // } - - // str += `${key.replace('hostname', 'cliente')}: ${data[key]}\n` - - // } - - str = `*Cliente*: ${contact['contact.name']}` - - let historico = data['historico'] - - for (const key in historico) { - - const hist = Object.keys(historico[key]); - - hist.forEach((keys, index) => { - - str2 += `*${keys}*: ${historico[key][keys]}\n` - - }); - - str2 += '\n' - - } - - console.log('--------------> str: ', str) - console.log('--------------> str2: ', str2) - - const botInfo = await BotIsOnQueue('botqueue') - - let ticket = await ShowTicketServiceByContactId(contact['contact.id']) - - if (ticket.id && ticket.status == 'pending') { - - await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, ticket); - - } - else if (!ticket.id) { - - ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot }); - - console.log('botInfo.botQueueId: ', botInfo.botQueueId) - - await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id }); - - await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, ticket); - - - } - - } - - } catch (error) { - - console.log(`Error on try sending the monitor message closed: `, error) - - } - } - else if (req.body['action'] === 'atdatualizou') { - - console.log('status: atdatualizou --------------> contact: ', contact) - - if (contact) { + let contact = null try { - let response = await hitPortalMonitoring(req.body['centro_custo']) - - if (!response || response.length == 0) { - console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo']) - return res.status(200).json({ "message": "Ok" }); - } - - const botInfo = await BotIsOnQueue('botqueue') - - let ticket = await ShowTicketServiceByContactId(contact['contact.id']) - - if (ticket.id && ticket.status == 'pending') { - - await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); - - } - else if (!ticket.id) { - - ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot }); - - console.log('botInfo.botQueueId: ', botInfo.botQueueId) - - await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id }); - - await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); - - } - + contact = await ContactByCustomField(req.body['centro_custo']) } catch (error) { - console.log(`Error on try sending the message monitor: `, error) + console.log('There was an error on try get centro_custo info: ', error) } - } + if (!contact) { + return res.status(200).json({ "message": "Ok" }); + } + + + if (req.body['action'] === 'atdfechou') { + + console.log('FECHOU') + + try { + + console.log('atdfechou ----------> THE CONTACT: ', contact) + + + let data = req.body + let str = '' + let str2 = '' + + str = `*Cliente*: ${contact['contact.name']}` + + let historico = data['historico'] + + for (const key in historico) { + + const hist = Object.keys(historico[key]); + + hist.forEach((keys, index) => { + + str2 += `*${keys}*: ${historico[key][keys]}\n` + + }); + + str2 += '\n' + + } + + await statuschange(req, res, contact, `*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, false) + + } catch (error) { + + console.log(`Error on try sending the monitor message closed: `, error) + + } + + + } + else if (req.body['action'] === 'atdatualizou') { + + console.log('status: atdatualizou --------------> contact: ', contact) + + await statuschange(req, res, contact, `*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n`) + + } + else if (req.body['action'] === 'atdabriu') { + + await statuschange(req, res, contact, `*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n`) + + } } else { - - console.log('status: atdatabriu --------------> contact: ', contact) - - if (contact) { - - try { - - let response = await hitPortalMonitoring(req.body['centro_custo']) - - if (!response || response.length == 0) { - console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo']) - return res.status(200).json({ "message": "Ok" }); - } - - const botInfo = await BotIsOnQueue('botqueue') - - let ticket = await ShowTicketServiceByContactId(contact['contact.id']) - - if (ticket.id && ticket.status == 'pending') { - - await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); - - } - else if (!ticket.id) { - - ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot }); - - console.log('botInfo.botQueueId: ', botInfo.botQueueId) - - await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id }); - - await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); - - } - - - } catch (error) { - - console.log(`Error on try sending the message monitor: `, error) - - } - - } - + res.status(401).json({ "message": "Token Inválido!" }); } - } - else { - res.status(401).json({ "message": "Token Inválido!" }); - } - - return res.status(200).json({ "message": "Ok" }); + return res.status(200).json({ "message": "Ok" }); }; async function sendMessageHitMonitoring(msg: string, ticket: Ticket) { - if (msg && msg.length > 0) { + if (msg && msg.length > 0) { - console.log('MESSAGE WILL BE SENT!') + console.log('MESSAGE WILL BE SENT!') - await SendWhatsAppMessage({ body: msg, ticket }); + await SendWhatsAppMessage({ body: msg, ticket }); - } + } } + +async function statuschange(req: Request, res: Response, contact: any, header_msg: string, request: boolean = true) { + try { + + const botInfo = await BotIsOnQueue('botqueue') + + let ticket: any = await ShowTicketServiceByContactId(contact.contactId) + + if (!ticket.dataValues.id) { + + const defaultWhatsapp = await GetDefaultWhatsApp(); + + let _contact: any = await Contact.findByPk(contact.contactId) + + let ticket_obj: any = await FindOrCreateTicketServiceBot( + _contact, + defaultWhatsapp.id!, + 0, + ); + + ticket = ticket_obj.ticket + } + + let _response: string + + if (request) { + let response = await hitPortalMonitoring(req.body['centro_custo']) + + if (!response || response.length == 0) { + console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo']) + return + } + + _response = `${header_msg} *Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}` + } + else { + _response = header_msg + } + + if (ticket.id && ticket.status == 'pending') { + + await sendMessageHitMonitoring(_response, ticket); + + } + else if (ticket.id && ticket.userId == botInfo.userIdBot) { + + let queue = await ShowQueueService(botInfo.botQueueId); + + await UpdateTicketService({ ticketData: { queueId: queue.id }, ticketId: ticket.id }); + + ticket = await ShowTicketService(ticket.id); + + await sendMessageHitMonitoring(_response, ticket); + } + + } catch (error) { + + console.log(`Error on try sending the message monitor: `, error) + + } +} \ No newline at end of file diff --git a/backend/src/controllers/old_HitController.ts b/backend/src/controllers/old_HitController.ts new file mode 100644 index 0000000..f2e9c7b --- /dev/null +++ b/backend/src/controllers/old_HitController.ts @@ -0,0 +1,237 @@ +import { Request, Response } from "express"; +import BotIsOnQueue from "../helpers/BotIsOnQueue"; +import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp"; +import { getIO } from "../libs/socket"; +import { getWbot } from "../libs/wbot"; +import Ticket from "../models/Ticket"; +import ContactByCustomField from "../services/HitServices/ShowContactByCustomFieldValueService"; +import ShowQueueService from "../services/QueueService/ShowQueueService"; +import CreateTicketService from "../services/TicketServices/CreateTicketService"; +import ShowTicketService from "../services/TicketServices/ShowTicketService"; +import UpdateTicketService from "../services/TicketServices/UpdateTicketService"; +import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage"; + +import { Op, where, Sequelize } from "sequelize"; +import ShowTicketServiceByContactId from "../services/TicketServices/ShowTicketServiceByContactId"; +import hitPortalMonitoring from "../helpers/HitPortalMonitoring"; + + +// type IndexQuery = { +// centro_custo: string; +// }; + +export const hit = async (req: Request, res: Response): Promise => { + + // const { + // centro_custo, + // } = req.body as IndexQuery; + + console.log('req.boy: ', req.body) + console.log('req.boy: ', req.body['centro_custo']) + console.log('ACTION: ', req.body['action']) + + if (req.headers["auth"] === '0424bd59b807674191e7d77572075f33') { + + let contact = null + + try { + + contact = await ContactByCustomField(req.body['centro_custo']) + + } catch (error) { + + console.log('There was an error on try get centro_custo info: ', error) + + } + + + if (req.body['action'] === 'atdfechou') { + + console.log('FECHOU') + + try { + + console.log('atdfechou ----------> THE CONTACT: ', contact) + + if (contact) { + + let data = req.body + let str = '' + let str2 = '' + + // const exclude = ["action", "centro_custo", "n_chamado_web", "historico"]; + + // for (const key in data) { + + // if (exclude.includes(`${key}`)) { + // continue + // } + + // str += `${key.replace('hostname', 'cliente')}: ${data[key]}\n` + + // } + + str = `*Cliente*: ${contact['contact.name']}` + + let historico = data['historico'] + + for (const key in historico) { + + const hist = Object.keys(historico[key]); + + hist.forEach((keys, index) => { + + str2 += `*${keys}*: ${historico[key][keys]}\n` + + }); + + str2 += '\n' + + } + + console.log('--------------> str: ', str) + console.log('--------------> str2: ', str2) + + const botInfo = await BotIsOnQueue('botqueue') + + let ticket = await ShowTicketServiceByContactId(contact['contact.id']) + + if (ticket.id && ticket.status == 'pending') { + + await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, ticket); + + } + else if (!ticket.id) { + + ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot }); + + console.log('botInfo.botQueueId: ', botInfo.botQueueId) + + await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id }); + + await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, ticket); + + + } + + } + + } catch (error) { + + console.log(`Error on try sending the monitor message closed: `, error) + + } + } + else if (req.body['action'] === 'atdatualizou') { + + console.log('status: atdatualizou --------------> contact: ', contact) + + if (contact) { + + try { + + let response = await hitPortalMonitoring(req.body['centro_custo']) + + if (!response || response.length == 0) { + console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo']) + return res.status(200).json({ "message": "Ok" }); + } + + const botInfo = await BotIsOnQueue('botqueue') + + let ticket = await ShowTicketServiceByContactId(contact['contact.id']) + + if (ticket.id && ticket.status == 'pending') { + + await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); + + } + else if (!ticket.id) { + + ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot }); + + console.log('botInfo.botQueueId: ', botInfo.botQueueId) + + await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id }); + + await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); + + } + + + } catch (error) { + + console.log(`Error on try sending the message monitor: `, error) + + } + + } + + } + else { + + console.log('status: atdatabriu --------------> contact: ', contact) + + if (contact) { + + try { + + let response = await hitPortalMonitoring(req.body['centro_custo']) + + if (!response || response.length == 0) { + console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo']) + return res.status(200).json({ "message": "Ok" }); + } + + const botInfo = await BotIsOnQueue('botqueue') + + let ticket = await ShowTicketServiceByContactId(contact['contact.id']) + + if (ticket.id && ticket.status == 'pending') { + + await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); + + } + else if (!ticket.id) { + + ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot }); + + console.log('botInfo.botQueueId: ', botInfo.botQueueId) + + await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id }); + + await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket); + + } + + + } catch (error) { + + console.log(`Error on try sending the message monitor: `, error) + + } + + } + + } + + } + else { + res.status(401).json({ "message": "Token Inválido!" }); + } + + + return res.status(200).json({ "message": "Ok" }); +}; + +async function sendMessageHitMonitoring(msg: string, ticket: Ticket) { + + if (msg && msg.length > 0) { + + console.log('MESSAGE WILL BE SENT!') + + await SendWhatsAppMessage({ body: msg, ticket }); + + } + +} diff --git a/backend/src/helpers/MostRepeatedPhrase.ts b/backend/src/helpers/MostRepeatedPhrase.ts new file mode 100644 index 0000000..b1e0bc0 --- /dev/null +++ b/backend/src/helpers/MostRepeatedPhrase.ts @@ -0,0 +1,58 @@ +import { subSeconds } from "date-fns"; +import Message from "../models/Message"; + +import { Op, Sequelize } from "sequelize"; + +const mostRepeatedPhrase = async (ticketId: number | string, fromMe: boolean = false) => { + + let res: any = { body: '', occurrences: 0 } + + try { + const mostRepeatedPhrase: any = await Message.findOne({ + where: { + ticketId: ticketId, + fromMe: fromMe ? fromMe : 0, + body: { + [Op.notRegexp]: '^[0-9]+$', + }, + updatedAt: { + [Op.between]: [+subSeconds(new Date(), 150), +new Date()], + }, + }, + attributes: [ + 'body', + [Sequelize.fn('COUNT', Sequelize.col('body')), 'occurrences'], + ], + + group: ['body'], + order: [[Sequelize.literal('occurrences'), 'DESC']], + limit: 1, + }); + + if (mostRepeatedPhrase) { + + const { body, occurrences } = mostRepeatedPhrase.get(); + + console.log(`The most repeated phrase is "${body}" with ${occurrences} occurrences.`); + + const isNumber = /^\d+$/.test(body.trim()); + + if (!isNumber) { + + return { body, occurrences } + } + + + } else { + console.log('No phrases found.'); + } + } catch (error) { + console.log('error on MostRepeatedPhrase: ', error) + } + + + + return { body: '', occurrences: 0 } +} + +export default mostRepeatedPhrase; \ No newline at end of file diff --git a/backend/src/helpers/whatsappQueueMatchingUserQueue.ts b/backend/src/helpers/whatsappQueueMatchingUserQueue.ts new file mode 100644 index 0000000..af54cd5 --- /dev/null +++ b/backend/src/helpers/whatsappQueueMatchingUserQueue.ts @@ -0,0 +1,26 @@ +import Whatsapp from "../models/Whatsapp"; +import ShowQueuesByUser from "../services/UserServices/ShowQueuesByUser"; +import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService"; + +async function whatsappQueueMatchingUserQueue(userId: number, whatsapp: Whatsapp, userProfile: string = 'user') { + + const userQueues = await ShowQueuesByUser({ profile: userProfile, userId: userId }); + + if (!userQueues || userQueues && userQueues.length == 0) return + + // console.log('-----> userQueues: ', userQueues); + + let whats: any = await ShowWhatsAppService(whatsapp.id); + + if (!whats.queues || whats.queues && whats.queues.length == 0) return + + const whatsappQueues = whats.queues.map((e: any) => e.dataValues.name); + + // console.log('-----> whatsappQueues: ', whatsappQueues); + + const matchingQueue = userQueues.find(queue => whatsappQueues.includes(queue.name)); + + return matchingQueue +} + +export default whatsappQueueMatchingUserQueue \ No newline at end of file diff --git a/backend/src/routes/hitRoutes.ts b/backend/src/routes/hitRoutes.ts index 1c47bfb..ad59ec0 100644 --- a/backend/src/routes/hitRoutes.ts +++ b/backend/src/routes/hitRoutes.ts @@ -1,6 +1,6 @@ import express from "express"; - -import * as HitController from "../controllers/HitController"; + +import * as HitController from "../controllers/HitController" const hitRoutes = express.Router(); diff --git a/backend/src/services/TicketServices/CreateTicketService.ts b/backend/src/services/TicketServices/CreateTicketService.ts index 376a90c..fbc73f6 100644 --- a/backend/src/services/TicketServices/CreateTicketService.ts +++ b/backend/src/services/TicketServices/CreateTicketService.ts @@ -14,6 +14,8 @@ import { splitDateTime } from "../../helpers/SplitDateTime"; import TicketEmiterSumOpenClosedByUser from "../../helpers/OnlineReporEmiterInfoByUser"; import { createOrUpdateTicketCache } from '../../helpers/TicketCache' +import User from "../../models/User"; +import whatsappQueueMatchingUserQueue from "../../helpers/whatsappQueueMatchingUserQueue"; let flatten = require('flat') @@ -21,14 +23,14 @@ let flatten = require('flat') interface Request { contactId: number; status: string; - userId: number; + userId: number; queueId?: number | undefined; } const CreateTicketService = async ({ contactId, status, - userId, + userId, queueId = undefined }: Request): Promise => { @@ -37,7 +39,13 @@ const CreateTicketService = async ({ try { - const defaultWhatsapp = await GetDefaultWhatsApp(userId); + const defaultWhatsapp = await GetDefaultWhatsApp(userId); + + if (!queueId) { + const user = await User.findByPk(userId, { raw: true, }) + const matchingQueue = await whatsappQueueMatchingUserQueue(userId, defaultWhatsapp, user?.profile); + queueId = matchingQueue ? matchingQueue.queueId : undefined + } await CheckContactOpenTickets(contactId); diff --git a/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts b/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts new file mode 100644 index 0000000..1592409 --- /dev/null +++ b/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts @@ -0,0 +1,145 @@ +import { subHours, subMinutes, subSeconds } from "date-fns"; +import { Op } from "sequelize"; +import BotIsOnQueue from "../../helpers/BotIsOnQueue"; +import Contact from "../../models/Contact"; +import Ticket from "../../models/Ticket"; +import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService"; +import ShowTicketService from "./ShowTicketService"; +import AppError from "../../errors/AppError"; +import { userInfo } from "os"; +import ShowQueueService from "../QueueService/ShowQueueService"; +import UpdateTicketService from "./UpdateTicketService"; + + +const FindOrCreateTicketServiceBot = async ( + contact: Contact, + whatsappId: number, + unreadMessages: number, + groupContact?: Contact +): Promise => { + + try { + + let ticket = await Ticket.findOne({ + where: { + status: { + [Op.or]: ["open", "pending", "queueChoice"] + }, + contactId: groupContact ? groupContact.id : contact.id + } + }); + + const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId); + + + //Habilitar esse caso queira usar o bot + const botInfo = await BotIsOnQueue('botqueue') + // const botInfo = { isOnQueue: false } + + + + if (ticket) { + await ticket.update({ unreadMessages }); + } + + // if (!ticket && groupContact) { + // ticket = await Ticket.findOne({ + // where: { + // contactId: groupContact.id + // }, + // order: [["updatedAt", "DESC"]] + // }); + + + + // if (ticket) { + + // await ticket.update({ + // status: "pending", + // userId: null, + // unreadMessages + // }); + // } + // } + + if (!ticket && !groupContact) { + + console.log('BOT CREATING OR REOPENING THE TICKET') + + ticket = await Ticket.findOne({ + where: { + contactId: contact.id, + userId: botInfo.userIdBot + }, + order: [["updatedAt", "DESC"]] + }); + + if (ticket) { + + await ticket.update({ + status: "open", + userId: botInfo.userIdBot, + unreadMessages + }); + + console.log('lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') + + await dialogFlowStartContext(contact, ticket, botInfo); + + } + } + + let created = false + + if (!ticket) { + + created = true + + let status = "open" + + if (queues.length > 1 && !botInfo.isOnQueue) { + status = "queueChoice" + } + + ticket = await Ticket.create({ + contactId: groupContact ? groupContact.id : contact.id, + status: status, + userId: botInfo.userIdBot, + isGroup: !!groupContact, + unreadMessages, + whatsappId + }); + + console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy') + + await dialogFlowStartContext(contact, ticket, botInfo); + + } + + ticket = await ShowTicketService(ticket.id); + + return { ticket, created }; + + } catch (error: any) { + console.error('===> Error on FindOrCreateTicketServiceBot.ts file: \n', error) + throw new AppError(error.message); + } +}; + +export default FindOrCreateTicketServiceBot; + +async function dialogFlowStartContext(contact: Contact, ticket: Ticket, botInfo: any) { + + let msg: any = { type: 'chat', from: `${contact.number}@c.us`, body: '0' }; + + let queue = await ShowQueueService(botInfo.botQueueId); + + await UpdateTicketService({ + ticketData: { queueId: queue.id }, + ticketId: ticket.id + }); + + ticket = await ShowTicketService(ticket.id); + +} + diff --git a/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts b/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts index b340d9a..5e27856 100644 --- a/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts +++ b/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts @@ -10,7 +10,7 @@ const ShowTicketServiceByContactId = async (contactId: string | number): Promise const ticket = await Ticket.findOne({ - where:{ contactId: contactId, [Op.or]: [ { status: 'open' }, { status: 'pending' }] }, + where: { contactId, [Op.or]: [{ status: 'open' }, { status: 'pending' }] }, include: [ { @@ -34,7 +34,7 @@ const ShowTicketServiceByContactId = async (contactId: string | number): Promise }); if (!ticket) { - + return new Ticket } diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 0f1208b..b64c213 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -72,6 +72,8 @@ import { getWhatsappIds, setWhatsappId } from "../../helpers/WhatsappIdMultiSess import SendWhatsAppMedia from "./SendWhatsAppMedia"; import AppError from "../../errors/AppError"; import { setMessageAsRead } from "../../helpers/SetMessageAsRead"; +import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot"; +import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase"; @@ -552,7 +554,7 @@ async function sendDelayedMessages(wbot: Session, ticket: Ticket, contact: Conta // await new Promise(f => setTimeout(f, 1000)); // // NEW - await SendWhatsAppMessage({ body: msgAction.msgBody, ticket, number: `${contact.number}@c.us` }) + await SendWhatsAppMessage({ body: msgAction.msgBody, ticket, number: `${contact.number}@c.us` }) await botSendMedia(ticket, contact, wbot, sourcePath, msgAction.actions[1]) @@ -748,14 +750,15 @@ const verifyQueue = async ( } else { + const repet: any = await mostRepeatedPhrase(ticket.id) - //test del transfere o atendimento se entrar na ura infinita - let ticket_message = await ShowTicketMessage(ticket.id, false); - if (ticket_message.length > 10) { + if (repet.occurrences > 4) { + //test del transfere o atendimento se entrar na ura infinita await UpdateTicketService({ ticketData: { status: 'pending', queueId: queues[0].id }, ticketId: ticket.id }); } + else { let options = ""; @@ -1021,7 +1024,7 @@ const handleMessage = async ( const chat = wbot.chat // if(chat.isGroup){ - + // console.log('This message is from a Group and will be ignored!') // return // } @@ -1056,12 +1059,43 @@ const handleMessage = async ( if (unreadMessages === 0 && whatsapp.farewellMessage && whatsapp.farewellMessage === msg.body) return; - const ticket = await FindOrCreateTicketService( - contact, - wbot.id!, - unreadMessages, - // groupContact - ); + let ticket + + const _botInfo = await BotIsOnQueue('botqueue') + + if (_botInfo.isOnQueue) { + + let ticket_obj: any = await FindOrCreateTicketServiceBot( + contact, + wbot.id!, + unreadMessages, + // groupContact + ); + + ticket = ticket_obj.ticket + + if (ticket_obj.created) { + + let queue = await ShowQueueService(_botInfo.botQueueId); + + await UpdateTicketService({ + ticketData: { queueId: queue.id }, + ticketId: ticket.id + }); + + ticket = await ShowTicketService(ticket.id); + } + + + } + else { + ticket = await FindOrCreateTicketService( + contact, + wbot.id!, + unreadMessages, + // groupContact + ); + } console.log('okkkkkkkkkkkkkkkkkk 1') @@ -1124,43 +1158,59 @@ const handleMessage = async ( console.log('okkkkkkkkkkkkkkkkkk 4') - // TEST DEL - let test: any = await ShowTicketMessage(ticket.id, false, true, 5); + const repet: any = await mostRepeatedPhrase(ticket.id) - console.log('okkkkkkkkkkkkkkkkkk 5 test: ', test) + console.log('repet.occurrences: ', repet.occurrences) - if (test && test.length > 0 && test[0].body.includes('Se deseja solicitar atendimento de urgência, digite *1*') && msg.body == '1') { + if (repet.occurrences > 4) { + + await transferTicket(0, wbot, ticket, contact) - console.log('===================================> ENDPOINT REQUEST') + await SendWhatsAppMessage({ + body: `Seu atendimento foi transferido para um agente!\n\nPara voltar ao menu principal digite *0* + `, ticket, number: `${contact.number}@c.us` + }) - for (let i = 0; i < test.length; i++) { - - if (test[i].body.includes('*categoria*: INFRAESTRUTURA')) { - - botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`) - - await transferTicket(0, wbot, ticket, contact) - break - - } - else if (test[i].body.includes('*categoria*: ELOS')) { - - botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`) - - await transferTicket(1, wbot, ticket, contact) - break - } - - } - - - return } - // + else { + // TEST DEL + let test: any = await ShowTicketMessage(ticket.id, false, true, 5); - console.log('okkkkkkkkkkkkkkkkkk 6') + console.log('okkkkkkkkkkkkkkkkkk 5 test: ', test) - await sendDialogflowAwswer(wbot, ticket, msg, contact, chat); + if (test && test.length > 0 && test[0].body.includes('Se deseja solicitar atendimento de urgência, digite *1*') && msg.body == '1') { + + console.log('===================================> ENDPOINT REQUEST') + + for (let i = 0; i < test.length; i++) { + + if (test[i].body.includes('*categoria*: INFRAESTRUTURA')) { + + botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`) + + await transferTicket(0, wbot, ticket, contact) + break + + } + else if (test[i].body.includes('*categoria*: ELOS')) { + + botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`) + + await transferTicket(1, wbot, ticket, contact) + break + } + + } + + + return + } + // + + console.log('okkkkkkkkkkkkkkkkkk 6') + + await sendDialogflowAwswer(wbot, ticket, msg, contact, chat); + } } else if (botInfo.isOnQueue && !msg.fromMe && msg.body == '0' && ticket.status == 'pending' && ticket.queueId) { @@ -1173,24 +1223,24 @@ const handleMessage = async ( }); const _ticket = await ShowTicketService(ticket.id); - + // const chat = await msg.getChat(); const chat = wbot.chat await sendDialogflowAwswer(wbot, _ticket, msg, contact, chat); return } - - if (msg && !msg.fromMe && ticket.status == 'pending') { - + + if (msg && !msg.fromMe && ticket.status == 'pending') { + await setMessageAsRead(ticket) } } catch (err) { Sentry.captureException(err); - logger.error(`Error handling whatsapp message: Err: ${err}`); + logger.error(`Error handling whatsapp message: Err: ${err}`); } }; @@ -1216,7 +1266,7 @@ const handleMsgAck = async (msg_id: any, ack: any) => { return; } await messageToUpdate.update({ ack }); - + io.to(messageToUpdate.ticketId.toString()).emit("appMessage", { action: "update", message: messageToUpdate