From db140a328c36949f996eb6da90551acab5c679ee Mon Sep 17 00:00:00 2001 From: adriano Date: Tue, 20 Feb 2024 12:33:36 -0300 Subject: [PATCH] feat: Enable direct transfer of tickets to agent via WhatsApp user input --- backend/src/helpers/OmnhitDashboardSession.ts | 6 +- backend/src/helpers/RedisClient.ts | 18 ++- backend/src/server.ts | 10 +- .../ListWhatsappQueuesByUserQueue.ts | 37 +++++ .../WbotServices/wbotMessageListener.ts | 147 ++++++++++++------ 5 files changed, 164 insertions(+), 54 deletions(-) create mode 100644 backend/src/services/UserServices/ListWhatsappQueuesByUserQueue.ts diff --git a/backend/src/helpers/OmnhitDashboardSession.ts b/backend/src/helpers/OmnhitDashboardSession.ts index 075501a..3b49843 100644 --- a/backend/src/helpers/OmnhitDashboardSession.ts +++ b/backend/src/helpers/OmnhitDashboardSession.ts @@ -15,9 +15,9 @@ async function omnihitDashboardSession(data: any) { } ); } catch (error) { - console.log( - `Post request error to ${process.env.URL_DASHBOARD_SESSIONS}/api/v1/omnihit/monitor` - ); + // console.log( + // `Post request error to ${process.env.URL_DASHBOARD_SESSIONS}/api/v1/omnihit/monitor` + // ); } } diff --git a/backend/src/helpers/RedisClient.ts b/backend/src/helpers/RedisClient.ts index 5d96368..30d6fc0 100644 --- a/backend/src/helpers/RedisClient.ts +++ b/backend/src/helpers/RedisClient.ts @@ -8,15 +8,29 @@ type WhatsappData = { value?: string; }; -export async function set(key: string, value: string) { +export async function set(key: string, value: string | object) { await redis.set(key, JSON.stringify(value)); } -export async function get(key: string) { +export async function get(key: string) { const value: any = await redis.get(key); return JSON.parse(value); } +export async function findByContain() { + // const keys = await redis.keys("*" + substring + "*"); + const keys = await redis.keys("user:*"); + + const results: any[] = []; + for (const key of keys) { + const value = await redis.get(key); + if (value) { + results.push(JSON.parse(value)); + } + } + return results; +} + export async function createObject({ whatsappId, contactId, diff --git a/backend/src/server.ts b/backend/src/server.ts index 2845f75..b3b687b 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -23,6 +23,7 @@ import fs from "fs"; import dir from "path"; import { getSettingValue } from "./helpers/WhaticketSettings"; import loadSettings from "./helpers/LoadSettings"; +import { set } from "./helpers/RedisClient"; const server = app.listen(process.env.PORT, () => { logger.info(`Server started on port: ${process.env.PORT}`); @@ -43,11 +44,18 @@ gracefulShutdown(server); (async () => { console.log("os.tmpdir(): ", os.tmpdir()); + const users = await User.findAll(); + + for (const user of users) { + const { id, name } = user; + await set(`user:${id}:${name.toLowerCase()}`, { id, name }); + } + loadSettings(); let whatsapps: any = await Whatsapp.findAll({ attributes: ["id", "url", "phoneNumberId"] - }); + }); if (whatsapps && whatsapps.length > 0) { for (let i = 0; i < whatsapps.length; i++) { diff --git a/backend/src/services/UserServices/ListWhatsappQueuesByUserQueue.ts b/backend/src/services/UserServices/ListWhatsappQueuesByUserQueue.ts new file mode 100644 index 0000000..9c68e32 --- /dev/null +++ b/backend/src/services/UserServices/ListWhatsappQueuesByUserQueue.ts @@ -0,0 +1,37 @@ +import { Op, Sequelize } from "sequelize"; +import Whatsapp from "../../models/Whatsapp"; +import WhatsappQueue from "../../models/WhatsappQueue"; +import { List } from "whatsapp-web.js"; +import UserQueue from "../../models/UserQueue"; +import Queue from "../../models/Queue"; +const dbConfig = require("../../config/database"); +const { QueryTypes } = require("sequelize"); + +const sequelize = new Sequelize(dbConfig); + +const ListWhatsappQueuesByUserQueue = async (userId: string | number) => { + try { + let userQueue: any = await UserQueue.findAll({ + where: { userId }, + attributes: ["queueId"], + raw: true + }); + + if (userQueue && userQueue.length > 0) { + userQueue = userQueue.map((u: any) => u.queueId); + + const result = await sequelize.query( + `select w.id, w.number, wq.whatsappId, wq.queueId, q.id, q.name from WhatsappQueues wq join Queues q on +wq.queueId = q.id join Whatsapps w +on wq.whatsappId = w.id where q.id in (${userQueue.join()})`, + { type: QueryTypes.SELECT } + ); + return result; + } + } catch (error) { + console.error("Error fetching joined data:", error); + } + return []; +}; + +export default ListWhatsappQueuesByUserQueue; diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 8d60993..309a4ce 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -83,14 +83,21 @@ import AppError from "../../errors/AppError"; import { setMessageAsRead } from "../../helpers/SetMessageAsRead"; import { getSettingValue } from "../../helpers/WhaticketSettings"; -import { Op } from "sequelize"; +import { Op, json } from "sequelize"; import SettingTicket from "../../models/SettingTicket"; import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase"; import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber"; -import { createObject, findObject, get } from "../../helpers/RedisClient"; -import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot" -import ShowTicketService from "../TicketServices/ShowTicketService" +import { + createObject, + findByContain, + findObject, + get +} from "../../helpers/RedisClient"; +import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot"; +import ShowTicketService from "../TicketServices/ShowTicketService"; +import ShowQueuesByUser from "../UserServices/ShowQueuesByUser"; +import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue"; var lst: any[] = getWhatsappIds(); @@ -504,13 +511,10 @@ const transferTicket = async (queueName: any, wbot: any, ticket: Ticket) => { const queues = queuesWhatsGreetingMessage.queues; - // console.log("queues ---> ", console.log(JSON.stringify(queues, null, 6))); - if (typeof queueName == "string") { queue = queues.find( (q: any) => q?.name?.toLowerCase() == queueName.trim().toLowerCase() ); - // await deleteObject(wbot.id, `${ticket.contactId}`, "ura"); } else if (typeof queueName == "number") { queue = queues[queueName]; } @@ -527,6 +531,21 @@ const botTransferTicket = async (queues: Queue, ticket: Ticket) => { }); }; +const botTransferTicketToUser = async ( + userId: number, + ticket: Ticket, + queueId?: number | undefined +) => { + console.log("USER ID: ", userId); + + // await ticket.update({ userId: userId }); + + await UpdateTicketService({ + ticketData: { status: "open", userId, queueId }, + ticketId: ticket.id + }); +}; + const botSendMessage = (ticket: Ticket, msg: string) => { const { phoneNumberId } = ticket; @@ -665,39 +684,38 @@ const handleMessage = async ( ) return; - let ticket; + let ticket; - const _botInfo = await BotIsOnQueue("botqueue"); + const _botInfo = await BotIsOnQueue("botqueue"); - if (_botInfo.isOnQueue) { - let ticket_obj: any = await FindOrCreateTicketServiceBot( - contact, - wbot.id!, - unreadMessages - // groupContact - ); + if (_botInfo.isOnQueue) { + let ticket_obj: any = await FindOrCreateTicketServiceBot( + contact, + wbot.id!, + unreadMessages + // groupContact + ); - ticket = ticket_obj.ticket; + ticket = ticket_obj.ticket; - if (ticket_obj.created) { - let queue = await ShowQueueService(_botInfo.botQueueId); + if (ticket_obj.created) { + let queue = await ShowQueueService(_botInfo.botQueueId); - await UpdateTicketService({ - ticketData: { queueId: queue.id }, - ticketId: ticket.id - }); + await UpdateTicketService({ + ticketData: { queueId: queue.id }, + ticketId: ticket.id + }); - ticket = await ShowTicketService(ticket.id); - } - } else { - ticket = await FindOrCreateTicketService( - contact, - wbot.id!, - unreadMessages - // groupContact - ); - } - + ticket = await ShowTicketService(ticket.id); + } + } else { + ticket = await FindOrCreateTicketService( + contact, + wbot.id!, + unreadMessages + // groupContact + ); + } if (getSettingValue("oneContactChatWithManyWhats")?.value == "disabled") { // Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen @@ -768,21 +786,54 @@ const handleMessage = async ( } else { console.log("MSG body: ", msg.body); - if (msg.type != "chat") { - botSendMessage( - ticket, - `Desculpe, nao compreendi!\nEnvie apenas texto quando estiver interagindo com o bot!\n _Digite *0* para voltar ao menu principal._` - ); - return; - } + if (msg.type != "chat") { + botSendMessage( + ticket, + `Desculpe, nao compreendi!\nEnvie apenas texto quando estiver interagindo com o bot!\n _Digite *0* para voltar ao menu principal._` + ); + return; + } - if (msg.type == "chat" && String(msg.body).length > 120) { - botSendMessage( - ticket, - `Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para voltar ao menu principal._` - ); - return; - } + if (msg.type == "chat" && String(msg.body).length > 120) { + botSendMessage( + ticket, + `Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para voltar ao menu principal._` + ); + return; + } + + // Transfer to agent + const listUser = await findByContain(); + + let filteredUsers = listUser.filter(user => + msg?.body?.trim()?.toLowerCase().includes(user.name) + ); + + if (filteredUsers && filteredUsers.length > 0) { + const whatsappQueues = await ListWhatsappQueuesByUserQueue( + +filteredUsers[0].id + ); + + const obj: any = whatsappQueues.find( + (ob: any) => ob.whatsappId == wbot.id + ); + + if (obj) { + await botTransferTicketToUser( + +filteredUsers[0].id, + ticket, + +obj.queueId + ); + + botSendMessage( + ticket, + `VocĂȘ foi transferido para falar com o agente ${filteredUsers[0].name}` + ); + } + + return; + } + // const menuMsg: any = await menu(msg.body, wbot.id, contact.id);