Merge branch 'el_lojas_melhorias' of https://github.com/AdrianoRobson/projeto-hit into el_lojas_melhorias
						commit
						024c6920af
					
				| 
						 | 
					@ -183,11 +183,17 @@ socketIo.on('connect_error', async function (err) {
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const wwebVersion = '2.2402.5';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//NOVA OPÇÃO MD
 | 
					//NOVA OPÇÃO MD
 | 
				
			||||||
client = new Client({
 | 
					client = new Client({
 | 
				
			||||||
    authStrategy: new LocalAuth({ clientId: 'omnihit_sesssion' }),
 | 
					    authStrategy: new LocalAuth({ clientId: 'omnihit_sesssion' }),
 | 
				
			||||||
    puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
 | 
					    puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
 | 
				
			||||||
 | 
					    webVersionCache: {
 | 
				
			||||||
 | 
					        type: 'remote',
 | 
				
			||||||
 | 
					        remotePath: `https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/${wwebVersion}.html`,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
client.initialize()
 | 
					client.initialize()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,9 @@ import UpdateQueueService from "../services/QueueService/UpdateQueueService";
 | 
				
			||||||
import Queue from "../models/Queue";
 | 
					import Queue from "../models/Queue";
 | 
				
			||||||
import AppError from "../errors/AppError";
 | 
					import AppError from "../errors/AppError";
 | 
				
			||||||
import { del, get, set } from "../helpers/RedisClient";
 | 
					import { del, get, set } from "../helpers/RedisClient";
 | 
				
			||||||
 | 
					import { Op } from "sequelize";
 | 
				
			||||||
 | 
					import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService";
 | 
				
			||||||
 | 
					import Whatsapp from "../models/Whatsapp";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
 | 
					export const index = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
  const queues = await ListQueuesService();
 | 
					  const queues = await ListQueuesService();
 | 
				
			||||||
| 
						 | 
					@ -15,6 +18,58 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
  return res.status(200).json(queues);
 | 
					  return res.status(200).json(queues);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const listQueues = async (
 | 
				
			||||||
 | 
					  req: Request,
 | 
				
			||||||
 | 
					  res: Response
 | 
				
			||||||
 | 
					): Promise<Response> => {
 | 
				
			||||||
 | 
					  const whatsapps = await Whatsapp.findAll({
 | 
				
			||||||
 | 
					    where: {
 | 
				
			||||||
 | 
					      name: { [Op.ne]: "botqueue" },
 | 
				
			||||||
 | 
					      number: { [Op.ne]: "" },
 | 
				
			||||||
 | 
					      phoneNumberId: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    attributes: ["number"],
 | 
				
			||||||
 | 
					    include: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        model: Queue,
 | 
				
			||||||
 | 
					        as: "queues",
 | 
				
			||||||
 | 
					        attributes: ["id", "name"]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const whats = whatsapps
 | 
				
			||||||
 | 
					    ?.filter((w: any) => w?.queues?.length > 0)
 | 
				
			||||||
 | 
					    ?.map((w: any) => {
 | 
				
			||||||
 | 
					      const { number, queues } = w;
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        number,
 | 
				
			||||||
 | 
					        queues: queues?.map((q: any) => {
 | 
				
			||||||
 | 
					          const { id, name } = q;
 | 
				
			||||||
 | 
					          return { id, name };
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let _queues: any = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const w of whats) {
 | 
				
			||||||
 | 
					    const { queues } = w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const q of queues) {
 | 
				
			||||||
 | 
					      const { id: queueId, name } = q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const auxQueue = _queues.findIndex((q: any) => q.queueId == queueId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (auxQueue == -1) {
 | 
				
			||||||
 | 
					        _queues.push({ queueId, name });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return res.status(200).json(_queues);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
 | 
					export const store = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
  const { name, color, greetingMessage } = req.body;
 | 
					  const { name, color, greetingMessage } = req.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -262,9 +262,7 @@ export const reportMessagesUserByDateStartDateEnd = async (
 | 
				
			||||||
      data_query_messages[i].fromMe = "Cliente";
 | 
					      data_query_messages[i].fromMe = "Cliente";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data_query_messages[i].id = i + 1;
 | 
					    data_query_messages[i].id = i + 1; 
 | 
				
			||||||
 | 
					 | 
				
			||||||
    console.log("data_query_messages: ", data_query_messages[i]);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return res.status(200).json(data_query_messages);
 | 
					  return res.status(200).json(data_query_messages);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,14 +20,14 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // const config = await SettingTicket.findAll();
 | 
					  // const config = await SettingTicket.findAll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return res.status(200).json({ settings, });
 | 
					  return res.status(200).json({ settings });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ticketSettings = async (
 | 
					export const ticketSettings = async (
 | 
				
			||||||
  req: Request,
 | 
					  req: Request,
 | 
				
			||||||
  res: Response
 | 
					  res: Response
 | 
				
			||||||
): Promise<Response> => {
 | 
					): Promise<Response> => {
 | 
				
			||||||
  const { number } = req.params; 
 | 
					  const { number } = req.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const config = await SettingTicket.findAll({ where: { number } });
 | 
					  const config = await SettingTicket.findAll({ where: { number } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,7 @@ export const updateTicketSettings = async (
 | 
				
			||||||
): Promise<Response> => {
 | 
					): Promise<Response> => {
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    number,
 | 
					    number,
 | 
				
			||||||
 | 
					    saturdayBusinessTime,
 | 
				
			||||||
    outBusinessHours,
 | 
					    outBusinessHours,
 | 
				
			||||||
    ticketExpiration,
 | 
					    ticketExpiration,
 | 
				
			||||||
    weekend,
 | 
					    weekend,
 | 
				
			||||||
| 
						 | 
					@ -47,7 +48,7 @@ export const updateTicketSettings = async (
 | 
				
			||||||
    sunday,
 | 
					    sunday,
 | 
				
			||||||
    holiday
 | 
					    holiday
 | 
				
			||||||
  } = req.body;
 | 
					  } = req.body;
 | 
				
			||||||
 
 | 
					
 | 
				
			||||||
  if (!number) throw new AppError("No number selected", 400);
 | 
					  if (!number) throw new AppError("No number selected", 400);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (outBusinessHours && Object.keys(outBusinessHours).length > 0) {
 | 
					  if (outBusinessHours && Object.keys(outBusinessHours).length > 0) {
 | 
				
			||||||
| 
						 | 
					@ -58,6 +59,14 @@ export const updateTicketSettings = async (
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (saturdayBusinessTime && Object.keys(saturdayBusinessTime).length > 0) {
 | 
				
			||||||
 | 
					    await updateSettingTicket({
 | 
				
			||||||
 | 
					      ...saturdayBusinessTime,
 | 
				
			||||||
 | 
					      key: "saturdayBusinessTime",
 | 
				
			||||||
 | 
					      number
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
 | 
					  if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
 | 
				
			||||||
    await updateSettingTicket({
 | 
					    await updateSettingTicket({
 | 
				
			||||||
      ...ticketExpiration,
 | 
					      ...ticketExpiration,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,10 +75,10 @@ import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
 | 
				
			||||||
import CreateContactService from "../services/ContactServices/CreateContactService";
 | 
					import CreateContactService from "../services/ContactServices/CreateContactService";
 | 
				
			||||||
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
 | 
					import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
 | 
				
			||||||
import WhatsappQueue from "../models/WhatsappQueue";
 | 
					import WhatsappQueue from "../models/WhatsappQueue";
 | 
				
			||||||
import { get } from "../helpers/RedisClient"
 | 
					import { get } from "../helpers/RedisClient";
 | 
				
			||||||
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService"
 | 
					import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const index = async (req: Request, res: Response): Promise<Response> => {  
 | 
					export const index = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    pageNumber,
 | 
					    pageNumber,
 | 
				
			||||||
    status,
 | 
					    status,
 | 
				
			||||||
| 
						 | 
					@ -110,8 +110,8 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
    withUnreadMessages,
 | 
					    withUnreadMessages,
 | 
				
			||||||
    unlimited,
 | 
					    unlimited,
 | 
				
			||||||
    searchParamContent
 | 
					    searchParamContent
 | 
				
			||||||
  }); 
 | 
					  });
 | 
				
			||||||
 
 | 
					
 | 
				
			||||||
  return res.status(200).json({ tickets, count, hasMore });
 | 
					  return res.status(200).json({ tickets, count, hasMore });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,10 +119,10 @@ export const remoteTicketCreation = async (
 | 
				
			||||||
  req: Request,
 | 
					  req: Request,
 | 
				
			||||||
  res: Response
 | 
					  res: Response
 | 
				
			||||||
): Promise<Response> => {
 | 
					): Promise<Response> => {
 | 
				
			||||||
  const { contact_from, contact_to, msg, contact_name }: any = req.body;
 | 
					  const { queueId, contact_to, msg, contact_name }: any = req.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const validate = ["contact_from", "contact_to", "msg"];
 | 
					  const validate = ["queueId", "contact_to", "msg"];
 | 
				
			||||||
  const validateOnlyNumber = ["contact_from", "contact_to"];
 | 
					  const validateOnlyNumber = ["queueId", "contact_to"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (let prop of validate) {
 | 
					  for (let prop of validate) {
 | 
				
			||||||
    if (!req.body[prop])
 | 
					    if (!req.body[prop])
 | 
				
			||||||
| 
						 | 
					@ -139,109 +139,97 @@ export const remoteTicketCreation = async (
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const whatsapp = await Whatsapp.findOne({
 | 
					  const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED"); 
 | 
				
			||||||
    where: { number: contact_from, status: "CONNECTED" }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (whatsapp) {
 | 
					  if (!whatsapps || whatsapps?.length == 0) {
 | 
				
			||||||
    const { id: whatsappId, number, status } = whatsapp;
 | 
					    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 queue: any = await WhatsappQueue.findOne({
 | 
					 | 
				
			||||||
      where: { whatsappId },
 | 
					 | 
				
			||||||
      attributes: ["queueId"]
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { queueId } = queue;
 | 
					  const { id: whatsappId } = whatsapps[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // const validNumber = await CheckIsValidContact(contact_to, true);
 | 
					  // const validNumber = await CheckIsValidContact(contact_to, true);
 | 
				
			||||||
    const validNumber = contact_to;
 | 
					  const validNumber = contact_to;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (validNumber) {
 | 
					  if (validNumber) {
 | 
				
			||||||
      let contact = await Contact.findOne({ where: { number: validNumber } });
 | 
					    let contact = await Contact.findOne({ where: { number: validNumber } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!contact) {
 | 
					    if (!contact) {
 | 
				
			||||||
        // const profilePicUrl = await GetProfilePicUrl(validNumber);
 | 
					      // const profilePicUrl = await GetProfilePicUrl(validNumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        contact = await CreateContactService({
 | 
					      contact = await CreateContactService({
 | 
				
			||||||
          name: contact_name ? contact_name : contact_to,
 | 
					        name: contact_name ? contact_name : contact_to,
 | 
				
			||||||
          number: validNumber
 | 
					        number: validNumber
 | 
				
			||||||
          // profilePicUrl
 | 
					        // profilePicUrl
 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const io = getIO();
 | 
					 | 
				
			||||||
        io.emit("contact", {
 | 
					 | 
				
			||||||
          action: "create",
 | 
					 | 
				
			||||||
          contact
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const { id: contactId } = contact;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const botInfo = await BotIsOnQueue("botqueue");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      let ticket = 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
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (!ticket) {
 | 
					 | 
				
			||||||
        ticket = await FindOrCreateTicketService(
 | 
					 | 
				
			||||||
          contact,
 | 
					 | 
				
			||||||
          whatsappId,
 | 
					 | 
				
			||||||
          0,
 | 
					 | 
				
			||||||
          undefined,
 | 
					 | 
				
			||||||
          queueId
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        botSendMessage(ticket, msg);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const io = getIO();
 | 
					      const io = getIO();
 | 
				
			||||||
      io.to(ticket.status).emit("ticket", {
 | 
					      io.emit("contact", {
 | 
				
			||||||
        action: "update",
 | 
					        action: "create",
 | 
				
			||||||
        ticket
 | 
					        contact
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					 | 
				
			||||||
      console.log(
 | 
					 | 
				
			||||||
        `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 200 | MSG: success`
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      return res.status(200).json({ msg: "success" });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { id: contactId } = contact;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const botInfo = await BotIsOnQueue("botqueue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let ticket = 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
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!ticket) {
 | 
				
			||||||
 | 
					      ticket = await FindOrCreateTicketService(
 | 
				
			||||||
 | 
					        contact,
 | 
				
			||||||
 | 
					        whatsappId,
 | 
				
			||||||
 | 
					        0,
 | 
				
			||||||
 | 
					        undefined,
 | 
				
			||||||
 | 
					        queueId
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      botSendMessage(ticket, `${msg}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const io = getIO();
 | 
				
			||||||
 | 
					    io.to(ticket.status).emit("ticket", {
 | 
				
			||||||
 | 
					      action: "update",
 | 
				
			||||||
 | 
					      ticket
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.log(
 | 
					    console.log(
 | 
				
			||||||
      `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: The number ${contact_to} does not exist on WhatsApp`
 | 
					      `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 200 | MSG: success`
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    return res
 | 
					    return res.status(200).json({ msg: "success" });
 | 
				
			||||||
      .status(500)
 | 
					 | 
				
			||||||
      .json({ msg: `The number ${contact_to} does not exist on WhatsApp` });
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log(
 | 
					  console.log(
 | 
				
			||||||
    `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: Whatsapp number ${contact_from} disconnected or it doesn't exist in omnihit`
 | 
					    `REMOTE TICKET CREATION FROM ENDPOINT | STATUS: 500 | MSG: The number ${contact_to} does not exist on WhatsApp`
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  return res.status(500).json({
 | 
					  return res
 | 
				
			||||||
    msg: `Whatsapp number ${contact_from} disconnected or it doesn't exist in omnihit`
 | 
					    .status(500)
 | 
				
			||||||
  });
 | 
					    .json({ msg: `The number ${contact_to} does not exist on WhatsApp` });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
 | 
					export const store = async (req: Request, res: Response): Promise<Response> => {
 | 
				
			||||||
| 
						 | 
					@ -408,7 +396,6 @@ export const update = async (
 | 
				
			||||||
          for (const w of whatsappsByqueue) {
 | 
					          for (const w of whatsappsByqueue) {
 | 
				
			||||||
            let whats = await ListWhatsAppsNumber(w.id);
 | 
					            let whats = await ListWhatsAppsNumber(w.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            console.log("-------> WHATS: ", JSON.stringify(whats, null, 6));
 | 
					 | 
				
			||||||
            const ticket = await Ticket.findOne({
 | 
					            const ticket = await Ticket.findOne({
 | 
				
			||||||
              where: {
 | 
					              where: {
 | 
				
			||||||
                [Op.and]: [
 | 
					                [Op.and]: [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					import { QueryInterface } from "sequelize";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  up: (queryInterface: QueryInterface) => {
 | 
				
			||||||
 | 
					    return queryInterface.bulkInsert(
 | 
				
			||||||
 | 
					      "SettingTickets",
 | 
				
			||||||
 | 
					      [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          message: "",
 | 
				
			||||||
 | 
					          startTime: new Date(),
 | 
				
			||||||
 | 
					          endTime: new Date(),
 | 
				
			||||||
 | 
					          value: "disabled",
 | 
				
			||||||
 | 
					          key: "saturdayBusinessTime",
 | 
				
			||||||
 | 
					          createdAt: new Date(),
 | 
				
			||||||
 | 
					          updatedAt: new Date()
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      {}
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  down: (queryInterface: QueryInterface) => {
 | 
				
			||||||
 | 
					    return queryInterface.bulkDelete("SettingTickets", {});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ const isHoliday = async (number: string | number) => {
 | 
				
			||||||
          locale: ptBR
 | 
					          locale: ptBR
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    ); 
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (currentDate.fullDate == startTime.fullDate) {
 | 
					    if (currentDate.fullDate == startTime.fullDate) {
 | 
				
			||||||
      obj.set = true;
 | 
					      obj.set = true;
 | 
				
			||||||
| 
						 | 
					@ -62,21 +62,8 @@ const isWeekend = async (number: string | number) => {
 | 
				
			||||||
    weekend.value == "enabled" &&
 | 
					    weekend.value == "enabled" &&
 | 
				
			||||||
    weekend.message?.trim()?.length > 0
 | 
					    weekend.message?.trim()?.length > 0
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    // Specify your desired timezone
 | 
					 | 
				
			||||||
    const brazilTimeZone = "America/Sao_Paulo";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const currentDateUtc = new Date();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Convert UTC date to Brazil time zone
 | 
					 | 
				
			||||||
    const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Format the date using the desired format
 | 
					 | 
				
			||||||
    const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const parsedDate = parseISO(formattedDate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Convert parsed date to Brazil time zone
 | 
					    // Convert parsed date to Brazil time zone
 | 
				
			||||||
    const localDate = utcToZonedTime(parsedDate, brazilTimeZone);
 | 
					    const localDate = localDateConvert();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Check if it's Saturday or Sunday
 | 
					    // Check if it's Saturday or Sunday
 | 
				
			||||||
    if (isSaturday(localDate)) {
 | 
					    if (isSaturday(localDate)) {
 | 
				
			||||||
| 
						 | 
					@ -173,8 +160,104 @@ async function isOutBusinessTime(number: string | number) {
 | 
				
			||||||
  return obj;
 | 
					  return obj;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					async function isOutBusinessTimeSaturday(number: string | number) {
 | 
				
			||||||
  isWeekend,
 | 
					  let obj = { set: false, msg: "" };
 | 
				
			||||||
  isHoliday,
 | 
					
 | 
				
			||||||
  isOutBusinessTime
 | 
					  // Convert parsed date to Brazil time zone
 | 
				
			||||||
};
 | 
					  const localDate = localDateConvert();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Check if it's Saturday or Sunday
 | 
				
			||||||
 | 
					  if (!isSaturday(localDate)) {
 | 
				
			||||||
 | 
					    return obj;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const outBusinessHoursSaturday = await SettingTicket.findOne({
 | 
				
			||||||
 | 
					    where: { key: "saturdayBusinessTime", number }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let isWithinRange = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (
 | 
				
			||||||
 | 
					    outBusinessHoursSaturday &&
 | 
				
			||||||
 | 
					    outBusinessHoursSaturday.value == "enabled" &&
 | 
				
			||||||
 | 
					    outBusinessHoursSaturday?.message?.trim()?.length > 0
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    const ticketDateTimeUpdate = splitDateTime(
 | 
				
			||||||
 | 
					      new Date(
 | 
				
			||||||
 | 
					        _format(new Date(), "yyyy-MM-dd HH:mm:ss", {
 | 
				
			||||||
 | 
					          locale: ptBR
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const startTime = splitDateTime(
 | 
				
			||||||
 | 
					      new Date(
 | 
				
			||||||
 | 
					        _format(
 | 
				
			||||||
 | 
					          new Date(outBusinessHoursSaturday.startTime),
 | 
				
			||||||
 | 
					          "yyyy-MM-dd HH:mm:ss",
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            locale: ptBR
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const endTime = splitDateTime(
 | 
				
			||||||
 | 
					      new Date(
 | 
				
			||||||
 | 
					        _format(
 | 
				
			||||||
 | 
					          new Date(outBusinessHoursSaturday.endTime),
 | 
				
			||||||
 | 
					          "yyyy-MM-dd HH:mm:ss",
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            locale: ptBR
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const format = "HH:mm:ss";
 | 
				
			||||||
 | 
					    const parsedStartTime = parse(
 | 
				
			||||||
 | 
					      ticketDateTimeUpdate.fullTime,
 | 
				
			||||||
 | 
					      format,
 | 
				
			||||||
 | 
					      new Date()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const parsedEndTime = parse(startTime.fullTime, format, new Date());
 | 
				
			||||||
 | 
					    const parsedTimeToCheck = parse(endTime.fullTime, format, new Date());
 | 
				
			||||||
 | 
					    const timeInterval = { start: parsedStartTime, end: parsedEndTime };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If the time range spans across different days, handle the date part
 | 
				
			||||||
 | 
					    if (parsedEndTime < parsedStartTime) {
 | 
				
			||||||
 | 
					      const nextDay = new Date(parsedStartTime);
 | 
				
			||||||
 | 
					      nextDay.setDate(nextDay.getDate() + 1);
 | 
				
			||||||
 | 
					      timeInterval.end = nextDay;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    isWithinRange = isWithinInterval(parsedTimeToCheck, timeInterval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!isWithinRange) {
 | 
				
			||||||
 | 
					      obj.set = true;
 | 
				
			||||||
 | 
					      obj.msg = outBusinessHoursSaturday.message;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return obj;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function localDateConvert() {
 | 
				
			||||||
 | 
					  const brazilTimeZone = "America/Sao_Paulo";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const currentDateUtc = new Date();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Convert UTC date to Brazil time zone
 | 
				
			||||||
 | 
					  const currentDate = utcToZonedTime(currentDateUtc, brazilTimeZone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Format the date using the desired format
 | 
				
			||||||
 | 
					  const formattedDate = _format(currentDate, "yyyy-MM-dd HH:mm:ssXXX");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const parsedDate = parseISO(formattedDate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Convert parsed date to Brazil time zone
 | 
				
			||||||
 | 
					  const localDate = utcToZonedTime(parsedDate, brazilTimeZone);
 | 
				
			||||||
 | 
					  return localDate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { isWeekend, isHoliday, isOutBusinessTime, isOutBusinessTimeSaturday };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,10 +19,11 @@ const isAuth = (req: Request, res: Response, next: NextFunction): void => {
 | 
				
			||||||
    throw new AppError("ERR_SESSION_EXPIRED", 401);
 | 
					    throw new AppError("ERR_SESSION_EXPIRED", 401);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [, token] = authHeader.split(" ");  
 | 
					  const [, token] = authHeader.split(" ");   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (
 | 
					  if (
 | 
				
			||||||
    req.originalUrl == "/tickets/remote/create" &&
 | 
					    (req.originalUrl == "/queue/remote/list" ||
 | 
				
			||||||
 | 
					      req.originalUrl == "/tickets/remote/create") &&
 | 
				
			||||||
    token === process.env.TOKEN_REMOTE_TICKET_CREATION
 | 
					    token === process.env.TOKEN_REMOTE_TICKET_CREATION
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    return next();
 | 
					    return next();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,8 @@ queueRoutes.post("/queue", isAuth, QueueController.store);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
queueRoutes.post("/queue/customization", QueueController.customization);
 | 
					queueRoutes.post("/queue/customization", QueueController.customization);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					queueRoutes.get("/queue/remote/list", isAuth, QueueController.listQueues);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@ import { startOfDay, endOfDay, parseISO, getDate } from "date-fns";
 | 
				
			||||||
import { string } from "yup/lib/locale";
 | 
					import { string } from "yup/lib/locale";
 | 
				
			||||||
import Whatsapp from "../../models/Whatsapp";
 | 
					import Whatsapp from "../../models/Whatsapp";
 | 
				
			||||||
import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query";
 | 
					import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query";
 | 
				
			||||||
 | 
					import { te } from "date-fns/locale";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Request {
 | 
					interface Request {
 | 
				
			||||||
  userId: string | number;
 | 
					  userId: string | number;
 | 
				
			||||||
| 
						 | 
					@ -43,43 +44,56 @@ const ShowTicketReport = async ({
 | 
				
			||||||
  createdOrUpdated = "created",
 | 
					  createdOrUpdated = "created",
 | 
				
			||||||
  queueId
 | 
					  queueId
 | 
				
			||||||
}: Request): Promise<Response> => {
 | 
					}: Request): Promise<Response> => {
 | 
				
			||||||
  let where_clause: any = {};
 | 
					  // let where_clause: any = {};
 | 
				
			||||||
  let query = "";
 | 
					  // let query = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (userId !== "0") {
 | 
					  // if (userId !== "0") {
 | 
				
			||||||
    where_clause.userid = userId;
 | 
					  //   where_clause.userid = userId;
 | 
				
			||||||
    query = `AND t.userId = ${userId}`;
 | 
					  //   query = `AND t.userId = ${userId}`;
 | 
				
			||||||
  }
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // if (queueId) {
 | 
				
			||||||
 | 
					  //   where_clause.queueId = queueId;
 | 
				
			||||||
 | 
					  //   query = `AND t.queueId = ${queueId}`;
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const createdAtOrUpdatedAt =
 | 
				
			||||||
 | 
					    createdOrUpdated == "created" ? "createdAt" : "updatedAt";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let where_clause = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (queueId) {
 | 
					  if (queueId) {
 | 
				
			||||||
    where_clause.queueId = queueId;
 | 
					    where_clause = {
 | 
				
			||||||
    query = `AND t.queueId = ${queueId}`;
 | 
					      queueId: queueId,
 | 
				
			||||||
 | 
					      [createdAtOrUpdatedAt]: {
 | 
				
			||||||
 | 
					        [Op.gte]: startDate + " 00:00:00.000000",
 | 
				
			||||||
 | 
					        [Op.lte]: endDate + " 23:59:59.999999"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  } else if (userId == "0") {
 | 
				
			||||||
 | 
					    where_clause = {
 | 
				
			||||||
 | 
					      [createdAtOrUpdatedAt]: {
 | 
				
			||||||
 | 
					        [Op.gte]: startDate + " 00:00:00.000000",
 | 
				
			||||||
 | 
					        [Op.lte]: endDate + " 23:59:59.999999"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  } else if (userId != "0") {
 | 
				
			||||||
 | 
					    where_clause = {
 | 
				
			||||||
 | 
					      userid: userId,
 | 
				
			||||||
 | 
					      [createdAtOrUpdatedAt]: {
 | 
				
			||||||
 | 
					        [Op.gte]: startDate + " 00:00:00.000000",
 | 
				
			||||||
 | 
					        [Op.lte]: endDate + " 23:59:59.999999"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const limit = 40;
 | 
					  const limit = 40;
 | 
				
			||||||
  const offset = limit * (+pageNumber - 1);
 | 
					  const offset = limit * (+pageNumber - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const createdAtOrUpdatedAt =
 | 
					 | 
				
			||||||
    createdOrUpdated == "created" ? "createdAt" : "updatedAt";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const _ticketsId = await sequelize.query(
 | 
					 | 
				
			||||||
    `SELECT t.id
 | 
					 | 
				
			||||||
        FROM Tickets t
 | 
					 | 
				
			||||||
        INNER JOIN (
 | 
					 | 
				
			||||||
            SELECT DISTINCT ticketId
 | 
					 | 
				
			||||||
            FROM Messages
 | 
					 | 
				
			||||||
            WHERE ${createdAtOrUpdatedAt} >= '${startDate} 00:00:00' AND ${createdAtOrUpdatedAt} <= '${endDate} 23:59:59'
 | 
					 | 
				
			||||||
        ) AS m ON m.ticketId = t.id ${query};`,
 | 
					 | 
				
			||||||
    { type: QueryTypes.SELECT }
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let { count, rows: tickets }: any = await Ticket.findAndCountAll({
 | 
					  let { count, rows: tickets }: any = await Ticket.findAndCountAll({
 | 
				
			||||||
    where: {
 | 
					    where: where_clause,
 | 
				
			||||||
      id: { [Op.in]: _ticketsId.map((t: any) => t.id) }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    limit,
 | 
					    limit,
 | 
				
			||||||
    offset,
 | 
					    offset,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    attributes: [
 | 
					    attributes: [
 | 
				
			||||||
      "id",
 | 
					      "id",
 | 
				
			||||||
      "status",
 | 
					      "status",
 | 
				
			||||||
| 
						 | 
					@ -151,43 +165,41 @@ const ShowTicketReport = async ({
 | 
				
			||||||
    throw new AppError("ERR_NO_TICKET_FOUND", 404);
 | 
					    throw new AppError("ERR_NO_TICKET_FOUND", 404);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const ticketIds = tickets.map((t: any) => t.id);
 | 
					  if (tickets.length > 0) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (ticketIds.length > 0) {
 | 
					 | 
				
			||||||
    const waiting_time: any = await sequelize.query(
 | 
					    const waiting_time: any = await sequelize.query(
 | 
				
			||||||
      `SELECT t.id as ticketId, t.status, TIME_FORMAT(
 | 
					      `SELECT t.id as ticketId, t.status, TIME_FORMAT(
 | 
				
			||||||
        SEC_TO_TIME( 
 | 
					        SEC_TO_TIME(
 | 
				
			||||||
                TIMESTAMPDIFF(
 | 
					                TIMESTAMPDIFF(
 | 
				
			||||||
                    SECOND,
 | 
					                    SECOND,
 | 
				
			||||||
                    (
 | 
					                    (
 | 
				
			||||||
                        SELECT createdAt 
 | 
					                        SELECT createdAt
 | 
				
			||||||
                        FROM Messages 
 | 
					                        FROM Messages
 | 
				
			||||||
                        WHERE ticketId = m.ticketId 
 | 
					                        WHERE ticketId = m.ticketId
 | 
				
			||||||
                        AND fromMe = 0 
 | 
					                        AND fromMe = 0
 | 
				
			||||||
                        ORDER BY createdAt ASC 
 | 
					                        ORDER BY createdAt ASC
 | 
				
			||||||
                        LIMIT 1
 | 
					                        LIMIT 1
 | 
				
			||||||
                    ), 
 | 
					                    ),
 | 
				
			||||||
                    (
 | 
					                    (
 | 
				
			||||||
                        SELECT createdAt 
 | 
					                        SELECT createdAt
 | 
				
			||||||
                        FROM Messages 
 | 
					                        FROM Messages
 | 
				
			||||||
                        WHERE ticketId = m.ticketId 
 | 
					                        WHERE ticketId = m.ticketId
 | 
				
			||||||
                        AND fromAgent = 1 
 | 
					                        AND fromAgent = 1
 | 
				
			||||||
                        ORDER BY createdAt ASC 
 | 
					                        ORDER BY createdAt ASC
 | 
				
			||||||
                        LIMIT 1
 | 
					                        LIMIT 1
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                ) 
 | 
					                )
 | 
				
			||||||
        ), '%H:%i:%s') AS WAITING_TIME      
 | 
					        ), '%H:%i:%s') AS WAITING_TIME
 | 
				
			||||||
    FROM Tickets t 
 | 
					    FROM Tickets t
 | 
				
			||||||
    JOIN Messages m ON t.id = m.ticketId
 | 
					    JOIN Messages m ON t.id = m.ticketId
 | 
				
			||||||
    JOIN Whatsapps w ON t.whatsappId = w.id
 | 
					    JOIN Whatsapps w ON t.whatsappId = w.id
 | 
				
			||||||
    JOIN Queues q ON q.id = t.queueId
 | 
					    JOIN Queues q ON q.id = t.queueId
 | 
				
			||||||
    WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999' 
 | 
					    WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
 | 
				
			||||||
      AND t.id IN (${ticketIds.join()})
 | 
					      AND t.id IN (${tickets.map((t: any) => t.id).join()})
 | 
				
			||||||
      AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id) 
 | 
					      AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
 | 
				
			||||||
      AND m.fromMe = 0  
 | 
					      AND m.fromMe = 0
 | 
				
			||||||
      AND t.status IN ('open', 'closed')
 | 
					      AND t.status IN ('open', 'closed')
 | 
				
			||||||
      HAVING WAITING_TIME IS NOT NULL
 | 
					      HAVING WAITING_TIME IS NOT NULL
 | 
				
			||||||
     ORDER BY 
 | 
					     ORDER BY
 | 
				
			||||||
        WAITING_TIME;`,
 | 
					        WAITING_TIME;`,
 | 
				
			||||||
      { type: QueryTypes.SELECT }
 | 
					      { type: QueryTypes.SELECT }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ import path from "path";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  isHoliday,
 | 
					  isHoliday,
 | 
				
			||||||
  isOutBusinessTime,
 | 
					  isOutBusinessTime,
 | 
				
			||||||
 | 
					  isOutBusinessTimeSaturday,
 | 
				
			||||||
  isWeekend
 | 
					  isWeekend
 | 
				
			||||||
} from "../../helpers/TicketConfig";
 | 
					} from "../../helpers/TicketConfig";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1221,6 +1222,13 @@ const outOfService = async (number: string) => {
 | 
				
			||||||
    objs.push({ type: "holiday", msg: holiday.msg });
 | 
					    objs.push({ type: "holiday", msg: holiday.msg });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // MESSAGE TO SATURDAY BUSINESS TIME
 | 
				
			||||||
 | 
					  const businessTimeSaturday = await isOutBusinessTimeSaturday(number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (businessTimeSaturday && businessTimeSaturday.set) {
 | 
				
			||||||
 | 
					    objs.push({ type: "saturdayBusinessTime", msg: businessTimeSaturday.msg });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // MESSAGES TO SATURDAY OR SUNDAY
 | 
					  // MESSAGES TO SATURDAY OR SUNDAY
 | 
				
			||||||
  const weekend: any = await isWeekend(number);
 | 
					  const weekend: any = await isWeekend(number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,17 +6,30 @@ const { QueryTypes } = require("sequelize");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const sequelize = new Sequelize(dbConfig);
 | 
					const sequelize = new Sequelize(dbConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ListWhatsAppsForQueueService = async (queueId: number | string): Promise<any> => {
 | 
					const ListWhatsAppsForQueueService = async (
 | 
				
			||||||
  const distinctWhatsapps = await sequelize.query(
 | 
					  queueId: number | string,
 | 
				
			||||||
    `SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId
 | 
					  status?: string
 | 
				
			||||||
FROM Whatsapps w
 | 
					): Promise<any> => {
 | 
				
			||||||
JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId}
 | 
					  let distinctWhatsapps: any;
 | 
				
			||||||
GROUP BY w.number;`,
 | 
					
 | 
				
			||||||
    { type: QueryTypes.SELECT }
 | 
					  if (status) { 
 | 
				
			||||||
  );
 | 
					    distinctWhatsapps = await sequelize.query(
 | 
				
			||||||
 | 
					      `SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId FROM Whatsapps w
 | 
				
			||||||
 | 
					     JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId} AND w.status = '${status}' 
 | 
				
			||||||
 | 
					     AND phoneNumberId = false 
 | 
				
			||||||
 | 
					     GROUP BY w.number;`,
 | 
				
			||||||
 | 
					      { type: QueryTypes.SELECT }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    distinctWhatsapps = await sequelize.query(
 | 
				
			||||||
 | 
					      `SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId FROM Whatsapps w
 | 
				
			||||||
 | 
					     JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId}
 | 
				
			||||||
 | 
					     GROUP BY w.number;`,
 | 
				
			||||||
 | 
					      { type: QueryTypes.SELECT }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return distinctWhatsapps;
 | 
					  return distinctWhatsapps;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ListWhatsAppsForQueueService;
 | 
					export default ListWhatsAppsForQueueService;
 | 
				
			||||||
 
 | 
					 | 
				
			||||||
| 
						 | 
					@ -77,8 +77,16 @@ const ConfigModal = ({ open, onClose, change }) => {
 | 
				
			||||||
    const initialState = {
 | 
					    const initialState = {
 | 
				
			||||||
        startTimeBus: new Date(),
 | 
					        startTimeBus: new Date(),
 | 
				
			||||||
        endTimeBus: new Date(),
 | 
					        endTimeBus: new Date(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        startTimeBusSaturday: new Date(),
 | 
				
			||||||
 | 
					        endTimeBusSaturday: new Date(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        messageBus: '',
 | 
					        messageBus: '',
 | 
				
			||||||
 | 
					        messageBusSaturday: '',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        businessTimeEnable: false,
 | 
					        businessTimeEnable: false,
 | 
				
			||||||
 | 
					        businessTimeEnableSaturday: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ticketTimeExpiration: new Date(),
 | 
					        ticketTimeExpiration: new Date(),
 | 
				
			||||||
        ticketExpirationMsg: '',
 | 
					        ticketExpirationMsg: '',
 | 
				
			||||||
        ticketExpirationEnable: false,
 | 
					        ticketExpirationEnable: false,
 | 
				
			||||||
| 
						 | 
					@ -115,13 +123,16 @@ const ConfigModal = ({ open, onClose, change }) => {
 | 
				
			||||||
                if (!selectedNumber) return
 | 
					                if (!selectedNumber) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const { data } = await api.get(`/settings/ticket/${selectedNumber}`)
 | 
					                const { data } = await api.get(`/settings/ticket/${selectedNumber}`)
 | 
				
			||||||
 
 | 
					
 | 
				
			||||||
                if (data?.config && data.config.length === 0) {
 | 
					                if (data?.config && data.config.length === 0) {
 | 
				
			||||||
                    setConfig(initialState)
 | 
					                    setConfig(initialState)
 | 
				
			||||||
                    return
 | 
					                    return
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
 | 
					                const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const saturdayBusinessTime = data.config.find((c) => c.key === "saturdayBusinessTime")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
 | 
					                const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
 | 
				
			||||||
                const saturday = data.config.find((c) => c.key === "saturday")
 | 
					                const saturday = data.config.find((c) => c.key === "saturday")
 | 
				
			||||||
                const sunday = data.config.find((c) => c.key === "sunday")
 | 
					                const sunday = data.config.find((c) => c.key === "sunday")
 | 
				
			||||||
| 
						 | 
					@ -134,6 +145,11 @@ const ConfigModal = ({ open, onClose, change }) => {
 | 
				
			||||||
                    messageBus: outBusinessHours.message,
 | 
					                    messageBus: outBusinessHours.message,
 | 
				
			||||||
                    businessTimeEnable: outBusinessHours.value === 'enabled' ? true : false,
 | 
					                    businessTimeEnable: outBusinessHours.value === 'enabled' ? true : false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    startTimeBusSaturday: saturdayBusinessTime.startTime,
 | 
				
			||||||
 | 
					                    endTimeBusSaturday: saturdayBusinessTime.endTime,
 | 
				
			||||||
 | 
					                    messageBusSaturday: saturdayBusinessTime.message,
 | 
				
			||||||
 | 
					                    businessTimeEnableSaturday: saturdayBusinessTime.value === 'enabled' ? true : false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    ticketTimeExpiration: ticketExpiration.startTime,
 | 
					                    ticketTimeExpiration: ticketExpiration.startTime,
 | 
				
			||||||
                    ticketExpirationMsg: ticketExpiration.message,
 | 
					                    ticketExpirationMsg: ticketExpiration.message,
 | 
				
			||||||
                    ticketExpirationEnable: ticketExpiration.value === 'enabled' ? true : false,
 | 
					                    ticketExpirationEnable: ticketExpiration.value === 'enabled' ? true : false,
 | 
				
			||||||
| 
						 | 
					@ -165,6 +181,14 @@ const ConfigModal = ({ open, onClose, change }) => {
 | 
				
			||||||
                message: values.messageBus,
 | 
					                message: values.messageBus,
 | 
				
			||||||
                value: values.businessTimeEnable ? 'enabled' : 'disabled'
 | 
					                value: values.businessTimeEnable ? 'enabled' : 'disabled'
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            saturdayBusinessTime: {
 | 
				
			||||||
 | 
					                startTime: values.startTimeBusSaturday,
 | 
				
			||||||
 | 
					                endTime: values.endTimeBusSaturday,
 | 
				
			||||||
 | 
					                message: values.messageBusSaturday,
 | 
				
			||||||
 | 
					                value: values.businessTimeEnableSaturday ? 'enabled' : 'disabled'
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ticketExpiration: {
 | 
					            ticketExpiration: {
 | 
				
			||||||
                startTime: values.ticketTimeExpiration,
 | 
					                startTime: values.ticketTimeExpiration,
 | 
				
			||||||
                message: values.ticketExpirationMsg,
 | 
					                message: values.ticketExpirationMsg,
 | 
				
			||||||
| 
						 | 
					@ -205,7 +229,7 @@ const ConfigModal = ({ open, onClose, change }) => {
 | 
				
			||||||
        onClose()
 | 
					        onClose()
 | 
				
			||||||
        // setConfig(initialState)
 | 
					        // setConfig(initialState)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={classes.root}>
 | 
					        <div className={classes.root}>
 | 
				
			||||||
            <Dialog
 | 
					            <Dialog
 | 
				
			||||||
| 
						 | 
					@ -325,6 +349,61 @@ const ConfigModal = ({ open, onClose, change }) => {
 | 
				
			||||||
                                    </div>
 | 
					                                    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    <br />
 | 
				
			||||||
 | 
					                                    {/* SABADO INICIO */}
 | 
				
			||||||
 | 
					                                    <div className={classes.multFieldLine}>
 | 
				
			||||||
 | 
					                                        <Field
 | 
				
			||||||
 | 
					                                            component={TimePicker}
 | 
				
			||||||
 | 
					                                            name="startTimeBusSaturday"
 | 
				
			||||||
 | 
					                                            label="Inicio atendimentos"
 | 
				
			||||||
 | 
					                                            ampm={false}
 | 
				
			||||||
 | 
					                                            openTo="hours"
 | 
				
			||||||
 | 
					                                            views={['hours', 'minutes',]}
 | 
				
			||||||
 | 
					                                            format="HH:mm"
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					                                        {' '}
 | 
				
			||||||
 | 
					                                        <Field
 | 
				
			||||||
 | 
					                                            component={TimePicker}
 | 
				
			||||||
 | 
					                                            name="endTimeBusSaturday"
 | 
				
			||||||
 | 
					                                            label="Fim atendimento"
 | 
				
			||||||
 | 
					                                            ampm={false}
 | 
				
			||||||
 | 
					                                            openTo="hours"
 | 
				
			||||||
 | 
					                                            views={['hours', 'minutes',]}
 | 
				
			||||||
 | 
					                                            format="HH:mm"
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        <FormControlLabel
 | 
				
			||||||
 | 
					                                            control={
 | 
				
			||||||
 | 
					                                                <Field
 | 
				
			||||||
 | 
					                                                    as={Switch}
 | 
				
			||||||
 | 
					                                                    color="primary"
 | 
				
			||||||
 | 
					                                                    name="businessTimeEnableSaturday"
 | 
				
			||||||
 | 
					                                                    checked={values.businessTimeEnableSaturday}
 | 
				
			||||||
 | 
					                                                />
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            label={'Ativar/Desativar'} />
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    <div>
 | 
				
			||||||
 | 
					                                        <Field
 | 
				
			||||||
 | 
					                                            as={TextField}
 | 
				
			||||||
 | 
					                                            label={'Mensagem fora do horário de atendimento sábado'}
 | 
				
			||||||
 | 
					                                            type="messageBusSaturday"
 | 
				
			||||||
 | 
					                                            multiline
 | 
				
			||||||
 | 
					                                            rows={5}
 | 
				
			||||||
 | 
					                                            fullWidth
 | 
				
			||||||
 | 
					                                            name="messageBusSaturday"
 | 
				
			||||||
 | 
					                                            error={
 | 
				
			||||||
 | 
					                                                touched.messageBusSaturday && Boolean(errors.messageBusSaturday)
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            helperText={
 | 
				
			||||||
 | 
					                                                touched.messageBusSaturday && errors.messageBusSaturday
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            variant="outlined"
 | 
				
			||||||
 | 
					                                            margin="dense"
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                    {/* SABADO FIM */}
 | 
				
			||||||
                                    <br />
 | 
					                                    <br />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ const PieChart = ({ data = dataExample }) => {
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}>
 | 
					      <Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}>
 | 
				
			||||||
        <Box sx={{ position: "absolute" }}>
 | 
					        <Box sx={{ position: "absolute" }}>
 | 
				
			||||||
          <Title>Tickets Status</Title>
 | 
					          <Title>Tickets encerramento</Title>
 | 
				
			||||||
        </Box>
 | 
					        </Box>
 | 
				
			||||||
        <ResponsiveContainer width="100%" height="100%">
 | 
					        <ResponsiveContainer width="100%" height="100%">
 | 
				
			||||||
          <RechartsPieChart width={400} height={400}>
 | 
					          <RechartsPieChart width={400} height={400}>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -258,7 +258,7 @@ const Dashboard = () => {
 | 
				
			||||||
  const [usersOnlineInfo, dispatch] = useReducer(reducer, [])
 | 
					  const [usersOnlineInfo, dispatch] = useReducer(reducer, [])
 | 
				
			||||||
  const [ticketStatusChange, setStatus] = useState()
 | 
					  const [ticketStatusChange, setStatus] = useState()
 | 
				
			||||||
  const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 })
 | 
					  const [ticketsStatus, setTicktsStatus] = useState({ open: 0, openAll: 0, pending: 0, closed: 0 })
 | 
				
			||||||
 | 
					  const [ticketStatusChatEnd, setTicketStatusChatEnd] = useState([])
 | 
				
			||||||
  const { user } = useContext(AuthContext)
 | 
					  const { user } = useContext(AuthContext)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
| 
						 | 
					@ -287,12 +287,17 @@ const Dashboard = () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          const { data } = await api.get("/reports/user/services", {
 | 
					          const { data } = await api.get("/reports/user/services", {
 | 
				
			||||||
            params: { userId: null, startDate: dateToday, endDate: dateToday },
 | 
					            params: { userId: null, startDate: dateToday, endDate: dateToday },
 | 
				
			||||||
          })
 | 
					          }) 
 | 
				
			||||||
 | 
					 | 
				
			||||||
          // console.log('data.data: ', data.usersProfile)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          dispatch({ type: "RESET" })
 | 
					          dispatch({ type: "RESET" })
 | 
				
			||||||
          dispatch({ type: "LOAD_QUERY", payload: data.usersProfile })
 | 
					          dispatch({ type: "LOAD_QUERY", payload: data.usersProfile })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          const { data: ticketStatusChatEndData } = await api.get("/reports/count/statusChatEnd", {
 | 
				
			||||||
 | 
					            params: { startDate: dateToday, endDate: dateToday },
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          setTicketStatusChatEnd(ticketStatusChatEndData.reportStatusChatEnd)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
        } catch (err) {
 | 
					        } catch (err) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -506,7 +511,7 @@ const Dashboard = () => {
 | 
				
			||||||
                  </Grid>
 | 
					                  </Grid>
 | 
				
			||||||
                  <Grid item xs={12} sm={12} md={6} lg={6}>
 | 
					                  <Grid item xs={12} sm={12} md={6} lg={6}>
 | 
				
			||||||
                    <Paper className={classes.fixedHeightPaper} variant="outlined">
 | 
					                    <Paper className={classes.fixedHeightPaper} variant="outlined">
 | 
				
			||||||
                      <PieChart data={[]} />
 | 
					                      <PieChart data={ticketStatusChatEnd} />
 | 
				
			||||||
                    </Paper>
 | 
					                    </Paper>
 | 
				
			||||||
                  </Grid>
 | 
					                  </Grid>
 | 
				
			||||||
                </Grid>
 | 
					                </Grid>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -363,7 +363,7 @@ const Report = () => {
 | 
				
			||||||
          if (reportOption === '1') {
 | 
					          if (reportOption === '1') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues })
 | 
					            const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues })
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
            let ticketsQueue = data.tickets
 | 
					            let ticketsQueue = data.tickets
 | 
				
			||||||
            let userQueues = userA.queues
 | 
					            let userQueues = userA.queues
 | 
				
			||||||
            let filterQueuesTickets = []
 | 
					            let filterQueuesTickets = []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue