From bc93d3a9d6e90f90364096b002cbf23a6ed70759 Mon Sep 17 00:00:00 2001 From: adriano Date: Wed, 7 Feb 2024 16:36:45 -0300 Subject: [PATCH] feat: Adapt migration from Dialogflow to Redis-based bot and optimize bot access using Redis --- backend/src/controllers/HitController.ts | 176 ++++++ backend/src/controllers/MessageController.ts | 4 +- backend/src/helpers/EndpointQuery2.ts | 57 ++ backend/src/helpers/HitPortalMonitoring.ts | 68 +++ backend/src/helpers/RedisClient.ts | 17 +- backend/src/routes/hitRoutes.ts | 9 + backend/src/routes/index.ts | 2 + .../ShowContactCustomFieldsService.ts | 20 + .../ShowContactByCustomFieldValueService.ts | 27 + .../TicketServices/ShowTicketMessage2.ts | 73 +++ .../ShowTicketServiceByContactId.ts | 44 ++ .../WbotServices/wbotMessageListener.ts | 575 +++++++++++++++--- frontend/src/components/MessageInput/index.js | 38 +- 13 files changed, 1019 insertions(+), 91 deletions(-) create mode 100644 backend/src/controllers/HitController.ts create mode 100644 backend/src/helpers/EndpointQuery2.ts create mode 100644 backend/src/helpers/HitPortalMonitoring.ts create mode 100644 backend/src/routes/hitRoutes.ts create mode 100644 backend/src/services/ContactServices/ShowContactCustomFieldsService.ts create mode 100644 backend/src/services/HitServices/ShowContactByCustomFieldValueService.ts create mode 100644 backend/src/services/TicketServices/ShowTicketMessage2.ts create mode 100644 backend/src/services/TicketServices/ShowTicketServiceByContactId.ts diff --git a/backend/src/controllers/HitController.ts b/backend/src/controllers/HitController.ts new file mode 100644 index 0000000..33cbc52 --- /dev/null +++ b/backend/src/controllers/HitController.ts @@ -0,0 +1,176 @@ +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"; +import FindOrCreateTicketServiceBot from "../services/TicketServices/FindOrCreateTicketServiceBot"; +import Contact from "../models/Contact"; + +// type IndexQuery = { +// centro_custo: string; +// }; + +export const hit = async (req: Request, res: Response): Promise => { + console.log("req.body: ", req.body); + + 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 (!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") { + console.log("PASS 1"); + + 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` + ); + console.log("PASS 2"); + } + } 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 }); + } +} + +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); + + console.log("PASS 01"); + + 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; + } + + console.log("PASS 02"); + + 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; + } + + console.log("PASS 03"); + + 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); + } +} diff --git a/backend/src/controllers/MessageController.ts b/backend/src/controllers/MessageController.ts index 234d654..f41823b 100644 --- a/backend/src/controllers/MessageController.ts +++ b/backend/src/controllers/MessageController.ts @@ -60,9 +60,11 @@ export const store = async (req: Request, res: Response): Promise => { " | quotedMsg: ", quotedMsg, " | params: ", - params + params, ' | body: ', JSON.stringify(body, null, 6) ); + + const { phoneNumberId, whatsappId } = ticket; if (phoneNumberId) { diff --git a/backend/src/helpers/EndpointQuery2.ts b/backend/src/helpers/EndpointQuery2.ts new file mode 100644 index 0000000..26fc770 --- /dev/null +++ b/backend/src/helpers/EndpointQuery2.ts @@ -0,0 +1,57 @@ +const fsPromises = require("fs/promises"); +const fs = require("fs"); +import axios from "axios"; +import * as https from "https"; + +const endPointQuery = async ( + url: string, + method: string, + param: string = "" +) => { + let response: any = null; + + try { + const httpsAgent = new https.Agent({ rejectUnauthorized: false }); + + if (method == "get") { + // const url = 'https://sos.espacolaser.com.br/api/whatsapp/ticket/R32656' + response = await axios.get(url, { + httpsAgent, + headers: { + "x-access-token": + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOnsiaWQiOjEsInJvbGUiOiJjbGllbnQiLCJob3N0Ijoic29zLmVzcGFjb2xhc2VyLmNvbS5iciIsInRlbmFudCI6ImVzcGFjb2xhc2VyIiwibmFtZSI6IlNFTlNSLklUIiwiY29tcGFueSI6eyJpZCI6NDR9fSwiZGF0ZSI6MTY2MTI2MjY0MywiaWF0IjoxNjYxMjYyNjQzLCJleHAiOjE3NDc2NjI2NDN9.zf91OmRs4_C7B8OlVpLLrQMiRBYc7edP4qAdH_hqxpk", + Origin: "espacolaser" + } + }); + console.log( + `TEST URL CLIENT GET ROUTE: ${url} | STATUS CODE: ${response.status}` + ); + } else if (method == "post") { + // const url = 'http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php' + + response = await axios.post( + url, + { + auth: "0424bd59b807674191e7d77572075f33", + jsonrpc: "2.0", + method: "chamado.ematendimento", + "params[ccusto]": param, + id: "101" + }, + { + httpsAgent, + headers: { "Content-Type": "multipart/form-data" } + } + ); + console.log( + `TEST URL CLIENT POST ROUTE: ${url} | STATUS CODE: ${response.status}` + ); + } + } catch (error) { + console.error(`Erro ao consultar endpoint ${url}: ${error}`); + } + + return response; +}; + +export default endPointQuery; diff --git a/backend/src/helpers/HitPortalMonitoring.ts b/backend/src/helpers/HitPortalMonitoring.ts new file mode 100644 index 0000000..aa2d1e7 --- /dev/null +++ b/backend/src/helpers/HitPortalMonitoring.ts @@ -0,0 +1,68 @@ + +const fsPromises = require("fs/promises"); +const fs = require('fs') + +import endPointQuery2 from './EndpointQuery2' +import WhatsQueueIndex from "./WhatsQueueIndex"; + + +const hitPortalMonitoring = async (centro_de_custo: string) => { + + let msg_endpoint: any = [] + + let response2 = await endPointQuery2('http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php', 'post', centro_de_custo.trim()) + + if (response2 && response2.data.result) { + + response2 = response2.data.result; + + for (let i = 0; i < response2.length; i++) { + + let data = '' + let sub_data = '*Atualizações:*\n\n' + + const properties: any = Object.entries(response2[i]); + + for (let x = 0; x < properties.length; x++) { + + if (typeof (properties[x][1]) != 'object') { + + data += `*${properties[x][0]}*: ${properties[x][1].replace(/(\r\n|\n|\r)/gm, "")}\n` + + } + else if (typeof (properties[x][1]) == 'object') { + + const sub_properties = properties[x][1]; + + for (let k = 0; k < sub_properties.length; k++) { + + const inner_properties: any = Object.entries(sub_properties[k]); + + for (let y = 0; y < inner_properties.length; y++) { + + sub_data += `*${inner_properties[y][0]}*: ${inner_properties[y][1].replace(/(\r\n|\n|\r)/gm, "")}\n` + + } + + sub_data += '\n' + + } + + } + + } + + msg_endpoint.push({ header: data, body: sub_data }) + + } + + } + else { + msg_endpoint = null + } + + return msg_endpoint + +} + +export default hitPortalMonitoring \ No newline at end of file diff --git a/backend/src/helpers/RedisClient.ts b/backend/src/helpers/RedisClient.ts index 5d96368..59074ec 100644 --- a/backend/src/helpers/RedisClient.ts +++ b/backend/src/helpers/RedisClient.ts @@ -2,20 +2,25 @@ const Redis = require("ioredis"); const redis = new Redis(process.env.REDIS_URI); type WhatsappData = { - whatsappId: string; - contactId: string; + whatsappId: string | number; + contactId: string | number; identifier: string; value?: string; }; -export async function set(key: string, value: string) { +export async function set(key: string, value: string, expire: boolean = false) { await redis.set(key, JSON.stringify(value)); + + if (expire) await redis.expire(key, 300); } -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 del(key: string) { + await redis.del(key); +} export async function createObject({ whatsappId, @@ -51,8 +56,8 @@ export async function updateObject({ } export async function findObject( - whatsappId: string, - contactId: string, + whatsappId: string | number, + contactId: string | number, identifier: string ) { const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`; diff --git a/backend/src/routes/hitRoutes.ts b/backend/src/routes/hitRoutes.ts new file mode 100644 index 0000000..21bc4dc --- /dev/null +++ b/backend/src/routes/hitRoutes.ts @@ -0,0 +1,9 @@ +import express from "express"; + +import * as HitController from "../controllers/HitController" + +const hitRoutes = express.Router(); + +hitRoutes.post("/espacolaser/incidente", HitController.hit); + +export default hitRoutes; diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index 297e954..63ba288 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -13,6 +13,7 @@ import quickAnswerRoutes from "./quickAnswerRoutes"; import reportRoutes from "./reportRoutes"; import schedulingNotifiyRoutes from "./SchedulingNotifyRoutes"; import statusChatEndRoutes from "./statusChatEndRoutes"; +import hitRoutes from "./hitRoutes"; import wbotMonitorRoutes from "./wbotMonitorRoutes"; const routes = Router(); @@ -32,6 +33,7 @@ routes.use(quickAnswerRoutes); routes.use(schedulingNotifiyRoutes); routes.use(reportRoutes); routes.use(statusChatEndRoutes); +routes.use(hitRoutes); routes.use(wbotMonitorRoutes); export default routes; diff --git a/backend/src/services/ContactServices/ShowContactCustomFieldsService.ts b/backend/src/services/ContactServices/ShowContactCustomFieldsService.ts new file mode 100644 index 0000000..35aabb7 --- /dev/null +++ b/backend/src/services/ContactServices/ShowContactCustomFieldsService.ts @@ -0,0 +1,20 @@ +import { raw } from "express"; +import AppError from "../../errors/AppError"; +import ContactCustomField from "../../models/ContactCustomField"; + +const ShowContactCustomFieldService = async (contactId: number | string): Promise => { + + const queue = await ContactCustomField.findAll({ + where: { contactId: contactId }, + raw: true + } + ); + + // if (!queue) { + // throw new AppError("ERR_CONTACT_CUSTOM_FIELD_NOT_FOUND"); + // } + + return queue; +}; + +export default ShowContactCustomFieldService; diff --git a/backend/src/services/HitServices/ShowContactByCustomFieldValueService.ts b/backend/src/services/HitServices/ShowContactByCustomFieldValueService.ts new file mode 100644 index 0000000..859ad1a --- /dev/null +++ b/backend/src/services/HitServices/ShowContactByCustomFieldValueService.ts @@ -0,0 +1,27 @@ + +import Contact from "../../models/Contact"; +import ContactCustomField from "../../models/ContactCustomField"; + +const ContactByCustomField = async (value: string | number): Promise => { + + const contact = await ContactCustomField.findOne({ + where: { value }, + raw: true, + attributes: ['id', 'value', 'contactId'], + + include: [ + { + model: Contact, + required: true, + attributes: ['id', 'name', 'number'], + + }, + + ], + + }); + + return contact; +}; + +export default ContactByCustomField; diff --git a/backend/src/services/TicketServices/ShowTicketMessage2.ts b/backend/src/services/TicketServices/ShowTicketMessage2.ts new file mode 100644 index 0000000..1a23b7b --- /dev/null +++ b/backend/src/services/TicketServices/ShowTicketMessage2.ts @@ -0,0 +1,73 @@ +import Ticket from "../../models/Ticket"; +import AppError from "../../errors/AppError"; +import Contact from "../../models/Contact"; +import User from "../../models/User"; +import Queue from "../../models/Queue"; + +import Message from "../../models/Message"; +import { userInfo } from "os"; + +import { Op, where } from "sequelize"; + +import { Sequelize } from "sequelize"; +import moment from "moment"; + +import { startOfDay, endOfDay, parseISO, getDate } from "date-fns"; +import { string } from "yup/lib/locale"; + +//Report by user, startDate, endDate +const ShowTicketMessage = async ( + ticketId: string | number, + onlyNumber: boolean = false, + fromMe?: boolean, + limit?: number, + regexp?: string +): Promise => { + let where_clause = {}; + + if (onlyNumber) { + where_clause = { + ticketId: ticketId, + fromMe: fromMe ? fromMe : 0, + //body: {[Op.regexp]: '^[0-9]*$'}, + // body: {[Op.regexp]: '^[0-3]$'}, + body: { [Op.regexp]: regexp } + }; + } else { + where_clause = { + ticketId: ticketId, + fromMe: fromMe ? fromMe : 0 + }; + } + + const ticket = await Message.findAll({ + where: where_clause, + limit: limit ? limit : 10000, + raw: true, + attributes: [ + "body", + "read", + "mediaType", + "fromMe", + "mediaUrl", + [ + Sequelize.fn( + "DATE_FORMAT", + Sequelize.col("createdAt"), + "%d/%m/%Y %H:%i:%s" + ), + "createdAt" + ] + ], + + order: [["createdAt", "DESC"]] + }); + + if (!ticket) { + throw new AppError("ERR_NO_TICKET_FOUND", 404); + } + + return ticket; +}; + +export default ShowTicketMessage; diff --git a/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts b/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts new file mode 100644 index 0000000..ac5d1de --- /dev/null +++ b/backend/src/services/TicketServices/ShowTicketServiceByContactId.ts @@ -0,0 +1,44 @@ +import Ticket from "../../models/Ticket"; +import AppError from "../../errors/AppError"; +import Contact from "../../models/Contact"; +import User from "../../models/User"; +import Queue from "../../models/Queue"; + +import { Op } from "sequelize"; + +const ShowTicketServiceByContactId = async (contactId: string | number): Promise => { + + const ticket = await Ticket.findOne({ + + where: { contactId, [Op.or]: [{ status: 'open' }, { status: 'pending' }] }, + + include: [ + { + model: Contact, + as: "contact", + attributes: ["id", "name", "number", "profilePicUrl", "useQueues"], + include: ["extraInfo"] + }, + { + model: User, + as: "user", + attributes: ["id", "name"] + }, + { + model: Queue, + as: "queue", + attributes: ["id", "name", "color"], + } + ] + }); + + if (!ticket) { + + return new Ticket + + } + + return ticket; +}; + +export default ShowTicketServiceByContactId; diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 8047d02..d770ec5 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -68,6 +68,9 @@ import { splitDateTime } from "../../helpers/SplitDateTime"; // import { updateTicketCacheByTicketId } from "../../helpers/TicketCache"; + +import endPointQuery from "../../helpers/EndpointQuery2"; + import { insertMessageContactCache, getLastId @@ -81,6 +84,7 @@ import { } from "../../helpers/WhatsappIdMultiSessionControl"; import AppError from "../../errors/AppError"; import { setMessageAsRead } from "../../helpers/SetMessageAsRead"; +import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot"; import { getSettingValue } from "../../helpers/WhaticketSettings"; import { Op } from "sequelize"; @@ -88,7 +92,15 @@ import { Op } 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 { + createObject, + del, + findObject, + get, + set +} from "../../helpers/RedisClient"; +import ShowContactCustomFieldService from "../ContactServices/ShowContactCustomFieldsService"; +import ShowTicketService from "../TicketServices/ShowTicketService" var lst: any[] = getWhatsappIds(); @@ -197,73 +209,6 @@ const verifyMediaMessage = async ( return newMessage; }; -// const verifyMediaMessage = async ( -// msg: any, -// ticket: Ticket, -// contact: Contact, -// media: any, -// quotedMsg?: any -// ): Promise => { -// // const quotedMsg = await verifyQuotedMessage(msg); - -// // const media = await msg.downloadMedia(); - -// if (!media) { -// throw new Error("ERR_WAPP_DOWNLOAD_MEDIA"); -// } - -// console.log( -// "MEDIA.FILENAME: ", -// media.fileName, -// " | msg.fromMe: ", -// msg.fromMe -// ); - -// if (!media.filename) { -// console.log("No file name -----------------------------------------"); - -// const ext = media.mimetype.split("/")[1].split(";")[0]; -// media.filename = `${new Date().getTime()}.${ext}`; -// } - -// try { -// // await writeFileAsync( -// // join(__dirname, "..", "..", "..", "public", media.filename), -// // media.data, -// // "base64" -// // ); - -// console.log("FROM wbotMessageListener.ts media.filename: ", media.filename); - -// await writeFileAsync( -// join(__dirname, "..", "..", "..", "..", "..", "public", media.filename), -// media.data, -// "base64" -// ); -// } catch (err) { -// Sentry.captureException(err); -// logger.error(`There was an error: wbotMessageLitener.ts: ${err}`); -// } - -// const messageData = { -// id: msg.id.id, -// ticketId: ticket.id, -// contactId: msg.fromMe ? undefined : contact.id, -// body: msg.body || media.filename, -// fromMe: msg.fromMe, -// read: msg.fromMe, -// mediaUrl: media.filename, -// mediaType: media.mimetype.split("/")[0], -// quotedMsgId: quotedMsg -// // quotedMsgId: quotedMsg?.id -// }; - -// await ticket.update({ lastMessage: msg.body || media.filename }); -// const newMessage = await CreateMessageService({ messageData }); - -// return newMessage; -// }; - const verifyMessage = async ( msg: any, ticket: Ticket, @@ -287,6 +232,374 @@ const verifyMessage = async ( await CreateMessageService({ messageData }); }; +const queryEndPointHit = async (centro_de_custo: string) => { + let msg_endpoint: any = []; + + let response2 = await endPointQuery( + "http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php", + "post", + centro_de_custo.trim() + ); + + if (response2 && response2.data.result) { + response2 = response2.data.result; + + for (let i = 0; i < response2.length; i++) { + let data = ""; + let sub_data = "*Atualizações:*\n\n"; + + const properties: any = Object.entries(response2[i]); + + for (let x = 0; x < properties.length; x++) { + if (typeof properties[x][1] != "object") { + data += `*${properties[x][0]}*: ${properties[x][1].replace( + /(\r\n|\n|\r)/gm, + "" + )}\n`; + } else if (typeof properties[x][1] == "object") { + const sub_properties = properties[x][1]; + + for (let k = 0; k < sub_properties.length; k++) { + const inner_properties: any = Object.entries(sub_properties[k]); + + for (let y = 0; y < inner_properties.length; y++) { + sub_data += `*${inner_properties[y][0]}*: ${inner_properties[ + y + ][1].replace(/(\r\n|\n|\r)/gm, "")}\n`; + } + + sub_data += "\n"; + } + } + } + + msg_endpoint.push({ header: data, body: sub_data }); + } + } else { + msg_endpoint = null; + } + + return msg_endpoint; +}; + +const monitoramento_response2 = async ( + response: any | null, + wbot: any, + contact: any, + ticket: any, + centro_de_custo: any, + final_message: string = "", + send_empty_incident?: boolean +) => { + if (!response) { + await SendWhatsAppMessage({ + body: `Houve um erro ao tentar consultar o monitoramento da Operadora!${final_message}`, + ticket, + number: `${contact.number}@c.us` + }); + } else if (response.length > 0) { + for (let i = 0; i < response.length; i++) { + await SendWhatsAppMessage({ + body: `*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[i].header}\n${response[i].body}${final_message}`, + ticket, + number: `${contact.number}@c.us` + }); + } + } else if (send_empty_incident) { + await SendWhatsAppMessage({ + body: `Conforme Monitoramento a internet da unidade está operacional${final_message}`, + ticket, + number: `${contact.number}@c.us` + }); + } +}; + +async function sendDelayedMessages( + wbot: Session, + ticket: Ticket, + contact: Contact, + message: string, + _msg?: WbotMessage +) { + const body = message.replace(/\\n/g, "\n"); + + if (body.search("dialog_actions") != -1) { + let msgAction = botMsgActions(body); + + if (msgAction.actions[0] == "request_endpoint") { + await SendWhatsAppMessage({ + body: msgAction.msgBody, + ticket, + number: `${contact.number}@c.us` + }); + + // const url = 'https://sos.espacolaser.com.br/api/whatsapps/ticket/R32656' + let endPointResponse = await endPointQuery(msgAction.actions[1], "get"); + + await del( + `whatsappId:${wbot.id}:contactId:${contact.id}:identifier:query` + ); + + console.log( + "Object.entries(endPointResponse.data).length: ", + Object.entries(endPointResponse.data).length + ); + + if ( + endPointResponse && + endPointResponse.status == 200 && + Object.entries(endPointResponse.data).length > 0 + ) { + if ( + endPointResponse.data.categoria != "INFRAESTRUTURA" && + endPointResponse.data.categoria != "ELOS" + ) { + botSendMessage( + ticket, + `A categorização desse chamado não se enquadra no atendimento deste canal!\n\n _Digite *0* para voltar ao menu principal._` + ); + return; + } + + const response = Object.entries(endPointResponse.data); + let msg_endpoint_response = ""; + let msg_endpoint2: any = []; + let centro_de_custo = ""; + + for (let i = 0; i < response.length; i++) { + if ( + [ + "id_solicitante", + "centro_custo_departamento", + "departamento_do_formulario", + "centro_de_custo_do_departamento_do_formulario" + ].includes(response[i][0]) + ) + continue; + + msg_endpoint_response += `*${response[i][0]}*: ${String( + response[i][1] + ).replace(/(<([^>]+)>)/gi, "")}\n`; + } + + if ( + endPointResponse.data.centro_custo_departamento && + endPointResponse.data.centro_custo_departamento.trim().length > 0 && + endPointResponse.data.categoria == "INFRAESTRUTURA" && + endPointResponse.data.subcategoria == "INTERNET" + ) { + centro_de_custo = endPointResponse.data.centro_custo_departamento; + + msg_endpoint2 = await queryEndPointHit(centro_de_custo); + } + + const itsm_response = async ( + message1: string = "", + message2: string = "" + ) => { + await SendWhatsAppMessage({ + body: `*Situação do chamado ${extractCallCode( + msgAction.msgBody + )}:*${message1}${msg_endpoint_response}${message2}\n_Digite *0* para voltar ao menu principal._`, + ticket, + number: `${contact.number}@c.us` + }); + }; + + const sendMessageBot = async ( + message1: string = "", + message2: string = "" + ) => { + await SendWhatsAppMessage({ + body: `${message1}${message2}`, + ticket, + number: `${contact.number}@c.us` + }); + }; + + if (body.search("dialog_options") != -1) { + let msgAction = botMsgActions(body); + + let index = msgAction.actions.findIndex(i => i == "dialog_options"); + + if (index != -1) { + let dialog_options = msgAction.actions[index + 1]; + + if ( + dialog_options == "3" && + endPointResponse.data.categoria == "ELOS" + ) { + index = msgAction.actions.findIndex(i => i == "queue_transfer"); + + if (index != -1) { + await itsm_response("\n\n"); + + await monitoramento_response2( + msg_endpoint2, + wbot, + contact, + ticket, + centro_de_custo, + "\n\n", + false + ); + + botSendMessage( + ticket, + `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( + +msgAction.actions[index + 1], + wbot, + ticket + ); + } + } + } + } else if ( + (endPointResponse.data.categoria == "INFRAESTRUTURA" && + endPointResponse.data.subcategoria == "INTERNET" && + endPointResponse.data.terceiro_nivel == "QUEDA TOTAL") || + (endPointResponse.data.categoria == "INFRAESTRUTURA" && + endPointResponse.data.subcategoria == "INTERNET" && + endPointResponse.data.terceiro_nivel == "PROBLEMA DE LENTIDÃO") || + (endPointResponse.data.categoria == "ELOS" && + endPointResponse.data.subcategoria == "VENDAS") || + (endPointResponse.data.categoria == "ELOS" && + endPointResponse.data.subcategoria == "INDISPONIBILIDADE") + ) { + await itsm_response("\n\n"); + + if ( + endPointResponse.data.categoria == "INFRAESTRUTURA" && + endPointResponse.data.subcategoria == "INTERNET" && + centro_de_custo + ) { + await monitoramento_response2( + msg_endpoint2, + wbot, + contact, + ticket, + centro_de_custo, + "\n\n _Digite *0* para voltar ao menu principal._", + true + ); + } + + await sendMessageBot( + "Se deseja solicitar atendimento de urgência, digite *1*!", + "\n\n _Digite *0* para voltar ao menu principal._" + ); + + return; + } else { + await itsm_response("\n\n"); + + if ( + endPointResponse.data.categoria == "INFRAESTRUTURA" && + endPointResponse.data.subcategoria == "INTERNET" && + centro_de_custo + ) { + await monitoramento_response2( + msg_endpoint2, + wbot, + contact, + ticket, + centro_de_custo, + "\n\n _Digite *0* para voltar ao menu principal._", + true + ); + } + + await sendMessageBot( + "Acompanhe a evolução do atendimento através do SOS" + ); + + return; + } + } else if ( + endPointResponse && + endPointResponse.status == 200 && + Object.entries(endPointResponse.data).length == 0 + ) { + botSendMessage( + ticket, + `Não existe nenhum chamado para consulta com esse número!\n _Digite *0* para voltar ao menu principal._` + ); + return; + } else if (endPointResponse && endPointResponse.status == 500) { + botSendMessage( + ticket, + `Houve um erro ao realizar a consulta no sos espacolaser!\n _Digite *0* para voltar ao menu principal._` + ); + return; + } else { + botSendMessage( + ticket, + `Desculpe, nao foi possível realizar a consulta!\n _Digite *0* para voltar ao menu principal._` + ); + return; + } + } else if (msgAction.actions[0] == "queue_transfer") { + console.log( + ">>>>>>>>>>>>>>> msgAction: ", + msgAction, + " | msgAction.actions[1]: ", + msgAction.actions[1] + ); + + const contact_custom_field = await ShowContactCustomFieldService( + contact.id + ); + + if (contact_custom_field && contact_custom_field.length > 0) { + const msg_endpoint = await queryEndPointHit( + contact_custom_field[0].value + ); + + await monitoramento_response2( + msg_endpoint, + wbot, + contact, + ticket, + contact_custom_field[0].value + ); + } + + console.log("************* contact_custom_field: ", contact_custom_field); + + await SendWhatsAppMessage({ + body: msgAction.msgBody, + ticket, + number: `${contact.number}@c.us` + }); + + await transferTicket(+msgAction.actions[1], wbot, ticket); + } else if (msgAction.actions[0] == "send_file") { + const sourcePath = path.join(__dirname, `../../../public/bot`); + + await SendWhatsAppMessage({ + body: msgAction.msgBody, + ticket, + number: `${contact.number}@c.us` + }); + } + } else { + sendWhatsAppMessageSocket(ticket, body); + } +} + +const extractCallCode = (str: string) => { + if (str.includes("*") && str.indexOf("*") < str.lastIndexOf("*")) { + return str + .substring(str.indexOf("*"), str.lastIndexOf("*") + 1) + .split("*") + .join(""); + } + return ""; +}; + const verifyQueue = async ( wbot: Session, msg: WbotMessage, @@ -457,6 +770,17 @@ const mediaTypeWhatsappOfficial = (mimetype: string): object => { return { type: null, mbsize: 0 }; }; +const botMsgActions = (params: string) => { + let lstActions = params.split("dialog_actions="); + let bodyMsg = lstActions[0]; + let obj = {}; + + console.log("lstActions: ", lstActions[1].split("=")); + let actions = lstActions[1].split("="); + + return { msgBody: bodyMsg, actions: actions }; +}; + const isValidMsg = (msg: any): boolean => { if (msg.from === "status@broadcast") return false; if ( @@ -663,12 +987,38 @@ const handleMessage = async ( ) 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 + ); + } if (getSettingValue("oneContactChatWithManyWhats")?.value == "disabled") { // Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen @@ -739,6 +1089,63 @@ 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" && String(msg.body).length > 120) { + botSendMessage( + ticket, + `Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para voltar ao menu principal._` + ); + return; + } + + let query = await get( + `whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query` + ); + + if (query && msg?.body?.trim() != "0") { + query = JSON.parse(query); + + const regexString = query?.queryRegex?.slice(1, -1); + + query.queryRegex = new RegExp(regexString); + + if (!query?.queryRegex.test(msg.body)) { + await botSendMessage(ticket, query?.queryMsgInvalidParam); + return; + } + + if (query?.value?.trim()?.length == 0) { + await set( + `whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query`, + JSON.stringify({ ...query, value: msg.body }), + true + ); + } + + let message = ""; + + // Refactor later + if (query?.optionsMenu == "3") { + message = `Consultando *${msg?.body?.trim()}* aguarde... +dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/ticket/${msg?.body?.trim()}=dialog_options=3=queue_transfer=1`; + } else if (query?.optionsMenu == "1") { + message = `Consultando *${msg.body}* aguarde... + dialog_actions=request_endpoint=https://sos.espacolaser.com.br/api/whatsapp/ticket/${msg?.body?.trim()}`; + } + + if (message.trim().length > 0) + await sendDelayedMessages(wbot, ticket, contact, message); + + return; + } + const menuMsg: any = await menu(msg.body, wbot.id, contact.id); console.log("menuMsg: ", menuMsg); @@ -755,6 +1162,22 @@ const handleMessage = async ( ); transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket); + } else if (menuMsg?.query) { + await set( + `whatsappId:${wbot.id}:contactId:${contact?.id}:identifier:query`, + JSON.stringify({ + whatsappId: wbot.id, + contactId: contact.id, + identifier: "query", + value: "", + queryRegex: menuMsg?.queryRegex, + query: menuMsg?.query, + queryMsg: menuMsg?.queryMsg, + queryMsgInvalidParam: menuMsg?.queryMsgInvalidParam, + optionsMenu: menuMsg?.optionsMenu + }), + true + ); } } @@ -894,6 +1317,10 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => { value: data[1].id }); + await del( + `whatsappId:${whatsappId}:contactId:${contactId}:identifier:query` + ); + return data[1]; } else { console.log("INVALID SEARCH"); diff --git a/frontend/src/components/MessageInput/index.js b/frontend/src/components/MessageInput/index.js index 30c72d1..2d9f599 100644 --- a/frontend/src/components/MessageInput/index.js +++ b/frontend/src/components/MessageInput/index.js @@ -321,16 +321,34 @@ const MessageInput = ({ ticketStatus }) => { setTabOption('open') } - const message = { + + if (templateParams) { + for (let key in templateParams) { + if (templateParams.hasOwnProperty(key)) { + // let value = templateParams[key] + // console.log('key: ', key, ' | ', 'VALUE: ', value) + + if (key === '_reactName') { + templateParams = null + break + } + } + } + } + + let message = { read: 1, fromMe: true, mediaUrl: "", - body: (signMessage && !templateParams) - ? `*${user?.name}:*\n${inputMessage.trim()}` - : inputMessage.trim(), - quotedMsg: replyingMessage, - params: templateParams + body: (signMessage && !templateParams) ? `*${user?.name}:*\n${inputMessage.trim()}` : inputMessage.trim(), + quotedMsg: replyingMessage } + + if (templateParams) { + message = { ...message, params: templateParams } + } + + try { const { data } = await api.post(`/messages/${ticketId}`, message) @@ -358,8 +376,8 @@ const MessageInput = ({ ticketStatus }) => { let { text } = body_params - console.log('PARAMS FROM MESSAGE INPUT: ', params, ' | text: ', text) - + console.log('PARAMS FROM MESSAGE INPUT: ', params, ' | text: ', text) + let body = text.match(/{{\d+}}/g) if (body && body.length > 0) { @@ -373,9 +391,9 @@ const MessageInput = ({ ticketStatus }) => { } } - } + } console.log('NEW TEXT: ', text) - setInputMessage(text) + setInputMessage(text) }, [params])