projeto-hit/backend/src/controllers/TicketController.ts

701 lines
19 KiB
TypeScript
Raw Normal View History

import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import CreateTicketService from "../services/TicketServices/CreateTicketService";
import DeleteTicketService from "../services/TicketServices/DeleteTicketService";
import ListTicketsService from "../services/TicketServices/ListTicketsService";
import ShowTicketService from "../services/TicketServices/ShowTicketService";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
2023-07-26 20:24:10 +00:00
import ShowStatusChatEndService from "../services/StatusChatEndService/ShowStatusChatEndService";
import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService";
import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService";
2023-07-26 20:24:10 +00:00
import { isScheduling } from "../helpers/CheckSchedulingReminderNotify";
2023-07-26 20:24:10 +00:00
import ptBR from "date-fns/locale/pt-BR";
import { splitDateTime } from "../helpers/SplitDateTime";
2023-07-26 20:24:10 +00:00
import format from "date-fns/format";
import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";
2023-07-26 20:24:10 +00:00
import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache";
import { Op, where } from "sequelize";
type IndexQuery = {
searchParam: string;
pageNumber: string;
status: string;
date: string;
showAll: string;
withUnreadMessages: string;
queueIds: string;
unlimited?: string;
2023-07-26 20:24:10 +00:00
searchParamContent?: string;
};
interface TicketData {
contactId: number;
status: string;
queueId: number;
userId: number;
2023-07-26 20:24:10 +00:00
whatsappId?: string | number;
msg?: string;
transfer?: boolean | undefined;
fromMe?: boolean;
}
import ListStatusChatEndService from "../services/StatusChatEndService/ListStatusChatEndService";
2022-05-03 21:20:58 +00:00
import Ticket from "../models/Ticket";
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
import TicketEmiterSumOpenClosedByUser from "../helpers/OnlineReporEmiterInfoByUser";
import CountTicketService from "../services/TicketServices/CountTicketService";
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
import ShowUserService from "../services/UserServices/ShowUserService";
import axios from "axios";
import User from "../models/User";
import CheckContactOpenTickets from "../helpers/CheckContactOpenTickets";
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
import { getWbot } from "../libs/wbot";
import endPointQuery from "../helpers/old_EndPointQuery";
import Contact from "../models/Contact";
import BotIsOnQueue from "../helpers/BotIsOnQueue";
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import Whatsapp from "../models/Whatsapp";
import AppError from "../errors/AppError";
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import CreateContactService from "../services/ContactServices/CreateContactService";
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
import WhatsappQueue from "../models/WhatsappQueue";
import { del, get, set } from "../helpers/RedisClient";
2024-04-01 20:06:11 +00:00
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService";
import Queue from "../models/Queue";
import StatusChatEnd from "../models/StatusChatEnd";
import controllByNumber from "../helpers/controllByNumber";
2024-04-01 20:06:11 +00:00
export const index = async (req: Request, res: Response): Promise<Response> => {
const {
pageNumber,
status,
date,
searchParam,
showAll,
queueIds: queueIdsStringified,
withUnreadMessages,
unlimited,
searchParamContent
} = req.query as IndexQuery;
const userId = req.user.id;
let queueIds: number[] = [];
if (queueIdsStringified && queueIdsStringified.trim().length > 0) {
queueIds = JSON.parse(queueIdsStringified);
}
const { tickets, count, hasMore, remoteTicketsControll } =
await ListTicketsService({
searchParam,
pageNumber,
status,
date,
showAll,
userId,
queueIds,
withUnreadMessages,
unlimited,
searchParamContent
});
2024-04-01 20:06:11 +00:00
return res
.status(200)
.json({ tickets, count, hasMore, remoteTicketsControll });
};
export const remoteTicketCreation = async (
req: Request,
res: Response
): Promise<Response> => {
let { queueId, contact_from, cc, contact_to, msg, contact_name }: any =
req.body;
let whatsappId: any;
if (!queueId && !contact_from && !cc) {
return res.status(400).json({
error: `Property 'queueId' or 'contact_from' or 'cc' is required.`
});
}
const validate = ["contact_to", "msg"];
const validateOnlyNumber = ["queueId", "contact_to", "contact_from"];
for (let prop of validate) {
if (!req.body[prop])
return res
.status(400)
.json({ error: `Property '${prop}' is undefined.` });
if (validateOnlyNumber.includes(prop)) {
if (!/^\d+$/.test(req.body[prop])) {
return res
.status(400)
.json({ error: `The property '${prop}' must be a number` });
}
}
}
if (queueId) {
const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED");
if (!whatsapps || whatsapps?.length == 0) {
return res.status(500).json({
msg: `queueId ${queueId} does not have a WhatsApp number associated with it or the number's session is disconnected.`
});
}
const { id } = whatsapps[0];
whatsappId = id;
} else if (contact_from) {
const whatsapp = await Whatsapp.findOne({
where: { number: contact_from, status: "CONNECTED" }
});
if (!whatsapp) {
return res.status(404).json({
msg: `Whatsapp number ${contact_from} not found or disconnected!`
});
}
const { id } = whatsapp;
const { queues } = await ShowWhatsAppService(id);
if (!queues || queues.length == 0) {
return res.status(500).json({
msg: `The WhatsApp number ${contact_from} is not associated with any queue! `
});
}
queueId = queues[0].id;
whatsappId = id;
} else if (cc) {
const queue = await Queue.findOne({ where: { cc } });
if (!queue) {
return res.status(404).json({
msg: `Queue with cc ${cc} not found! `
});
}
queueId = queue.id;
const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED");
if (whatsapps.length === 0) {
return res.status(500).json({
msg: `No WhatsApp found for this cc ${cc} or the WhatsApp number is disconnected! `
});
}
whatsappId = whatsapps[0].id;
}
// const validNumber = await CheckIsValidContact(contact_to, true);
const validNumber = contact_to;
if (validNumber) {
let contact = await Contact.findOne({ where: { number: validNumber } });
if (!contact) {
// const profilePicUrl = await GetProfilePicUrl(validNumber);
contact = await CreateContactService({
name: contact_name ? contact_name : contact_to,
number: validNumber
// profilePicUrl
});
const io = getIO();
io.emit("contact", {
action: "create",
contact
});
}
const { id: contactId } = contact;
const botInfo = await BotIsOnQueue("botqueue");
// ticket from queueChoice or bot
let ticket: any = await Ticket.findOne({
where: {
[Op.or]: [
{ contactId, status: "queueChoice" },
{ contactId, status: "open", userId: botInfo.userIdBot }
]
}
});
if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
if (ticket) {
await UpdateTicketService({
ticketData: { status: "closed" },
ticketId: ticket.id
});
ticket = null;
}
} else {
if (ticket) {
await UpdateTicketService({
ticketData: { status: "closed" },
ticketId: ticket.id
});
}
}
ticket = await Ticket.findOne({
where: {
[Op.or]: [
{ contactId, status: "pending" },
{ contactId, status: "open" }
]
}
});
if (ticket) {
console.log(
`THE CAMPAIGN TICKET WAS NOT CREATED BECAUSE THE TICKET IS PENDING OR OPEN`
);
return res.status(422).json({
msg: `The campaign ticket was not created because the number ${contact_to} already has a ticket open or pending`
});
}
ticket = await FindOrCreateTicketService(
contact,
whatsappId,
0,
undefined,
queueId,
true
);
// botSendMessage(ticket, `${msg}`);
await ticket.update({
lastMessage: msg
});
await set(
`remote:ticketId:${ticket.id}`,
JSON.stringify({
id: ticket.id,
createdAt: ticket.createdAt,
updatedAt: ticket.updatedAt,
whatsappId: ticket.whatsappId
})
);
const io = getIO();
io.to(ticket.status).emit("ticket", {
action: "update",
ticket
});
const obj = await controllByNumber();
if (obj?.tickets) {
io.emit("remoteTickesControll", {
action: "update",
tickets: obj.ticketIds
});
}
console.log(
`REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 200 | MSG: success`
);
return res.status(200).json({ msg: "success" });
}
console.log(
`REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: The number ${contact_to} does not exist on WhatsApp`
);
return res
.status(500)
.json({ msg: `The number ${contact_to} does not exist on WhatsApp` });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
2023-09-08 19:50:51 +00:00
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
req.body;
const botInfo = await BotIsOnQueue("botqueue");
let ticket = await Ticket.findOne({
where: {
[Op.or]: [
{ contactId, status: "queueChoice" },
{ contactId, status: "open", userId: botInfo.userIdBot }
]
}
});
2022-05-03 21:20:58 +00:00
if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
if (ticket) {
await UpdateTicketService({
ticketData: { status: "closed" },
ticketId: ticket.id
});
ticket = null;
}
2023-07-26 20:24:10 +00:00
} else {
if (ticket) {
await UpdateTicketService({
ticketData: { status: "open", userId: userId, queueId },
ticketId: ticket.id
});
}
}
if (!ticket) {
ticket = await CreateTicketService({
contactId,
status,
userId,
queueId,
whatsappId
});
}
const io = getIO();
io.to(ticket.status).emit("ticket", {
action: "update",
ticket
});
return res.status(200).json(ticket);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
const contact = await ShowTicketService(ticketId);
2023-07-26 20:24:10 +00:00
const { statusChatEnd, count, hasMore } = await ListStatusChatEndService({
searchParam: "",
pageNumber: "1"
});
//////////////////
2023-07-26 20:24:10 +00:00
const schedulesContact = await ListSchedulingNotifyContactService(
contact.contact.number
);
/////////////////
return res.status(200).json({ contact, statusChatEnd, schedulesContact });
};
export const count = async (req: Request, res: Response): Promise<Response> => {
// type indexQ = { status: string; date?: string; };
const { status, date, queueIds } = req.query as IndexQuery;
const ticketCount = await CountTicketService(status, date, queueIds);
return res.status(200).json(ticketCount);
};
2023-07-26 20:24:10 +00:00
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
console.log("ENTROU NO UPDATE TICKET CONTROLLER");
const { ticketId } = req.params;
2023-07-26 20:24:10 +00:00
const userOldInfo = await Ticket.findByPk(ticketId);
2023-07-26 20:24:10 +00:00
let ticket2 = {};
2023-07-26 20:24:10 +00:00
if (req.body["status"] === "closed") {
const { status, userId, schedulingNotifyData } = req.body;
// lembrete
2023-07-26 20:24:10 +00:00
const scheduleData = JSON.parse(schedulingNotifyData);
console.log("scheduleData: ", scheduleData);
const statusChatEnd = await ShowStatusChatEndService({
name: scheduleData.statusChatEndName
});
const { ticket } = await UpdateTicketService({
2023-07-26 20:24:10 +00:00
ticketData: {
status: status,
userId: userId,
statusChatEnd: statusChatEnd.name,
statusChatEndId: statusChatEnd.id
2023-07-26 20:24:10 +00:00
},
ticketId
});
let _farewellMessage;
if (getSettingValue("farewellMessageByStatusChatEnd")?.value == "enabled") {
const statusChatEndData = await get({
key: `statusChatEnd:${statusChatEnd.id}`,
parse: true
});
if (
statusChatEndData &&
statusChatEndData?.farewellMessage &&
statusChatEndData?.farewellMessage?.trim()?.length > 0
) {
const { farewellMessage } = statusChatEndData;
_farewellMessage = farewellMessage;
}
} else if (getSettingValue("farewellMessageByQueue")?.value == "enabled") {
const queueData = await get({
key: `queue:${ticket.queueId}`,
parse: true
});
if (
queueData &&
queueData?.farewellMessage &&
queueData?.farewellMessage?.trim()?.length > 0
) {
const { farewellMessage } = queueData;
_farewellMessage = farewellMessage;
}
} else if (scheduleData.farewellMessage) {
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
const { farewellMessage } = whatsapp;
if (farewellMessage) {
_farewellMessage = farewellMessage;
}
}
if (_farewellMessage) {
await SendWhatsAppMessage({ body: `\u200e${_farewellMessage}`, ticket });
}
console.log("tatusChatEnd.name: ", statusChatEnd.name);
2023-07-26 20:24:10 +00:00
if (
statusChatEnd.name === "LEMBRETE" ||
statusChatEnd.name === "AGENDAMENTO À CONFIRMAR"
2023-07-26 20:24:10 +00:00
) {
// lembrete // agendamento
2023-07-26 20:24:10 +00:00
if (
isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)
) {
console.log("*** É AGENDAMENTO!");
} else {
console.log("*** É LEMBRETE!");
}
2023-07-26 20:24:10 +00:00
const schedulingNotifyCreate = await CreateSchedulingNotifyService({
ticketId: scheduleData.ticketId,
statusChatEndId: `${statusChatEnd.id}`,
2023-07-26 20:24:10 +00:00
schedulingDate: scheduleData.schedulingDate,
schedulingTime: scheduleData.schedulingTime,
message: scheduleData.message
});
}
2023-07-26 20:24:10 +00:00
ticket2 = ticket;
} else {
// Para aparecer pendente para todos usuarios que estao na fila
if (req.body.transfer) {
2023-07-26 20:24:10 +00:00
req.body.userId = null;
}
let ticketData: TicketData = req.body;
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
2023-07-26 20:24:10 +00:00
if (ticketData.transfer) {
const whatsappsByqueue = await ListWhatsAppsForQueueService(
ticketData.queueId
);
if (userOldInfo) {
let listTicketOpenPending: any = [];
for (const w of whatsappsByqueue) {
let whats = await ListWhatsAppsNumber(w.id);
const ticket = await Ticket.findOne({
where: {
[Op.and]: [
{ contactId: userOldInfo.contactId },
{
whatsappId: {
[Op.in]: whats.whatsapps.map((w: any) => w.id)
}
},
{ status: { [Op.or]: ["open", "pending"] } }
]
}
});
if (ticket) {
listTicketOpenPending.push({
ticketId: ticket.id,
status: ticket.status,
userId: ticket.userId,
contactId: ticket.contactId,
whatsappId: ticket.whatsappId,
queueId: ticket.queueId
});
}
}
// console.log("userOldInfo: ", JSON.stringify(userOldInfo, null, 6));
// console.log("##########")
// console.log(
// "listTicketOpenPending: ",
// JSON.stringify(listTicketOpenPending)
// );
if (
listTicketOpenPending.filter(
(ob: any) => userOldInfo.whatsappId != ob.whatsappId
)?.length > 0
) {
throw new AppError("ERR_OTHER_OPEN_TICKET");
}
}
//////////////////////////////////////////////
// const defaultWhatsapp: any = await GetDefaultWhatsApp({
// userId: ticketData.userId
// });
// console.log(
// "ticketData.userId: ",
// ticketData.userId,
// " | defaultWhatsapp: ",
// JSON.stringify(defaultWhatsapp, null, 6)
// );
// const _ticket: any = await Ticket.findByPk(ticketId);
// if (defaultWhatsapp && ticketData.status != "open") {
// await CheckContactOpenTickets(
// _ticket.dataValues.contactId,
// defaultWhatsapp.dataValues.id
// );
// }
// ticketData.whatsappId = defaultWhatsapp.dataValues.id;
2023-07-26 20:24:10 +00:00
}
}
2023-07-26 20:24:10 +00:00
console.log(
"--------> ticketData.status: ",
ticketData.status,
" | ticketData.fromMe: ",
ticketData.fromMe
);
const { ticket } = await UpdateTicketService({
ticketData,
2023-07-26 20:24:10 +00:00
ticketId
});
2023-07-26 20:24:10 +00:00
if (ticketData.status == "open" && !ticketData.fromMe) {
await setMessageAsRead(ticket);
}
if (ticketData.userId) {
2023-07-26 20:24:10 +00:00
const dateToday = splitDateTime(
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
);
TicketEmiterSumOpenClosedByUser(
ticketData.userId.toString(),
dateToday.fullDate,
dateToday.fullDate
);
}
2023-07-26 20:24:10 +00:00
ticket2 = ticket;
}
if (userOldInfo) {
2023-07-26 20:24:10 +00:00
const dateToday = splitDateTime(
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
);
if (userOldInfo.userId) {
2023-07-26 20:24:10 +00:00
TicketEmiterSumOpenClosedByUser(
userOldInfo.userId.toString(),
dateToday.fullDate,
dateToday.fullDate
);
}
}
return res.status(200).json(ticket2);
};
// export const update = async (
// req: Request,
// res: Response
// ): Promise<Response> => {
// const { ticketId } = req.params;
// const ticketData: TicketData = req.body;
// const { ticket } = await UpdateTicketService({
// ticketData,
// ticketId
// });
// if (ticket.status === "closed") {
// const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
// const { farewellMessage } = whatsapp;
// if (farewellMessage) {
// await SendWhatsAppMessage({ body: farewellMessage, ticket });
// }
// }
// return res.status(200).json(ticket);
// };
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { ticketId } = req.params;
const ticket = await DeleteTicketService(ticketId);
const io = getIO();
2023-07-26 20:24:10 +00:00
io.to(ticket.status).to(ticketId).to("notification").emit("ticket", {
action: "delete",
ticketId: +ticketId
});
await del(`remote:ticketId:${ticketId}`);
return res.status(200).json({ message: "ticket deleted" });
};