Correção do queuChoice

pull/1/head
adriano 2022-05-03 18:20:58 -03:00
parent 6f48e9aa1e
commit be3320e883
20 changed files with 517 additions and 89 deletions

View File

@ -21,6 +21,7 @@
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"date-fns": "^2.16.1",
"date-fns-tz": "^1.3.4",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",

View File

@ -36,6 +36,10 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
const { body, quotedMsg }: MessageData = req.body;
const medias = req.files as Express.Multer.File[];
@ -52,7 +56,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
);
} else {
console.log('------- quotedMsg: ', quotedMsg)
console.log('------- quotedMsg: ', quotedMsg, ' | ticket: ', ticket)
await SendWhatsAppMessage({ body, ticket, quotedMsg });
}

View File

@ -5,6 +5,8 @@ import AppError from "../errors/AppError";
import ShowTicketReport from "../services/TicketServices/ShowTicketReport";
import ShowMessageReport from "../services/MessageServices/ShowMessageReport";
import onlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
type IndexQuery = {
userId: string;
@ -15,6 +17,10 @@ type IndexQuery = {
export const reportUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
//const test = await onlineUserService({userId: 3, status: 'offline'})
if (req.user.profile !== "master" && req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}

View File

@ -36,6 +36,7 @@ interface TicketData {
import ListStatusChatEndService from "../services/StatusChatEndService/ListStatusChatEndService";
import Ticket from "../models/Ticket";
export const index = async (req: Request, res: Response): Promise<Response> => {
const {
@ -82,13 +83,33 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
// `contactId: ${contactId} \n| status: ${status} \n| userId: ${userId}`
// )
const ticket = await CreateTicketService({ contactId, status, userId });
// test del
let ticket = await Ticket.findOne({where: { contactId, status: 'queueChoice' } });
if(ticket){
await UpdateTicketService({ ticketData: { status: 'open',userId: userId,}, ticketId: ticket.id});
console.log('TICKET QUEUE CHOICE !!!!!!!')
}
else{
ticket = await CreateTicketService({ contactId, status, userId });
}
const io = getIO();
io.to(ticket.status).emit("ticket", {
action: "update",
ticket
});
//
// const ticket = await CreateTicketService({ contactId, status, userId });
// const io = getIO();
// io.to(ticket.status).emit("ticket", {
// action: "update",
// ticket
// });
return res.status(200).json(ticket);
};

View File

@ -13,6 +13,7 @@ import QuickAnswer from "../models/QuickAnswer";
import SchedulingNotify from "../models/SchedulingNotify";
import StatusChatEnd from "../models/StatusChatEnd";
import UserOnlineTime from "../models/UserOnlineTime";
// eslint-disable-next-line
@ -36,6 +37,7 @@ const models = [
SchedulingNotify,
StatusChatEnd,
UserOnlineTime,
];
sequelize.addModels(models);

View File

@ -0,0 +1,41 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("UserOnlineTimes", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
userId: {
type: DataTypes.INTEGER,
references: { model: "Users", key: "id" },
onUpdate: "CASCADE",
onDelete: "CASCADE",
allowNull: false
},
status: {
type: DataTypes.STRING,
allowNull: false
},
onlineTime: {
type: DataTypes.DATE,
allowNull: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("UserOnlineTimes");
}
};

View File

@ -6,6 +6,7 @@ import ListSchedulingNotifyService from "../services/SchedulingNotifyServices/L
import DeleteSchedulingNotifyService from "../services/SchedulingNotifyServices/DeleteSchedulingNotifyService";
let scheduler_monitor:any;
const monitor = async () => {
@ -41,6 +42,7 @@ const monitor = async () => {
}
};

View File

@ -0,0 +1,15 @@
export const splitDateTime = (date: Date) => {
let day = date.getDate().toString().padStart(2, '0');
let month = (date.getMonth()+1).toString().padStart(2, '0');
let year = date.getFullYear();
let hour = date.getHours().toString().padStart(2, '0');
let minute = date.getMinutes().toString().padStart(2, '0');
let seconds = date.getSeconds().toString().padStart(2, '0');
return {fullDate: `${year}-${month}-${day}`, fullTime: `${hour}:${minute}:${seconds}`}
}

View File

@ -0,0 +1,35 @@
import { getIO } from "../libs/socket";
// import usersOnline from '../libs/socket'
let whoIsOnline_monitor:any;
const monitor = async () => {
const io = getIO();
io.emit("isOnline");
//const test = require('./../libs/socket');
// console.log('*usersOnline: ', test.listOnlineUsers)
};
export const startWhoIsOnlinegMonitor =async (mileseconds: number) => {
whoIsOnline_monitor = setInterval(monitor, mileseconds)
}
export const stopWhoIsOnlineMonitor =async ( ) => {
clearInterval(whoIsOnline_monitor)
}

View File

@ -5,6 +5,12 @@ import { logger } from "../utils/logger";
let io: SocketIO;
//test del
let listOnlineUsers:any[]=[]
let count:number = 0
//
export const initIO = (httpServer: Server): SocketIO => {
io = new SocketIO(httpServer, {
cors: {
@ -12,13 +18,38 @@ export const initIO = (httpServer: Server): SocketIO => {
}
});
io.on("connection", socket => {
logger.info("Client Connected");
// // test del
// let userId = socket.handshake.query;
// console.log('SOCKET userId: ', userId)
// //
socket.on("online", (userId: string) => {
logger.info(`CLIENT ID ${userId}` );
const indexUser = listOnlineUsers.findIndex((e) => e.userId == userId)
if(indexUser == -1){
//listOnlineUsers.push({userId: userId, status: 'online'})
}
count++
//console.log('count: ', count)
if(count >= listOnlineUsers.length){
//console.log('listOnlineUsers1: ', listOnlineUsers)
count = 0
}
//console.log('listOnlineUsers1: ', listOnlineUsers)
});
socket.on("joinChatBox", (ticketId: string) => {
logger.info("A client joined a ticket channel");
@ -48,3 +79,7 @@ export const getIO = (): SocketIO => {
}
return io;
};
exports.listOnlineUsers = listOnlineUsers

View File

@ -11,12 +11,13 @@ import {
AutoIncrement,
Default,
HasMany,
BelongsToMany
BelongsToMany,
} from "sequelize-typescript";
import { hash, compare } from "bcryptjs";
import Ticket from "./Ticket";
import Queue from "./Queue";
import UserQueue from "./UserQueue";
import UserOnlineTime from "./UserOnlineTime";
@Table
class User extends Model<User> {
@ -54,6 +55,11 @@ class User extends Model<User> {
@HasMany(() => Ticket)
tickets: Ticket[];
//test del
@HasMany(() => UserOnlineTime)
UserOnlineTime: UserOnlineTime[];
//
@BelongsToMany(() => Queue, () => UserQueue)
queues: Queue[];

View File

@ -0,0 +1,45 @@
import {
Table,
AutoIncrement,
Column,
CreatedAt,
UpdatedAt,
Model,
PrimaryKey,
HasMany,
ForeignKey,
BelongsTo
} from "sequelize-typescript";
import User from "./User";
@Table
class UserOnlineTime extends Model<UserOnlineTime> {
@PrimaryKey
@AutoIncrement
@Column
id: number;
@Column
status: string;
@Column
onlineTime: Date;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
@ForeignKey(() => User)
@Column
userId: number;
@BelongsTo(() => User)
user: User;
}
export default UserOnlineTime;

View File

@ -5,6 +5,7 @@ import { logger } from "./utils/logger";
import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhatsAppsSessions";
import { startSchedulingMonitor } from "./helpers/SchedulingNotifySendMessage"
import { startWhoIsOnlinegMonitor } from "./helpers/WhoIsOnlineMonitor"
const server = app.listen(process.env.PORT, () => {
logger.info(`Server started on port: ${process.env.PORT}`);
@ -15,3 +16,4 @@ StartAllWhatsAppsSessions();
gracefulShutdown(server);
startSchedulingMonitor(5000)
startWhoIsOnlinegMonitor(3000)

View File

@ -39,14 +39,7 @@ const CreateMessageService = async ({messageData}: Request): Promise<Message> =>
throw new Error("ERR_CREATING_MESSAGE");
}
//console.log('SERVER SIDE MESSAGE: ', message)
// console.log('>>>>>>>>>>>>>>>>>>>>>> TICKET STATUS: ',message.ticket.status)
//test del
// const ticketInfo = await Ticket.findByPk(message.ticket.id)
// console.log('&&&&&&&&&&&&&&&&& TICKET INFO queueId: ', ticketInfo?.queueId)
//
if(message.ticket.status!='queueChoice'){

View File

@ -0,0 +1,111 @@
import AppError from "../../errors/AppError";
import UserOnlineTime from "../../models/UserOnlineTime";
import { splitDateTime } from "../../helpers/SplitDateTime";
import { Op, Sequelize } from "sequelize";
import { addHours, addMinutes, addSeconds, intervalToDuration, add } from "date-fns";
import format from 'date-fns/format';
import ptBR from 'date-fns/locale/pt-BR';
import { stat } from "fs";
interface Request {
userId: string | number,
status: string,
}
const CreateOrUpdateUserOnlineTime = async ({
userId,
status,
}: Request): Promise<UserOnlineTime> => {
let userOnlineTime = null;
// let dateTime = splitDateTime(new Date(new Date() + 'UTC'))
let dateTime = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }) ))
userOnlineTime = await UserOnlineTime.findOne({
where: {
[Op.and]: [
{
userId: userId
},
{
"$createdAt$": Sequelize.where(Sequelize.fn("date", Sequelize.col("createdAt")), `${dateTime.fullDate}`)
},
]
}
});
if(userOnlineTime){
try{
if(status === 'offline'){
//updatedAt
let newtTime = intervalToDuration({ start: userOnlineTime.updatedAt, end: new Date()})
console.log('TESTANDO INTERVAL DURATION: ', newtTime)
console.log('hours: ', newtTime.hours, ' | minutes: ', newtTime.minutes, ' | seconds: ', newtTime.seconds)
let onlineTime = new Date()
onlineTime.setUTCHours(userOnlineTime.onlineTime.getHours())
onlineTime.setUTCMinutes(userOnlineTime.onlineTime.getMinutes())
onlineTime.setUTCSeconds(userOnlineTime.onlineTime.getSeconds())
console.log('userOnlineTime.onlineTime: ',userOnlineTime.onlineTime)
console.log('userOnlineTime.onlineTime.getHours(): ',userOnlineTime.onlineTime.getHours())
console.log('userOnlineTime.onlineTime.getMinutes(): ',userOnlineTime.onlineTime.getMinutes())
console.log('userOnlineTime.onlineTime.getSeconds(): ',userOnlineTime.onlineTime.getSeconds())
console.log('online time 3: ', onlineTime)
if(newtTime.hours && +newtTime.hours > 0){
onlineTime = addHours(onlineTime, newtTime.hours)
}
if(newtTime.minutes && +newtTime.minutes > 0){
onlineTime = addMinutes(onlineTime,newtTime.minutes)
}
if(newtTime.seconds && +newtTime.seconds > 0){
onlineTime = addSeconds(onlineTime, newtTime.seconds)
}
console.log('online time 4: ', onlineTime)
const isoDate = new Date(onlineTime);
const mySQLDateString = isoDate.toJSON().slice(0, 19).replace('T', ' ');
console.log('mySQLDateString: ', mySQLDateString)
await userOnlineTime.update({ status, onlineTime: mySQLDateString })
}
else if(status === 'online'){
await userOnlineTime.update({ status })
}
}catch(err){
throw new AppError("ERR_NO_USER_ONLINE_FOUND", 404);
}
}
if(!userOnlineTime){
userOnlineTime = await UserOnlineTime.create(
{
userId,
status,
onlineTime: `${dateTime.fullDate} 00:00:00`
})
}
return userOnlineTime
}
export default CreateOrUpdateUserOnlineTime

View File

@ -0,0 +1,74 @@
import Ticket from "../../models/Ticket";
import AppError from "../../errors/AppError";
import Contact from "../../models/Contact";
import User from "../../models/User";
import Queue from "../../models/Queue";
import Message from "../../models/Message";
import { userInfo } from "os";
import { Op, where } from "sequelize";
import { Sequelize } from "sequelize";
import moment from 'moment';
import { startOfDay, endOfDay, parseISO, getDate} from "date-fns";
import { string } from "yup/lib/locale";
import Whatsapp from "../../models/Whatsapp";
//Report by user, startDate, endDate
const ShowUserServiceReport = async (id: string | number, startDate: string, endDate: string): Promise<Ticket[]> => {
let where_clause = {}
if(id=='0'){
where_clause = {
createdAt: {
[Op.gte]: startDate+' 00:00:00.000000',
[Op.lte]: endDate +' 23:59:59.999999'
},
}
}
else{
where_clause = {
userid: id,
createdAt: {
[Op.gte]: startDate+' 00:00:00.000000',
[Op.lte]: endDate +' 23:59:59.999999'
},
}
}
const ticket = await Ticket.findAll({
// where: where_clause ,
// attributes: ['id', 'status', [Sequelize.fn("DATE_FORMAT",Sequelize.col("Ticket.createdAt"),"%d/%m/%Y %H:%i:%s"),"createdAt"],
// [Sequelize.fn("DATE_FORMAT",Sequelize.col("Ticket.updatedAt"),"%d/%m/%Y %H:%i:%s"),"updatedAt"]],
// include: [
// {
// model: Message,
// required:true,
// separate: true,
// attributes: ['body', 'read', 'mediaType','fromMe', 'mediaUrl', [Sequelize.fn("DATE_FORMAT",Sequelize.col("createdAt"),"%d/%m/%Y %H:%i:%s"),"createdAt"]],
// order: [
// ['createdAt', 'ASC']
// ]
// }
// ],
});
if (!ticket) {
throw new AppError("ERR_NO_TICKET_FOUND", 404);
}
return ticket;
};
export default ShowUserServiceReport;

View File

@ -28,7 +28,7 @@ const SendWhatsAppMessage = async ({
quotedMsgSerializedId = SerializeWbotMsgId(ticket, quotedMsg);
}
// test del
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
if(whatsapp.status!='CONNECTED'){
@ -42,10 +42,12 @@ const SendWhatsAppMessage = async ({
}
}
//
const wbot = await GetTicketWbot(ticket);
try {
const sentMessage = await wbot.sendMessage(
`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,

View File

@ -1,53 +1,33 @@
const data = [
const data:any[] = [
{
"id":"1",
"option":"Status do Pedido",
"description":"Digite aqui umas das opções abaixo para iniciarmos o atendimento, tá? 🧡",
"subOptions": [{"subOpt":"Digitar meu CPF","responseToClient":"Digite o seu CPF"}, {"subOpt":"Digitar o Número do Pedido", "responseToClient":"Digite o numero do pedido"}],
"option":"Conhecer a história da HiT",
"description":"Conheça nossa história acessando o link abaixo:\nhttp://www.hittelco.com/br/hit-communications.html",
// "subOptions": [{"subOpt":"Digitar meu CPF","responseToClient":"Digite o seu CPF"}, {"subOpt":"Digitar o Número do Pedido", "responseToClient":"Digite o numero do pedido"}],
"atendente":false
},
{
"id":"2",
"option":"Status do Reembolso",
"description":"Digite aqui umas das opções abaixo para iniciarmos o atendimento, tá? 🧡",
"subOptions": [{"subOpt":"Digitar meu CPF","responseToClient":"Digite o seu CPF"}, {"subOpt":"Digitar o Número do Pedido", "responseToClient":"Digite o numero do pedido"}],
"option":"Conhecer os produtos da HIT",
"description":"Conheça nossos produtos acessando o link abaixo:\nhttp://www.hittelco.com/br/index.html",
"atendente":false
},
{
"id":"3",
"option":"Quero Trocar ou Devolver",
"description":"Para solicitar, é bem simples! Disponibilizamos um passo-a-passo bem completo em nossa loja online. \nBasta acessar www.dressto.com.br, ir até nosso rodapé, e clicar em “Como Trocar”, indicamos que leia atentamente nossa política de troca. 😉 \nCaso ainda precise de atendimento",
"subOptions": [{"subOpt":"Para continuar", "responseToClient":"Aguarde, um de nossos atendentes vai te atender em breve!"}],
"option":"Conhecer nossa Estrutura",
"description":"Conheça nossa estrutura acessando o link abaixo\nhttp://www.hittelco.com/br/infraestrutura.html",
"atendente":false
},
} ,
{
"id":"4",
"option":"Quero Rastrear meu Pedido",
"description":"Digite aqui umas das opções abaixo para iniciarmos o atendimento, tá? 🧡",
"subOptions": [{"subOpt":"Digitar meu CPF","responseToClient":"Digite o seu CPF"}, {"subOpt":"Digitar o Número do Pedido", "responseToClient":"Digite o numero do pedido"}],
"atendente":false
},
{
"id":"5",
"option":"Cancelamento de Pedido",
"description":"Digite aqui umas das opções abaixo para iniciarmos o atendimento, tá? 🧡",
"subOptions": [{"subOpt":"Digitar meu CPF","responseToClient":"Digite o seu CPF"}, {"subOpt":"Digitar o Número do Pedido", "responseToClient":"Digite o numero do pedido"}],
"atendente":false
},
{
"id":"6",
"option":"Cupons",
"description":"Digite o número da opção desejada",
"subOptions": [{"subOpt":"Primeira Compra", "responseToClient":"Primeira Compra\nAguarde, um de nossos atendentes vai te atender em breve!"}, {"subOpt":"Aniversariante", "responseToClient":"Aniversariante\nAguarde, um de nossos atendentes vai te atender em breve!"}],
"atendente":false
},
{
"id":"7",
"option":"Outros Assuntos",
"description":"7 - Prezado cliente, você está sendo direcionado para um atendente disponível 😊.\nPedimos gentilmente que aguarde para ser atendido.\nLembramos que nosso atendimento está sempre disponível de segunda a sexta-feira, das 08:00 às 17:00 horas. Um beijo! !",
"subOptions": [],
"atendente":true
"option":"Finalizar atendimento",
"description":"Seu atendimento foi encerrado!\nFoi um prazer conhece-lo, volte sempre.",
"atendente":false,
"closeChat": true
}
]

View File

@ -34,7 +34,8 @@ import fs from 'fs';
// test del
import data_ura from './ura'
import msg_client_transfer from './ura_msg_transfer'
import final_message from "./ura _final_message";
import final_message from "./ura_final_message";
import SendWhatsAppMessage from "./SendWhatsAppMessage";
//
@ -242,6 +243,17 @@ const verifyQueue = async (
await verifyMessage(sentMessage, ticket, contact);
} else {
//test del transfere o atendimento se entrar na ura infinita
let ticket_message = await ShowTicketMessage(ticket.id, false);
if(ticket_message.length > 10){
await UpdateTicketService({ ticketData: {status: 'pending', queueId: queues[0].id }, ticketId: ticket.id });
}
else{
let options = "";
queues.forEach((queue, index) => {
@ -260,6 +272,12 @@ const verifyQueue = async (
);
debouncedSentMessage();
}
console.log('TICKET MESSAGE ON QUEUE CHOICE: ', ticket_message)
//
}
};
@ -447,12 +465,14 @@ const handleMessage = async (
let indexAttendant = data_ura.findIndex((u) => u.atendente )
let opt_user_attendant = ''
let opt_user_attendant = '-1'
if(indexAttendant != -1){
opt_user_attendant = data_ura[indexAttendant].id
}
// console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨ indexAttendant: ',indexAttendant, ' | opt_user_attendant: ', opt_user_attendant)
let ticket_message = await ShowTicketMessage(ticket.id, true, ura_length, `^[0-${ura_length}}]$`);
if(ticket_message.length > 1){
@ -483,18 +503,25 @@ const handleMessage = async (
}
// console.log('----------------- ticket_message: ', ticket_message)
//console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨ MSG.BODY: ', msg.body , ' | opt_user_attendant: ',opt_user_attendant, ' | lastOption: ', lastOption)
// È numero
if( !Number.isNaN(Number(msg.body.trim())) && (+msg.body >= 0 && +msg.body <= data_ura.length) ) {
const indexUra = data_ura.findIndex((ura) => ura.id == msg.body.trim())
if(indexUra != -1){
if(data_ura[indexUra].id != opt_user_attendant && lastOption != opt_user_attendant){
console.log('TICKET MESSAGE: ', ticket_message)
// test del
@ -536,10 +563,11 @@ const handleMessage = async (
id = listMessage[listMessage.length-1].body
subUra = data_ura.filter((e)=>e.id == id )[0]
if(subUra.subOptions){
if(subUra.subOptions && subUra.subOptions.length > 0){
if( !Number.isNaN(Number(msg.body.trim())) && (+msg.body >= 0 && +msg.body <= subUra.subOptions?.length) && subUra.subOptions ) {
if(subUra.subOptions[+msg.body - 1].responseToClient){
botSendMessage(ticket, contact, wbot, `*${subUra.option}*\n\n${subUra.subOptions[+msg.body - 1].responseToClient}`)
@ -564,7 +592,7 @@ const handleMessage = async (
else{
let options = "";
let subOptions = subUra.subOptions
let subOptions:any[] = subUra.subOptions
subOptions?.forEach((s, index) => { options += `*${index + 1}* - ${s.subOpt}\n` });
@ -581,11 +609,11 @@ const handleMessage = async (
//
if(next){
if(data_ura[indexUra].subOptions){
if(data_ura[indexUra].subOptions && data_ura[indexUra].subOptions.length > 0){
let options = "";
let option = data_ura[indexUra].option
let subOptions = data_ura[indexUra].subOptions
let subOptions:any[] = data_ura[indexUra].subOptions
let description = data_ura[indexUra].description
subOptions?.forEach((s, index) => { options += `*${index + 1}* - ${s.subOpt}\n` });
@ -597,7 +625,32 @@ const handleMessage = async (
}
else{
//test del deletar isso (Usar somente na hit)
if(data_ura[indexUra].closeChat){
const {ticket :res} = await UpdateTicketService({
ticketData:{'status': 'closed', 'userId': botInfo.userIdBot}, ticketId: ticket.id
});
///////////////////////////////
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
const { farewellMessage } = whatsapp;
if (farewellMessage) {
await SendWhatsAppMessage({ body: farewellMessage, ticket: res });
}
///////////////////////////////
}
else{
botSendMessage(ticket, contact, wbot, `${data_ura[indexUra].description}\n\n *0* - Voltar ao menu principal`)
}
//
// botSendMessage(ticket, contact, wbot, `${data_ura[indexUra].description}\n\n *0* - Voltar ao menu principal`)
}
}