feat: Support IVR(ura) for bot interactions, optimize botqueue user checks, and allow supervisor to view all tickets
parent
dfa4be6253
commit
ad89d3ccdb
|
@ -5,6 +5,9 @@ import DeleteQueueService from "../services/QueueService/DeleteQueueService";
|
||||||
import ListQueuesService from "../services/QueueService/ListQueuesService";
|
import ListQueuesService from "../services/QueueService/ListQueuesService";
|
||||||
import ShowQueueService from "../services/QueueService/ShowQueueService";
|
import ShowQueueService from "../services/QueueService/ShowQueueService";
|
||||||
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
|
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
|
||||||
|
import Queue from "../models/Queue"
|
||||||
|
import AppError from "../errors/AppError"
|
||||||
|
import { get, set } from "../helpers/RedisClient";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +31,106 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
return res.status(200).json(queue);
|
return res.status(200).json(queue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const customization = async (
|
||||||
|
req: Request,
|
||||||
|
res: Response
|
||||||
|
): Promise<Response> => {
|
||||||
|
const { ura } = req.body;
|
||||||
|
|
||||||
|
if (!ura) throw new AppError("BAD REQUEST", 400);
|
||||||
|
|
||||||
|
let new_queues: any;
|
||||||
|
|
||||||
|
if (ura.length > 0) {
|
||||||
|
new_queues = ura
|
||||||
|
.filter(
|
||||||
|
(u: any) =>
|
||||||
|
u.idmaster === ura[1].id &&
|
||||||
|
u?.queueName &&
|
||||||
|
u?.color &&
|
||||||
|
u?.greetingMessage
|
||||||
|
)
|
||||||
|
.map((u: any) => {
|
||||||
|
const { queueName, color, greetingMessage } = u;
|
||||||
|
return {
|
||||||
|
queueName: queueName?.trim()?.replace(/\s+/g, " "),
|
||||||
|
color,
|
||||||
|
greetingMessage
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (new_queues && new_queues.length > 0) {
|
||||||
|
const db_queues: any = await Queue.findAll();
|
||||||
|
|
||||||
|
for (const i in new_queues) {
|
||||||
|
let { queueName: name, color, greetingMessage } = new_queues[i];
|
||||||
|
|
||||||
|
name = name?.trim()?.replace(/\s+/g, " ");
|
||||||
|
|
||||||
|
const update = db_queues.find(
|
||||||
|
(q: any) => q.name?.trim()?.replace(/\s+/g, " ") == name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
const { id } = update;
|
||||||
|
// UPDATE
|
||||||
|
// const queue = await UpdateQueueService(id, {
|
||||||
|
// name,
|
||||||
|
// color,
|
||||||
|
// greetingMessage
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const io = getIO();
|
||||||
|
// io.emit("queue", {
|
||||||
|
// action: "update",
|
||||||
|
// queue
|
||||||
|
// });
|
||||||
|
} else {
|
||||||
|
// CREATE
|
||||||
|
// const queue = await CreateQueueService({
|
||||||
|
// name,
|
||||||
|
// color,
|
||||||
|
// greetingMessage
|
||||||
|
// });
|
||||||
|
// const io = getIO();
|
||||||
|
// io.emit("queue", {
|
||||||
|
// action: "update",
|
||||||
|
// queue
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let remove_queues = db_queues.filter(
|
||||||
|
(q: any) =>
|
||||||
|
!new_queues
|
||||||
|
.map((nq: any) => nq.queueName)
|
||||||
|
.includes(q.name?.trim()?.replace(/\s+/g, " "))
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const i in remove_queues) {
|
||||||
|
const { id, name } = remove_queues[i];
|
||||||
|
|
||||||
|
// await DeleteQueueService(id);
|
||||||
|
|
||||||
|
// const io = getIO();
|
||||||
|
// io.emit("queue", {
|
||||||
|
// action: "delete",
|
||||||
|
// queueId: +id
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
// await set("ura", ura);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await set("ura", ura);
|
||||||
|
|
||||||
|
const _ura = await get("ura");
|
||||||
|
console.log("_URA: ", _ura);
|
||||||
|
|
||||||
|
return res.status(200).json({ new_queues });
|
||||||
|
};
|
||||||
|
|
||||||
export const show = async (req: Request, res: Response): Promise<Response> => {
|
export const show = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { queueId } = req.params;
|
const { queueId } = req.params;
|
||||||
|
|
||||||
|
|
|
@ -110,11 +110,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
|
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
|
||||||
req.body;
|
req.body;
|
||||||
|
|
||||||
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
|
|
||||||
let ticket = await Ticket.findOne({
|
let ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
[Op.or]: [
|
[Op.or]: [
|
||||||
{ contactId, status: "queueChoice" }
|
{ contactId, status: "queueChoice" },
|
||||||
// { contactId, status: "open", userId: botInfo.userIdBot }
|
{ contactId, status: "open", userId: botInfo.userIdBot }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,7 @@ import DeleteUserService from "../services/UserServices/DeleteUserService";
|
||||||
|
|
||||||
import ListUser from "../services/UserServices/ListUserParamiterService";
|
import ListUser from "../services/UserServices/ListUserParamiterService";
|
||||||
import User from "../models/User";
|
import User from "../models/User";
|
||||||
|
import { get, set } from "../helpers/RedisClient";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
startWhoIsOnlineMonitor,
|
startWhoIsOnlineMonitor,
|
||||||
|
@ -134,7 +135,8 @@ export const all = async (req: Request, res: Response): Promise<Response> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { email, password, name, profile, positionCompany, queueIds } = req.body;
|
const { email, password, name, profile, positionCompany, queueIds } =
|
||||||
|
req.body;
|
||||||
|
|
||||||
console.log("===========> req.url: ", req.url);
|
console.log("===========> req.url: ", req.url);
|
||||||
|
|
||||||
|
@ -149,13 +151,10 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
getSettingValue("userCreation")?.value == "disabled"
|
getSettingValue("userCreation")?.value == "disabled"
|
||||||
) {
|
) {
|
||||||
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
|
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
|
||||||
} else if (
|
} else if (req.user.profile !== "master") {
|
||||||
req.user.profile !== "master"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const user = await CreateUserService({
|
const user = await CreateUserService({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
|
@ -266,12 +265,38 @@ export const update = async (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('userQueuesAttendance: ', userQueuesAttendance)
|
|
||||||
|
|
||||||
// return res.status(200).json({});
|
|
||||||
|
|
||||||
let user: any = await UpdateUserService({ userData, userId });
|
let user: any = await UpdateUserService({ userData, userId });
|
||||||
|
|
||||||
|
if (user?.name?.trim() == "botqueue") {
|
||||||
|
let botInfo;
|
||||||
|
|
||||||
|
if (
|
||||||
|
user?.queues?.length > 0 &&
|
||||||
|
user.queues[0]?.name?.trim() == "botqueue"
|
||||||
|
) {
|
||||||
|
botInfo = JSON.stringify({
|
||||||
|
userId: user.id,
|
||||||
|
queueId: user.queues[0].id,
|
||||||
|
botIsOnQueue: true
|
||||||
|
});
|
||||||
|
botInfo = JSON.parse(botInfo);
|
||||||
|
|
||||||
|
await set("botInfo", botInfo);
|
||||||
|
} else if (
|
||||||
|
user?.queues?.length == 0 ||
|
||||||
|
user.queues[0]?.name?.trim() != "botqueue"
|
||||||
|
) {
|
||||||
|
botInfo = JSON.stringify({
|
||||||
|
userId: user.id,
|
||||||
|
queueId: 0,
|
||||||
|
botIsOnQueue: false
|
||||||
|
});
|
||||||
|
botInfo = JSON.parse(botInfo);
|
||||||
|
|
||||||
|
await set("botInfo", botInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("user", {
|
io.emit("user", {
|
||||||
action: "update",
|
action: "update",
|
||||||
|
|
|
@ -1,37 +1,26 @@
|
||||||
const fsPromises = require("fs/promises");
|
const fsPromises = require("fs/promises");
|
||||||
const fs = require('fs')
|
const fs = require("fs");
|
||||||
|
|
||||||
import ListUsersService from "../services/UserServices/ListUsersService"
|
import ListUsersService from "../services/UserServices/ListUsersService";
|
||||||
|
import { get } from "./RedisClient";
|
||||||
|
|
||||||
const _botIsOnQueue = async (botName: string) => {
|
const _botIsOnQueue = async (botName: string) => {
|
||||||
|
|
||||||
const { users, count, hasMore } = await ListUsersService({searchParam:`${botName}`,pageNumber:1});
|
const botInfo = await get("botInfo");
|
||||||
let botIsOnQueue = false
|
|
||||||
let userIdBot = null
|
|
||||||
let queueId = null
|
|
||||||
|
|
||||||
if(users.length > 0){
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
console.log('----------------- bot queue id: ', Object(users)[0]["queues"][0].id)
|
|
||||||
queueId = Object(users)[0]["queues"][0].id;
|
|
||||||
userIdBot = Object(users)[0].id
|
|
||||||
botIsOnQueue = true
|
|
||||||
|
|
||||||
}catch(err){
|
|
||||||
|
|
||||||
console.log('O usuário botqueue não está em nenhuma fila err: ',err)
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
botInfo &&
|
||||||
|
botInfo?.userId &&
|
||||||
|
botInfo?.queueId &&
|
||||||
|
botInfo?.botIsOnQueue == true
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
userIdBot: botInfo.userId,
|
||||||
|
botQueueId: botInfo.queueId,
|
||||||
|
isOnQueue: botInfo.botIsOnQueue
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
return { userIdBot: null, botQueueId: null, isOnQueue: false };
|
||||||
|
};
|
||||||
|
|
||||||
}
|
export default _botIsOnQueue;
|
||||||
else{
|
|
||||||
console.log('Usuário botqueue não existe!')
|
|
||||||
}
|
|
||||||
|
|
||||||
return { userIdBot: userIdBot, botQueueId: queueId, isOnQueue: botIsOnQueue }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default _botIsOnQueue;
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import ListTicketTimeLife from "../services/TicketServices/ListTicketTimeLife";
|
||||||
|
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
|
||||||
|
import BotIsOnQueue from "./BotIsOnQueue";
|
||||||
|
|
||||||
|
const fsPromises = require("fs/promises");
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
let timer: any
|
||||||
|
|
||||||
|
const CloseBotTickets = async () => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
const botInfo = await BotIsOnQueue('botqueue')
|
||||||
|
|
||||||
|
if (!botInfo.userIdBot) return
|
||||||
|
|
||||||
|
let tickets: any = await ListTicketTimeLife({ timeseconds: 60, status: 'open', userId: botInfo.userIdBot })
|
||||||
|
|
||||||
|
console.log('tickets: ', tickets)
|
||||||
|
|
||||||
|
for (let i = 0; i < tickets.length; i++) {
|
||||||
|
|
||||||
|
await UpdateTicketService({
|
||||||
|
ticketData: { 'status': 'closed', 'userId': botInfo.userIdBot, 'statusChatEnd': 'FINALIZADO' },
|
||||||
|
ticketId: tickets[i].ticket_id
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('There was an error on try close the bot tickets: ', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const schedule = async () => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
clearInterval(timer);
|
||||||
|
|
||||||
|
await CloseBotTickets()
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('error on schedule: ', error)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
timer = setInterval(schedule, 60000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timer = setInterval(schedule, 60000);
|
||||||
|
|
||||||
|
export default schedule;
|
|
@ -0,0 +1,130 @@
|
||||||
|
const Redis = require("ioredis");
|
||||||
|
const redis = new Redis(process.env.REDIS_URI);
|
||||||
|
|
||||||
|
type WhatsappData = {
|
||||||
|
whatsappId: string;
|
||||||
|
contactId: string;
|
||||||
|
identifier: string;
|
||||||
|
value?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function set(key: string, value: string) {
|
||||||
|
await redis.set(key, JSON.stringify(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get(key: string) {
|
||||||
|
const value: any = await redis.get(key);
|
||||||
|
return JSON.parse(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier,
|
||||||
|
value
|
||||||
|
}: WhatsappData) {
|
||||||
|
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
||||||
|
const result = await redis.hmset(
|
||||||
|
key,
|
||||||
|
"whatsappId",
|
||||||
|
whatsappId,
|
||||||
|
"contactId",
|
||||||
|
contactId,
|
||||||
|
"identifier",
|
||||||
|
identifier,
|
||||||
|
"value",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
await redis.expire(key, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier,
|
||||||
|
value
|
||||||
|
}: WhatsappData) {
|
||||||
|
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
||||||
|
|
||||||
|
await redis.hset(key, "value", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function findObject(
|
||||||
|
whatsappId: string,
|
||||||
|
contactId: string,
|
||||||
|
identifier: string
|
||||||
|
) {
|
||||||
|
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
||||||
|
const result = await redis.hmget(
|
||||||
|
key,
|
||||||
|
"whatsappId",
|
||||||
|
"contactId",
|
||||||
|
"identifier",
|
||||||
|
"value"
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteObject(
|
||||||
|
whatsappId: string,
|
||||||
|
contactId: string,
|
||||||
|
identifier: string
|
||||||
|
) {
|
||||||
|
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
||||||
|
const deletedCount = await redis.del(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteKeysWithPattern(
|
||||||
|
whatsappId: string,
|
||||||
|
contactId: string
|
||||||
|
) {
|
||||||
|
const pattern = `whatsappId:${whatsappId}:contactId:${contactId}:*`;
|
||||||
|
|
||||||
|
let cursor = "0";
|
||||||
|
|
||||||
|
do {
|
||||||
|
const [newCursor, keys] = await redis.scan(
|
||||||
|
cursor,
|
||||||
|
"MATCH",
|
||||||
|
pattern,
|
||||||
|
"COUNT",
|
||||||
|
"100"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const key of keys) {
|
||||||
|
await redis.del(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = newCursor;
|
||||||
|
} while (cursor !== "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getHashesWithPattern(
|
||||||
|
whatsappId: string,
|
||||||
|
contactId: string
|
||||||
|
) {
|
||||||
|
const pattern = `whatsappId:${whatsappId}:contactId:${contactId}:*`;
|
||||||
|
|
||||||
|
let cursor = "0";
|
||||||
|
const hashes = [];
|
||||||
|
|
||||||
|
do {
|
||||||
|
const [newCursor, keys] = await redis.scan(
|
||||||
|
cursor,
|
||||||
|
"MATCH",
|
||||||
|
pattern,
|
||||||
|
"COUNT",
|
||||||
|
"100"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const key of keys) {
|
||||||
|
const hash = await redis.hgetall(key);
|
||||||
|
hashes.push(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = newCursor;
|
||||||
|
} while (cursor !== "0");
|
||||||
|
|
||||||
|
return hashes;
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ queueRoutes.get("/queue", isAuth, QueueController.index);
|
||||||
|
|
||||||
queueRoutes.post("/queue", isAuth, QueueController.store);
|
queueRoutes.post("/queue", isAuth, QueueController.store);
|
||||||
|
|
||||||
|
queueRoutes.post("/queue/customization", QueueController.customization);
|
||||||
|
|
||||||
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
|
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
|
||||||
|
|
||||||
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);
|
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);
|
||||||
|
|
|
@ -7,6 +7,8 @@ import User from "./models/User";
|
||||||
import Whatsapp from "./models/Whatsapp";
|
import Whatsapp from "./models/Whatsapp";
|
||||||
import endPointQuery from "./helpers/EndPointQuery";
|
import endPointQuery from "./helpers/EndPointQuery";
|
||||||
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
|
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
|
||||||
|
|
||||||
|
import "./helpers/CloseBotTickets";
|
||||||
import { loadContactsCache } from "./helpers/ContactsCache";
|
import { loadContactsCache } from "./helpers/ContactsCache";
|
||||||
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
||||||
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
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<any> => {
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// await sendDialogflowAnswer(ticket.whatsappId, ticket, msg, contact, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import ShowTicketService from "./ShowTicketService";
|
||||||
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||||
|
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
||||||
|
import { deleteObject } from "../../helpers/RedisClient"
|
||||||
var flatten = require("flat");
|
var flatten = require("flat");
|
||||||
|
|
||||||
interface TicketData {
|
interface TicketData {
|
||||||
|
@ -49,6 +51,15 @@ const UpdateTicketService = async ({
|
||||||
|
|
||||||
const ticket = await ShowTicketService(ticketId);
|
const ticket = await ShowTicketService(ticketId);
|
||||||
|
|
||||||
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
|
|
||||||
|
if (
|
||||||
|
status == "closed" ||
|
||||||
|
(status == "open" && ticket && `${userId}` != `${botInfo.userIdBot}`)
|
||||||
|
) {
|
||||||
|
deleteObject(`${ticket.whatsappId}`, `${ticket.contactId}`, "ura");
|
||||||
|
}
|
||||||
|
|
||||||
const oldStatus = ticket.status;
|
const oldStatus = ticket.status;
|
||||||
const oldUserId = ticket.user?.id;
|
const oldUserId = ticket.user?.id;
|
||||||
|
|
||||||
|
@ -68,7 +79,6 @@ const UpdateTicketService = async ({
|
||||||
await ticket.reload();
|
await ticket.reload();
|
||||||
|
|
||||||
if (msg?.trim().length > 0) {
|
if (msg?.trim().length > 0) {
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
sendWhatsAppMessageSocket(ticket, msg);
|
sendWhatsAppMessageSocket(ticket, msg);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import User from "../../models/User";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Ticket from "../../models/Ticket";
|
import Ticket from "../../models/Ticket";
|
||||||
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
|
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
|
||||||
|
import { set } from "../../helpers/RedisClient"
|
||||||
|
|
||||||
const DeleteUserService = async (id: string | number): Promise<void> => {
|
const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -13,6 +13,17 @@ const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
throw new AppError("ERR_NO_USER_FOUND", 404);
|
throw new AppError("ERR_NO_USER_FOUND", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user?.name?.trim() == "botqueue") {
|
||||||
|
let botInfo = JSON.stringify({
|
||||||
|
userId: 0,
|
||||||
|
queueId: 0,
|
||||||
|
botIsOnQueue: false
|
||||||
|
});
|
||||||
|
botInfo = JSON.parse(botInfo);
|
||||||
|
|
||||||
|
await set("botInfo", botInfo);
|
||||||
|
}
|
||||||
|
|
||||||
const userOpenTickets: Ticket[] = await user.$get("tickets", {
|
const userOpenTickets: Ticket[] = await user.$get("tickets", {
|
||||||
where: { status: "open" }
|
where: { status: "open" }
|
||||||
});
|
});
|
||||||
|
@ -21,9 +32,7 @@ const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
UpdateDeletedUserOpenTicketsStatus(userOpenTickets);
|
UpdateDeletedUserOpenTicketsStatus(userOpenTickets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await user.destroy();
|
await user.destroy();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeleteUserService;
|
export default DeleteUserService;
|
||||||
|
|
|
@ -88,6 +88,7 @@ import { Op } from "sequelize";
|
||||||
import SettingTicket from "../../models/SettingTicket";
|
import SettingTicket from "../../models/SettingTicket";
|
||||||
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
||||||
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
||||||
|
import { createObject, findObject, get } from "../../helpers/RedisClient";
|
||||||
|
|
||||||
var lst: any[] = getWhatsappIds();
|
var lst: any[] = getWhatsappIds();
|
||||||
|
|
||||||
|
@ -298,8 +299,8 @@ const verifyQueue = async (
|
||||||
let choosenQueue = null;
|
let choosenQueue = null;
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
//Habilitar esse caso queira usar o bot
|
||||||
// const botInfo = await BotIsOnQueue('botqueue')
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
||||||
|
|
||||||
if (botInfo.isOnQueue) {
|
if (botInfo.isOnQueue) {
|
||||||
choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
||||||
|
@ -337,9 +338,17 @@ const verifyQueue = async (
|
||||||
ticketId: ticket.id
|
ticketId: ticket.id
|
||||||
});
|
});
|
||||||
|
|
||||||
data_ura.forEach((s, index) => {
|
const data = await get("ura");
|
||||||
botOptions += `*${index + 1}* - ${s.option}\n`;
|
|
||||||
|
await createObject({
|
||||||
|
whatsappId: `${ticket.whatsappId}`,
|
||||||
|
contactId: `${ticket.contactId}`,
|
||||||
|
identifier: "ura",
|
||||||
|
value: data[1].id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
botSendMessage(ticket, data[1].value);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -479,12 +488,35 @@ const queuesOutBot = async (wbot: Session, botId: string | number) => {
|
||||||
return { queues, greetingMessage };
|
return { queues, greetingMessage };
|
||||||
};
|
};
|
||||||
|
|
||||||
const botTransferTicket = async (
|
const transferTicket = async (queueName: any, wbot: any, ticket: Ticket) => {
|
||||||
queues: Queue,
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
ticket: Ticket,
|
|
||||||
contact: Contact,
|
console.log("kkkkkkkkkkkkkkkkkkkkk queueName: ", queueName);
|
||||||
wbot: Session
|
|
||||||
) => {
|
const queuesWhatsGreetingMessage = await queuesOutBot(
|
||||||
|
wbot,
|
||||||
|
botInfo.botQueueId
|
||||||
|
);
|
||||||
|
|
||||||
|
let queue: any;
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue) await botTransferTicket(queue, ticket);
|
||||||
|
};
|
||||||
|
|
||||||
|
const botTransferTicket = async (queues: Queue, ticket: Ticket) => {
|
||||||
await ticket.update({ userId: null });
|
await ticket.update({ userId: null });
|
||||||
|
|
||||||
await UpdateTicketService({
|
await UpdateTicketService({
|
||||||
|
@ -683,9 +715,72 @@ const handleMessage = async (
|
||||||
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
//Habilitar esse caso queira usar o bot
|
||||||
// const botInfo = await BotIsOnQueue('botqueue')
|
const botInfo = await BotIsOnQueue("botqueue");
|
||||||
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
||||||
|
|
||||||
|
if (
|
||||||
|
botInfo.isOnQueue &&
|
||||||
|
!msg.fromMe &&
|
||||||
|
ticket.userId == botInfo.userIdBot
|
||||||
|
) {
|
||||||
|
const repet: any = await mostRepeatedPhrase(ticket.id);
|
||||||
|
|
||||||
|
console.log("repet.occurrences: ", repet.occurrences);
|
||||||
|
|
||||||
|
if (repet.occurrences > 4) {
|
||||||
|
await transferTicket(0, wbot, ticket);
|
||||||
|
|
||||||
|
await SendWhatsAppMessage({
|
||||||
|
body: `Seu atendimento foi transferido para um agente!\n\nPara voltar ao menu principal digite *0*
|
||||||
|
`,
|
||||||
|
ticket,
|
||||||
|
number: `${contact.number}@c.us`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("MSG body: ", msg.body);
|
||||||
|
|
||||||
|
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
||||||
|
|
||||||
|
console.log("menuMsg: ", menuMsg);
|
||||||
|
|
||||||
|
await botSendMessage(ticket, menuMsg.value);
|
||||||
|
|
||||||
|
if (
|
||||||
|
menuMsg?.transferToQueue &&
|
||||||
|
menuMsg.transferToQueue.trim().length > 0
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
"YYYYYYYYYYYYYYYYYYYY menuMsg.transferToQueue: ",
|
||||||
|
menuMsg.transferToQueue
|
||||||
|
);
|
||||||
|
|
||||||
|
transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else if (
|
||||||
|
!msg.fromMe &&
|
||||||
|
msg.body == "0" &&
|
||||||
|
ticket.status == "pending" &&
|
||||||
|
ticket.queueId
|
||||||
|
) {
|
||||||
|
let choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
||||||
|
|
||||||
|
await UpdateTicketService({
|
||||||
|
ticketData: {
|
||||||
|
status: "open",
|
||||||
|
userId: botInfo.userIdBot,
|
||||||
|
queueId: choosenQueue.id
|
||||||
|
},
|
||||||
|
ticketId: ticket.id
|
||||||
|
});
|
||||||
|
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
||||||
|
await botSendMessage(ticket, menuMsg.value);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg && !msg.fromMe && ticket.status == "pending") {
|
if (msg && !msg.fromMe && ticket.status == "pending") {
|
||||||
await setMessageAsRead(ticket);
|
await setMessageAsRead(ticket);
|
||||||
}
|
}
|
||||||
|
@ -720,6 +815,133 @@ const handleMessage = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
||||||
|
let lastId = await findObject(whatsappId, contactId, "ura");
|
||||||
|
const data: any = await get("ura");
|
||||||
|
|
||||||
|
console.log("lastId[0]: ", lastId[0]);
|
||||||
|
|
||||||
|
if (!lastId[0]) {
|
||||||
|
await createObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier: "ura",
|
||||||
|
value: data[1].id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lastId = await findObject(whatsappId, contactId, "ura");
|
||||||
|
console.log("LAST ID: ", lastId);
|
||||||
|
let option: any;
|
||||||
|
|
||||||
|
if (
|
||||||
|
lastId &&
|
||||||
|
lastId.length == 4 &&
|
||||||
|
lastId[3] &&
|
||||||
|
lastId[3].trim().length > 0
|
||||||
|
) {
|
||||||
|
option = data.find(
|
||||||
|
(o: any) =>
|
||||||
|
o.idmaster == lastId[3] &&
|
||||||
|
o.value.toLowerCase() == userTyped.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
// TEST DEL
|
||||||
|
console.log("OPTION: ", option);
|
||||||
|
|
||||||
|
if (!option && userTyped != "0") {
|
||||||
|
if (!existSubMenu()) {
|
||||||
|
const response = await mainOptionsMenu(userTyped);
|
||||||
|
if (response) return response;
|
||||||
|
else {
|
||||||
|
console.log("kkkkkkkkkkkkkkkkkkk");
|
||||||
|
await createObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier: "ura",
|
||||||
|
value: data[1].id
|
||||||
|
});
|
||||||
|
|
||||||
|
return data[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
if (option) {
|
||||||
|
let response: any = data.find((o: any) => o.idmaster == option.id);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRR response: ",
|
||||||
|
response,
|
||||||
|
" | option: ",
|
||||||
|
option
|
||||||
|
);
|
||||||
|
|
||||||
|
await createObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier: "ura",
|
||||||
|
value: response.id
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} else if (userTyped == "0") {
|
||||||
|
await createObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier: "ura",
|
||||||
|
value: data[1].id
|
||||||
|
});
|
||||||
|
|
||||||
|
return data[1];
|
||||||
|
} else {
|
||||||
|
console.log("INVALID SEARCH");
|
||||||
|
|
||||||
|
let response = await existSubMenu();
|
||||||
|
if (response) return response;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: data.find((o: any) => o.id == lastId[3])?.value
|
||||||
|
};
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// value: `Você digitou uma opçao inválida!\n\n${
|
||||||
|
// data.find((o: any) => o.id == lastId[3])?.value
|
||||||
|
// }\n\nDigite 0 para voltar ao menu `
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function existSubMenu() {
|
||||||
|
let existSubMenu = data.find((o: any) => o.idmaster == lastId[3]);
|
||||||
|
|
||||||
|
if (existSubMenu) true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mainOptionsMenu(userTyped: any) {
|
||||||
|
let menuOption = data.find(
|
||||||
|
(o: any) => o.value.toLowerCase() == userTyped.toLowerCase()
|
||||||
|
);
|
||||||
|
console.log("============> menuOption OPTION: ", menuOption);
|
||||||
|
if (menuOption) {
|
||||||
|
let response = data.find((o: any) => o.idmaster == menuOption.id);
|
||||||
|
if (response) {
|
||||||
|
await createObject({
|
||||||
|
whatsappId,
|
||||||
|
contactId,
|
||||||
|
identifier: "ura",
|
||||||
|
value: response.id
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleMsgAck = async (
|
const handleMsgAck = async (
|
||||||
msg_id: any,
|
msg_id: any,
|
||||||
ack: any,
|
ack: any,
|
||||||
|
|
|
@ -161,7 +161,9 @@ const TicketsManager = () => {
|
||||||
let searchContentTimeout;
|
let searchContentTimeout;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user.profile.toUpperCase() === "ADMIN") {
|
if (user.profile.toUpperCase() === "ADMIN" ||
|
||||||
|
user.profile.toUpperCase() === "SUPERVISOR" ||
|
||||||
|
user.profile.toUpperCase() === "MASTER") {
|
||||||
setShowAllTickets(true);
|
setShowAllTickets(true);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
|
|
@ -9,7 +9,8 @@ const rules = {
|
||||||
"user-view:show",
|
"user-view:show",
|
||||||
"user-modal:editQueues",
|
"user-modal:editQueues",
|
||||||
'dashboard-view:show',
|
'dashboard-view:show',
|
||||||
'ticket-report:show'
|
'ticket-report:show',
|
||||||
|
'tickets-manager:showall'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue