Merge remote-tracking branch 'origin/dual_session_test' into dialogflow

pull/20/head
adriano 2022-12-19 12:54:59 -03:00
commit 4c510ed75b
18 changed files with 682 additions and 303 deletions

View File

@ -1,7 +1,11 @@
import path from "path"; import path from "path";
import multer from "multer"; import multer from "multer";
const publicFolder = path.resolve(__dirname, "..", "..", "public"); // const publicFolder = path.resolve(__dirname, "..", "..", "public");
const publicFolder = path.resolve(__dirname, "..", "..","..","..", "public");
console.log('publicFolder: ',publicFolder)
export default { export default {
directory: publicFolder, directory: publicFolder,

View File

@ -1,18 +1,11 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import AppError from "../errors/AppError"; import AppError from "../errors/AppError";
import { getIO } from "../libs/socket"; import { getIO } from "../libs/socket";
import DeleteSchedulingNotifyService from "../services/SchedulingNotifyServices/DeleteSchedulingNotifyService"; import DeleteSchedulingNotifyService from "../services/SchedulingNotifyServices/DeleteSchedulingNotifyService";
import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService"; import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService";
import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService"; import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService";
import ShowSchedulingNotifyService from "../services/SchedulingNotifyServices/ShowSchedulingNotifyService";
// const test = await ListSchedulingNotifyContactService('5517988310949','2022-03-18','2022-03-19'); import { deleteScheduleByTicketIdCache } from "../helpers/SchedulingNotifyCache";
// const test = await ListSchedulingNotifyContactService('','2022-03-18','2022-03-19');
// const test = await ListSchedulingNotifyContactService('5517988310949');
//
type IndexQuery = { type IndexQuery = {
@ -21,13 +14,13 @@ type IndexQuery = {
endDate: string; endDate: string;
}; };
export const reportScheduleNotifyByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
const { contactNumber, startDate, endDate } = req.query as IndexQuery
const data_query = await ListSchedulingNotifyContactService(contactNumber, startDate, endDate); export const reportScheduleNotifyByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
const { contactNumber, startDate, endDate } = req.query as IndexQuery
const data_query = await ListSchedulingNotifyContactService(contactNumber, startDate, endDate);
// console.group('DATA QUERY SCHEDULE:\n',data_query) // console.group('DATA QUERY SCHEDULE:\n',data_query)
@ -36,23 +29,23 @@ export const reportScheduleNotifyByDateStartDateEnd = async (req: Request, res:
}; };
export const createOrUpdateScheduleNotify = async (req: Request, res: Response): Promise<Response> => { export const createOrUpdateScheduleNotify = async (req: Request, res: Response): Promise<Response> => {
const scheduleData = req.body; const scheduleData = req.body;
const schedulingNotifyCreate = await CreateSchedulingNotifyService( const schedulingNotifyCreate = await CreateSchedulingNotifyService(
{ {
schedulingNotifyId: scheduleData.schedulingNotifyId, schedulingNotifyId: scheduleData.schedulingNotifyId,
ticketId: scheduleData.ticketId, ticketId: scheduleData.ticketId,
statusChatEndId: scheduleData.statusChatEndId, statusChatEndId: scheduleData.statusChatEndId,
schedulingDate: scheduleData.schedulingDate, schedulingDate: scheduleData.schedulingDate,
schedulingTime: scheduleData.schedulingTime, schedulingTime: scheduleData.schedulingTime,
message: scheduleData.message message: scheduleData.message
} }
) )
// console.group(':::::::::::::::::: DATA schedulingNotifyCreate:\n',schedulingNotifyCreate) // console.group(':::::::::::::::::: DATA schedulingNotifyCreate:\n',schedulingNotifyCreate)
// const io = getIO(); // const io = getIO();
// io.emit("schedulingNotify", {action: "update", schedulingNotifyCreate }); // io.emit("schedulingNotify", {action: "update", schedulingNotifyCreate });
@ -61,13 +54,17 @@ export const createOrUpdateScheduleNotify = async (req: Request, res: Response):
}; };
export const remove = async ( req: Request, res: Response ): Promise<Response> => { export const remove = async (req: Request, res: Response): Promise<Response> => {
const { scheduleId } = req.params; const { scheduleId } = req.params;
await DeleteSchedulingNotifyService(scheduleId); let schedule: any = await ShowSchedulingNotifyService(scheduleId)
await deleteScheduleByTicketIdCache(schedule.ticketId)
await DeleteSchedulingNotifyService(scheduleId);
return res.status(200).send(); return res.status(200).send();
}; };

View File

@ -94,7 +94,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
}); });
await stopWhoIsOnlineMonitor() // await stopWhoIsOnlineMonitor()
await startWhoIsOnlineMonitor() await startWhoIsOnlineMonitor()
return res.status(200).json(user); return res.status(200).json(user);

View File

@ -0,0 +1,219 @@
import Redis from 'ioredis'
import { type } from 'os'
const unflatten = require('flat').unflatten
var flatten = require('flat')
import ListContactsServiceCache from "../services/ContactServices/ListContactsServiceCache"
import { redisConn } from './TicketCache'
import SchedulingNotify from '../models/SchedulingNotify'
import { format } from "date-fns";
import ptBR from 'date-fns/locale/pt-BR';
import { escapeCharCache } from './ContactsCache'
const deleteScheduleByTicketIdCache = async (ticketId: string | number) => {
const redis: any = await redisConn();
if (!redis) return
if (redis.status !== 'connect') return
const schedule_cache: any = await redis.hgetall(`schedule:${ticketId}`)
try {
if (schedule_cache && Object.keys(schedule_cache).length > 0) {
await redis.del(`schedule:${ticketId}`)
console.log(`Schedule cache ticketId ${schedule_cache.ticketId} deleted!`)
}
else {
console.log('SCHEDULE CACHE NOT FOUND!')
}
} catch (error) {
console.log(`There was an error on deleteScheduleByTicketIdCache: ${error}`)
}
redis.quit()
}
const updateScheduleCacheByTicketId = async (scheduleNotify: any) => {
const redis: any = await redisConn();
if (!redis) return
if (redis.status !== 'connect') return
const pipeline = redis.pipeline()
let entries = Object.entries(scheduleNotify)
entries.forEach((e: any) => {
pipeline.hset(`schedule:${scheduleNotify.ticketId}`, e[0], e[1])
})
await pipeline.exec(() => { console.log("schedule Key/value inserted/updated") });
redis.quit()
}
const createSchedulingNotifyCache = async (scheduleNotify: any) => {
const redis: any = await redisConn();
if (!redis) return
if (redis.status !== 'connect') return
let date_time: any = format(new Date(scheduleNotify.schedulingTime), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }).split(' ')
delete scheduleNotify.schedulingTime
delete scheduleNotify.updatedAt
delete scheduleNotify.createdAt
delete scheduleNotify.schedulingDate
console.log('created date_time: ', date_time)
scheduleNotify.date = date_time[0]
scheduleNotify.date_escaped = escapeCharCache(date_time[0])
scheduleNotify.hour = date_time[1].split(':')[0]
scheduleNotify.minute = date_time[1].split(':')[1]
await redis.hmset(`schedule:${scheduleNotify.ticketId}`, scheduleNotify);
console.log(`${scheduleNotify.length} SCHEDULE NOTIFY INSERTED IN CACHE!`)
redis.quit()
}
async function searchScheduleCache(date: string, hour: number | string, minute: number | string) {
const redis: any = await redisConn();
if (!redis) return
if (redis.status !== 'connect') return null
date = escapeCharCache(date).trim()
const response: any = await redis.call('FT.SEARCH', 'idx_schedule', `(@date_escaped:${date}) (@hour:${hour}) (@minute:${minute})`)
redis.quit()
if (response.length === 1) {
return []
}
const results: any = []
for (let n = 2; n < response.length; n += 2) {
const result: any = {}
const fieldNamesAndValues = response[n]
for (let m = 0; m < fieldNamesAndValues.length; m += 2) {
const k = fieldNamesAndValues[m]
const v = fieldNamesAndValues[m + 1]
result[k] = v
}
results.push(result)
}
return results
}
const loadSchedulesCache = async () => {
await createScheduleIndexCache('idx_schedule')
const redis: any = await redisConn();
if (!redis) return
if (redis.status !== 'connect') return
let schedules: any = await SchedulingNotify.findAll({ raw: true, attributes: ["id", "statusChatEndId", "ticketId", "schedulingTime", "message"] });
// console.log('SCHEDULE NOTIFY CACHE2: ', schedules)
const pipeline = redis.pipeline()
for (let i = 0; i < schedules.length; i++) {
let date_time: any = format(new Date(schedules[i].schedulingTime), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }).split(' ')
delete schedules[i].schedulingTime
console.log('date_time: ', date_time)
schedules[i].date = date_time[0]
schedules[i].date_escaped = escapeCharCache(date_time[0])
schedules[i].hour = date_time[1].split(':')[0]
schedules[i].minute = date_time[1].split(':')[1]
pipeline.hmset(`schedule:${schedules[i].ticketId}`, schedules[i]);
}
await pipeline.exec(() => { console.log(`${schedules.length} SCHEDULES NOTIFY INSERTED IN CACHE!`) });
redis.quit()
// let test = await searchScheduleCache('2022-12-16', '18', '30')
// console.log('--------------> TEST: ', test)
}
const createScheduleIndexCache = async (hashIndex: string) => {
const redis: any = await redisConn();
if (!redis) return
if (redis.status !== 'connect') return
try {
const lst_index_redis: any = await redis.call('FT._LIST')
if (lst_index_redis.includes(hashIndex)) {
console.log('entrou...')
await redis.call('FT.DROPINDEX', hashIndex)
}
const response = await redis.call('FT.CREATE', hashIndex, 'ON', 'HASH', 'PREFIX', '1', 'schedule:', 'SCHEMA', 'id', 'TEXT', 'SORTABLE', 'date_escaped', 'TEXT', 'SORTABLE', 'hour', 'TEXT', 'SORTABLE', 'minute', 'TEXT', 'SORTABLE')
console.log('Schedule index created: ', response)
} catch (error) {
console.log('There was an error on createScheduleIndexCache: ', error)
}
redis.quit()
}
export {
loadSchedulesCache,
searchScheduleCache,
updateScheduleCacheByTicketId,
createSchedulingNotifyCache,
deleteScheduleByTicketIdCache
}

View File

@ -8,6 +8,8 @@ import { getIO } from "../libs/socket";
import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService"; import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService";
import path from "path"; import path from "path";
import { convertBytes } from "./ConvertBytes"; import { convertBytes } from "./ConvertBytes";
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
import SchedulingNotify from "../models/SchedulingNotify";
const fastFolderSize = require('fast-folder-size') const fastFolderSize = require('fast-folder-size')
const { promisify } = require('util') const { promisify } = require('util')
@ -15,6 +17,8 @@ const fs = require('fs')
const { exec } = require("child_process"); const { exec } = require("child_process");
let _fifo: any
let scheduler_monitor: any; let scheduler_monitor: any;
let timeInterval = 5 let timeInterval = 5
@ -36,23 +40,35 @@ const monitor = async () => {
try { try {
// const { schedulingNotifies, count, hasMore } = await ListSchedulingNotifyService({ searchParam: dateParm, pageNumber: "1" }); const { schedulingNotifies, count, hasMore } = await ListSchedulingNotifyService({ searchParam: dateParm, pageNumber: "1" });
if (schedulingNotifies && schedulingNotifies.length > 0) {
// // console.log('schedulingNotifies: ',schedulingNotifies) for (let i = 0; i < schedulingNotifies.length; i++) {
// if (schedulingNotifies && schedulingNotifies.length > 0) {
// const ticket = await ShowTicketService(schedulingNotifies[0].ticketId); const ticket = await ShowTicketService(+schedulingNotifies[i].ticketId);
await new Promise(f => setTimeout(f, 3000));
// SetTicketMessagesAsRead(ticket); if(!ticket.queue){
await ticket.update({status: 'open'})
}
// await SendWhatsAppMessage({ SetTicketMessagesAsRead(ticket);
// body: schedulingNotifies[0].message, ticket
// });
// DeleteSchedulingNotifyService(schedulingNotifies[0].id) await SendWhatsAppMessage({
body: schedulingNotifies[i].message, ticket
});
// } await deleteScheduleByTicketIdCache(schedulingNotifies[i].ticketId)
await DeleteSchedulingNotifyService(schedulingNotifies[i].id)
}
}
exec("df -h /", (error: any, stdout: any, stderr: any) => { exec("df -h /", (error: any, stdout: any, stderr: any) => {
@ -66,9 +82,9 @@ const monitor = async () => {
return; return;
} }
stdout = stdout.split(/\r?\n/) stdout = stdout.split(/\r?\n/)
stdout = stdout[1].trim().split(/\s+/) stdout = stdout[1].trim().split(/\s+/)
// DISK SPACE MONITORING // DISK SPACE MONITORING
const io = getIO(); const io = getIO();
io.emit("diskSpaceMonit", { io.emit("diskSpaceMonit", {
@ -90,20 +106,20 @@ const monitor = async () => {
whatsapps.forEach(async whats => { whatsapps.forEach(async whats => {
const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`) const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`)
if (fs.existsSync(sourcePath)) { if (fs.existsSync(sourcePath)) {
try { try {
const fastFolderSizeAsync = promisify(fastFolderSize) const fastFolderSizeAsync = promisify(fastFolderSize)
let size = await fastFolderSizeAsync(sourcePath) let size = await fastFolderSizeAsync(sourcePath)
size = convertBytes(size) size = convertBytes(size)
// SESSION MONITORING // SESSION MONITORING
const io = getIO(); const io = getIO();
@ -132,27 +148,32 @@ const monitor = async () => {
} catch (error) { } catch (error) {
console.log('>>> SchedulingNotifiySendMessage.ts error: ', error) console.log('>>> SchedulingNotifiySendMessage.ts error: ', error)
stopSchedulingMonitor()
startSchedulingMonitor(timeInterval)
} }
}; };
export const startSchedulingMonitor = async (mileseconds: number) => { const SchedulingNotifySendMessage = async () => {
timeInterval = mileseconds try {
clearInterval(_fifo);
scheduler_monitor = setInterval(monitor, mileseconds) await monitor()
} catch (error) {
console.log('error on SchedulingNotifySendMessage: ', error)
}
finally {
_fifo = setInterval(SchedulingNotifySendMessage, 5000);
}
} }
_fifo = setInterval(SchedulingNotifySendMessage, 5000);
export const stopSchedulingMonitor = async () => {
clearInterval(scheduler_monitor) module.exports = SchedulingNotifySendMessage
}

View File

@ -17,7 +17,7 @@ import { date } from "faker";
import sumOnlineTimeNow from '../helpers/SumOlineTimeNow' import sumOnlineTimeNow from '../helpers/SumOlineTimeNow'
import UserOnlineTime from "../models/UserOnlineTime"; import UserOnlineTime from "../models/UserOnlineTime";
let _fifo: any
let whoIsOnline_monitor: any; let whoIsOnline_monitor: any;
// const listUserId:any[] = [{'id':8, status: 'offline'},{'id':3, status: 'offline'},{'id':5, status: 'offline'}] // const listUserId:any[] = [{'id':8, status: 'offline'},{'id':3, status: 'offline'},{'id':5, status: 'offline'}]
@ -30,7 +30,7 @@ let timeInterval = 5
let lstOnline: any = [] let lstOnline: any = []
let deleted: boolean = false; let deleted: boolean = false;
const emitterOnline = (user: any, status: string, showOnlineTime: boolean = true) => { const emitterOnline = (user: any, status: string, showOnlineTime: boolean = true) => {
@ -66,147 +66,179 @@ const monitor = async () => {
const usersSocket = require('./../libs/socket'); const usersSocket = require('./../libs/socket');
if (usersSocket.ob) { if (usersSocket.ob) {
if (count > 1) { if (count > 1) {
count = 0 count = 0
} }
if (count == 0) { if (count == 0) {
uuid = usersSocket.ob.uuid uuid = usersSocket.ob.uuid
} }
if (count == 1) { if (count == 1) {
if (uuid) { if (uuid) {
if (uuid == usersSocket.ob.uuid) { if (uuid == usersSocket.ob.uuid) {
console.log('ALL USERS CLIENTS OFFLINE 1...........') console.log('ALL USERS CLIENTS OFFLINE 1...........')
usersSocket.ob.listOnline = [] usersSocket.ob.listOnline = []
usersSocket.ob.listOnlineAux = [] usersSocket.ob.listOnlineAux = []
usersSocket.ob.uuid = undefined usersSocket.ob.uuid = undefined
} }
} }
} else { } else {
usersSocket.ob.listOnline.forEach(async (el: any) => { usersSocket.ob.listOnline.forEach(async (el: any) => {
const indexAux = lstOnline.findIndex((e: any) => e.id == el.id) const indexAux = lstOnline.findIndex((e: any) => e.id == el.id)
if (indexAux == -1) { if (indexAux == -1) {
const userOnline = await createOrUpdateOnlineUserService({ userId: el.id, status: 'online' }) const userOnline = await createOrUpdateOnlineUserService({ userId: el.id, status: 'online' })
if (userOnline) { if (userOnline) {
el.onlineTime = userOnline.onlineTime el.onlineTime = userOnline.onlineTime
el.updatedAt = userOnline.updatedAt, el.updatedAt = userOnline.updatedAt,
console.log(' * CREATED OR UPDATED USER TO ONLINE: ', userOnline.userId) console.log(' * CREATED OR UPDATED USER TO ONLINE: ', userOnline.userId)
lstOnline.push({ 'id': el.id, 'status': 'online' }) lstOnline.push({ 'id': el.id, 'status': 'online' })
} }
} }
if (el.status == 'waiting...') { if (el.status == 'waiting...') {
emitterOnline(el, el.status, false) emitterOnline(el, el.status, false)
} }
else { else {
emitterOnline(el, el.status) emitterOnline(el, el.status)
} }
}); });
let difference = lstOnline.filter((x: any) => !usersSocket.ob.listOnline.map((e: any) => e.id).includes(x.id)); let difference = lstOnline.filter((x: any) => !usersSocket.ob.listOnline.map((e: any) => e.id).includes(x.id));
difference.forEach(async (e: any) => { difference.forEach(async (e: any) => {
const index = lstOnline.findIndex((x: any) => x.id == e.id) const index = lstOnline.findIndex((x: any) => x.id == e.id)
if (index != -1) { if (index != -1) {
lstOnline.splice(index, 1) lstOnline.splice(index, 1)
const userOnline = await createOrUpdateOnlineUserService({ userId: e.id, status: 'offline' }) const userOnline = await createOrUpdateOnlineUserService({ userId: e.id, status: 'offline' })
} }
}) })
} }
count++ count++
} }
if (countTest > 5) { if (countTest > 5) {
countTest = 0 countTest = 0
} }
if (countTest == 0) { if (countTest == 0) {
try { try {
console.log(' Carregando usuarios no listUserId...') console.log(' Carregando usuarios no listUserId...')
listUserId = await ListUserParamiterService({ profile: 'user' }) listUserId = await ListUserParamiterService({ profile: 'user' })
} catch (error) { } catch (error) {
console.log('There was an erro on ListUserParamiterService: ', error) console.log('There was an erro on ListUserParamiterService: ', error)
return return
} }
} }
countTest = 1 countTest = 1
listUserId.forEach((u) => { listUserId.forEach((u) => {
const io = getIO(); const io = getIO();
io.emit("isOnline", { action: "online", userId: u.id }); io.emit("isOnline", { action: "online", userId: u.id });
}); });
} catch (error) { } catch (error) {
console.log('>>> There was an error no WhoIsOnlineMonitor.ts: ',error) console.log('>>> There was an error no WhoIsOnlineMonitor.ts: ', error)
stopWhoIsOnlineMonitor()
startWhoIsOnlineMonitor() listUserId = []
} count = 0
countTest = 0
uuid = 0
}
}; };
export const startWhoIsOnlineMonitor = async (mileseconds?: number) => {
const WhoIsOnlineMonitor = async () => {
try {
clearInterval(_fifo);
await monitor()
} catch (error) {
console.log('error on WhoIsOnlineMonitor: ', error)
}
finally {
_fifo = setInterval(WhoIsOnlineMonitor, 3000);
}
}
_fifo = setInterval(WhoIsOnlineMonitor, 3000);
const startWhoIsOnlineMonitor = async (mileseconds?: number) => {
listUserId = [] listUserId = []
count = 0 count = 0
countTest = 0 countTest = 0
uuid = 0 uuid = 0
if (mileseconds) { clearInterval(_fifo);
timeInterval = mileseconds _fifo = setInterval(WhoIsOnlineMonitor, 3000);
}
whoIsOnline_monitor = setInterval(monitor, timeInterval)
// if (mileseconds) {
// timeInterval = mileseconds
// }
} }
export const stopWhoIsOnlineMonitor = async () => { const stopWhoIsOnlineMonitor = async () => {
clearInterval(whoIsOnline_monitor) clearInterval(_fifo);
// _fifo = setInterval(WhoIsOnlineMonitor, 3000);
} }
export { WhoIsOnlineMonitor, startWhoIsOnlineMonitor, stopWhoIsOnlineMonitor }

View File

@ -3,10 +3,8 @@ import app from "./app";
import { initIO } from "./libs/socket"; import { initIO } from "./libs/socket";
import { logger } from "./utils/logger"; import { logger } from "./utils/logger";
import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhatsAppsSessions"; import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhatsAppsSessions";
import "./helpers/SchedulingNotifySendMessage"
import { startSchedulingMonitor } from "./helpers/SchedulingNotifySendMessage" import "./helpers/WhoIsOnlineMonitor"
import { startWhoIsOnlineMonitor } from "./helpers/WhoIsOnlineMonitor"
import { loadTicketsCache, flushCache, cacheSize } from './helpers/TicketCache' import { loadTicketsCache, flushCache, cacheSize } from './helpers/TicketCache'
import { loadContactsCache } from './helpers/ContactsCache' import { loadContactsCache } from './helpers/ContactsCache'
@ -14,6 +12,7 @@ import "./helpers/CloseBotTickets";
import { loadWhatsappCache } from './helpers/WhatsCache' import { loadWhatsappCache } from './helpers/WhatsCache'
import { delRestoreControllFile } from "./helpers/RestoreControll"; import { delRestoreControllFile } from "./helpers/RestoreControll";
import { createSessionDir } from "./helpers/CreateSessionDir"; import { createSessionDir } from "./helpers/CreateSessionDir";
import { loadSchedulesCache, } from "./helpers/SchedulingNotifyCache";
const server = app.listen(process.env.PORT, () => { const server = app.listen(process.env.PORT, () => {
logger.info(`Server started on port: ${process.env.PORT}`); logger.info(`Server started on port: ${process.env.PORT}`);
@ -31,19 +30,19 @@ gracefulShutdown(server);
console.log('cacheSize: ', cacheLength) console.log('cacheSize: ', cacheLength)
if(cacheLength == 0){ if (cacheLength == 0) {
console.log('Loading from cache...') console.log('Loading from cache...')
await flushCache() await flushCache()
await loadContactsCache() await loadContactsCache()
await loadTicketsCache() await loadTicketsCache()
await loadWhatsappCache()
} }
await loadWhatsappCache()
await loadSchedulesCache()
})() })()
createSessionDir() createSessionDir()
delRestoreControllFile() delRestoreControllFile()
startSchedulingMonitor(5000)
startWhoIsOnlineMonitor(3000)

View File

@ -1,4 +1,5 @@
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import { createSchedulingNotifyCache } from "../../helpers/SchedulingNotifyCache";
import SchedulingNotify from "../../models/SchedulingNotify"; import SchedulingNotify from "../../models/SchedulingNotify";
@ -55,10 +56,11 @@ const CreateSchedulingNotifyService = async ({
schedulingTime, schedulingTime,
message message
}) })
} }
await createSchedulingNotifyCache(JSON.parse(JSON.stringify(schedulingNotify)))
return schedulingNotify return schedulingNotify
} }

View File

@ -1,68 +1,83 @@
import { Op, Sequelize } from "sequelize"; import { Op, Sequelize } from "sequelize";
import { searchScheduleCache } from "../../helpers/SchedulingNotifyCache";
import SchedulingNotify from "../../models/SchedulingNotify"; import SchedulingNotify from "../../models/SchedulingNotify";
interface Request { interface Request {
searchParam?: string; searchParam?: string;
pageNumber?: string; pageNumber?: string;
} }
interface Response {
schedulingNotifies: SchedulingNotify[];
count: number;
hasMore: boolean;
}
const ListSchedulingNotifyService = async ({
searchParam = "",
pageNumber = "1"
}: Request): Promise<Response> => {
// const whereCondition = {
// message: Sequelize.where(
// Sequelize.fn("date", Sequelize.col("schedulingDate")), `${searchParam.toLowerCase().trim()}`,
// ),
// };
let date = searchParam.split(' ')[0] interface Response {
let hour = searchParam.split(' ')[1].split(':')[0] schedulingNotifies: SchedulingNotify[];
let minute = searchParam.split(' ')[1].split(':')[1] count: number;
hasMore: boolean;
const whereCondition = { }
[Op.and]: [
{
"$schedulingTime$": Sequelize.where(Sequelize.fn("date", Sequelize.col("schedulingTime")), `${date.trim()}`)
},
{
"$schedulingTime$": Sequelize.where(Sequelize.fn("hour", Sequelize.col("schedulingTime")), `${hour.trim()}`)
},
{
"$schedulingTime$": Sequelize.where(Sequelize.fn("minute", Sequelize.col("schedulingTime")), `${minute.trim()}`)
}
]
};
const ListSchedulingNotifyService = async ({
searchParam = "",
pageNumber = "1"
}: Request): Promise<Response> => {
// const whereCondition = {
// message: Sequelize.where(
// Sequelize.fn("date", Sequelize.col("schedulingDate")), `${searchParam.toLowerCase().trim()}`,
// ),
// };
let date = searchParam.split(' ')[0]
let hour = searchParam.split(' ')[1].split(':')[0]
let minute = searchParam.split(' ')[1].split(':')[1]
let fromCache = null
fromCache = await searchScheduleCache(date, hour, minute)
if (fromCache) {
const limit = 1;
const offset = limit * (+pageNumber - 1);
const { count, rows: schedulingNotifies } = await SchedulingNotify.findAndCountAll({
raw: true,
where: whereCondition,
limit,
offset,
order: [["id", "ASC"]]
});
const hasMore = count > offset + schedulingNotifies.length;
return { return {
schedulingNotifies, schedulingNotifies: fromCache,
count, count: 0,
hasMore hasMore: false,
}; };
}
const whereCondition = {
[Op.and]: [
{
"$schedulingTime$": Sequelize.where(Sequelize.fn("date", Sequelize.col("schedulingTime")), `${date.trim()}`)
},
{
"$schedulingTime$": Sequelize.where(Sequelize.fn("hour", Sequelize.col("schedulingTime")), `${hour.trim()}`)
},
{
"$schedulingTime$": Sequelize.where(Sequelize.fn("minute", Sequelize.col("schedulingTime")), `${minute.trim()}`)
}
]
}; };
export default ListSchedulingNotifyService;
const limit = 1;
const offset = limit * (+pageNumber - 1);
const { count, rows: schedulingNotifies } = await SchedulingNotify.findAndCountAll({
raw: true,
where: whereCondition,
limit,
offset,
order: [["id", "ASC"]]
});
const hasMore = count > offset + schedulingNotifies.length;
return {
schedulingNotifies,
count,
hasMore
};
};
export default ListSchedulingNotifyService;

View File

@ -128,8 +128,14 @@ const verifyMediaMessage = async (
} }
try { try {
// await writeFileAsync(
// join(__dirname, "..", "..", "..", "public", media.filename),
// media.data,
// "base64"
// );
await writeFileAsync( await writeFileAsync(
join(__dirname, "..", "..", "..", "public", media.filename), join(__dirname, "..", "..", "..", "..", "..", "public", media.filename),
media.data, media.data,
"base64" "base64"
); );
@ -821,19 +827,11 @@ const botSendMessage = (ticket: Ticket, contact: Contact, wbot: Session, msg: st
const _clear_lst = () => { const _clear_lst = () => {
console.log('WHATSAPP MESSAGE ID MULTI SESSION: ', lst.length) if (lst.length <= 200 ) return
if (lst.length <= 200 ) return
console.log('BEFORE lst SLICE: ', lst)
console.log('lst whatsapp message id sliced! | lst.length: ', lst.length)
const chunk: any = Math.floor((lst.length / 2)) const chunk: any = Math.floor((lst.length / 2))
lst = lst.slice(chunk, chunk + lst.length); lst = lst.slice(chunk, chunk + lst.length);
console.log('AFTER lst SLICE: ', lst)
} }
@ -882,38 +880,7 @@ const handleMessage = async (
// console.log('LIST OF ID MESSAGE lst: ', lst) // console.log('LIST OF ID MESSAGE lst: ', lst)
console.log('PASSOU.................................FROM: ', msg.from.split("@")[0], ' | ID: ', msg.id.id) console.log('PASSOU.................................FROM: ', msg.from.split("@")[0], ' | ID: ', msg.id.id)
// const contact_message = await getLastId(`contact_message:5517988310949`)
// if (contact_message && contact_message.id == msg.id.id) {
// console.log('IGNORED MESSAGE SAME ID FROM CLIENT: ', contact_message.id)
// return
// }
// await insertMessageContactCache(`contact_message:5517988310949`,
// {
// from: msg.from.split("@")[0],
// to: msg.to.split("@")[0],
// id: msg.id.id
// })
// console.log('PASSOU............................................... contact_message.id: ',contact_message.id)
// if (testLastId == msg.id.id) {
// console.log('IGNORED MESSAGE SAME ID!')
// return
// }
// testLastId = msg.id.id
// console.log('PASSOU............................................... msg.id.id: ',msg.id.id)
if (!isValidMsg(msg)) { if (!isValidMsg(msg)) {

View File

@ -26,6 +26,8 @@ import ErrorIcon from "@material-ui/icons/Error";
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle"; import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
import PowerSettingsNewIcon from "@material-ui/icons/PowerSettingsNew"; import PowerSettingsNewIcon from "@material-ui/icons/PowerSettingsNew";
import { i18n } from "../../translate/i18n";
const TableUser = ({ classes, usersOnlineInfo, logout }) => { const TableUser = ({ classes, usersOnlineInfo, logout }) => {
const [search, setSearch] = React.useState(""); const [search, setSearch] = React.useState("");
const [filterStatus, setFilterStatus] = React.useState(null); const [filterStatus, setFilterStatus] = React.useState(null);
@ -48,7 +50,8 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => {
color="primary" color="primary"
style={{ marginBottom: "16px" }} style={{ marginBottom: "16px" }}
> >
Lista de Usuários
{i18n.t("dashboard.table_users.title")}
</Typography> </Typography>
</Grid> </Grid>
<Grid item sx={8} width="100%"> <Grid item sx={8} width="100%">
@ -84,12 +87,12 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => {
<Table> <Table>
<TableHead> <TableHead>
<TableRow className={classes.tableRowHead}> <TableRow className={classes.tableRowHead}>
<TableCell>Nome</TableCell> <TableCell>{i18n.t("dashboard.table_users.column0")}</TableCell>
<TableCell>Em Atendimento/Finalizado(s)</TableCell> <TableCell>{i18n.t("dashboard.table_users.column1")}</TableCell>
<TableCell>abertos Por Fila</TableCell> <TableCell>{i18n.t("dashboard.table_users.column2")}</TableCell>
<TableCell>Fechados Por Fila</TableCell> <TableCell>{i18n.t("dashboard.table_users.column3")}</TableCell>
<TableCell>Tempo Online</TableCell> <TableCell>{i18n.t("dashboard.table_users.column4")}</TableCell>
<TableCell>Ações</TableCell> <TableCell>{i18n.t("dashboard.table_users.column5")}</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>

View File

@ -10,6 +10,8 @@ import chat from '@material-ui/icons/Chat';
import React from 'react'; import React from 'react';
import { i18n } from '../../../translate/i18n';
const MTable = (props) => { const MTable = (props) => {
const tableRef = React.useRef(); const tableRef = React.useRef();
@ -79,7 +81,7 @@ const MTable = (props) => {
if (props.hasChild) { if (props.hasChild) {
render(<Modal data={selectedRow.messages} render(<Modal data={selectedRow.messages}
hasChild={false} hasChild={false}
modal_header={'Chat do atendimento pelo Whatsapp'} modal_header={i18n.t("reports.listTitles.title2_1")}
user={selectedRow.user.name} user={selectedRow.user.name}
clientContactNumber={selectedRow.contact.number} />) clientContactNumber={selectedRow.contact.number} />)
} }

View File

@ -10,23 +10,25 @@ import DialogTitle from '@mui/material/DialogTitle';
//import DataGridTable from '../Table'; //import DataGridTable from '../Table';
import MTable from "../MTable"; import MTable from "../MTable";
import { i18n } from '../../../translate/i18n';
import ExportCSV from '../ExportCSV' import ExportCSV from '../ExportCSV'
//import { margin } from '@mui/system'; //import { margin } from '@mui/system';
let columns = [ let columns = [
{ {
title: 'Atendente/Cliente', title: `${i18n.t("reports.listColumns.column2_1")}`,
field: 'fromMe', field: 'fromMe',
}, },
{ {
title: 'Mensagem', title: `${i18n.t("reports.listColumns.column0_8")}`,
field: 'body', field: 'body',
//cellStyle: {whiteSpace: 'nowrap'}, //cellStyle: {whiteSpace: 'nowrap'},
}, },
{ title: 'Criado', field: 'createdAt' } { title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' }
/*cellStyle: { /*cellStyle: {
backgroundColor: '#039be5', backgroundColor: '#039be5',

View File

@ -23,6 +23,9 @@ import fileDownload from 'js-file-download'
import openSocket from "socket.io-client"; import openSocket from "socket.io-client";
import { i18n } from "../../translate/i18n";
const report = [{ 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }] const report = [{ 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }]
@ -206,17 +209,17 @@ Item.propTypes = {
let columnsData = [ let columnsData = [
{ title: 'Unidade', field: 'whatsapp.name' }, { title: `${i18n.t("reports.listColumns.column1_1")}`, field: 'whatsapp.name' },
{ title: 'Atendente', field: 'user.name' }, { title: `${i18n.t("reports.listColumns.column1_2")}`, field: 'user.name' },
{ title: 'Contato', field: 'contact.number' }, { title: `${i18n.t("reports.listColumns.column0_4")}`, field: 'contact.number' },
{ title: 'Nome', field: 'contact.name' }, { title: `${i18n.t("reports.listColumns.column0_3")}`, field: 'contact.name' },
{ title: 'Assunto', field: 'queue.name' }, { title: `${i18n.t("reports.listColumns.column1_5")}`, field: 'queue.name' },
{ title: 'Status', field: 'status' }, { title: 'Status', field: 'status' },
{ title: 'Criado', field: 'createdAt' }, { title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
{title: 'Atualizado', field: 'updatedAt'}, {title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt'},
{ title: 'Status de encerramento', field: 'statusChatEnd' }]; { title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' }];
const Report = () => { const Report = () => {
@ -630,12 +633,12 @@ const Report = () => {
<MainContainer> <MainContainer>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}> <Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
<Item><SelectField func={textFieldSelectUser} emptyField={true} header={'Usuário'} currencies={users.map((obj) => { <Item><SelectField func={textFieldSelectUser} emptyField={true} header={i18n.t("reports.user")} currencies={users.map((obj) => {
return { 'value': obj.id, 'label': obj.name } return { 'value': obj.id, 'label': obj.name }
})} /></Item> })} /></Item>
<Item><DatePicker1 func={datePicker1Value} minDate={false} startEmpty={false} title={'Data inicio'} /></Item> <Item><DatePicker1 func={datePicker1Value} minDate={false} startEmpty={false} title={i18n.t("reports.dateStart")} /></Item>
<Item><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={false} title={'Data fim'} /></Item> <Item><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={false} title={i18n.t("reports.dateEnd")} /></Item>
<Item sx={{ display: 'grid', gridColumn: '4 / 5', }}> <Item sx={{ display: 'grid', gridColumn: '4 / 5', }}>
@ -672,7 +675,7 @@ const Report = () => {
handleScroll={handleScroll} handleScroll={handleScroll}
table_title={'Atendimento por atendentes'} /> table_title={i18n.t("reports.listTitles.title1_1")} />
</> </>
@ -689,7 +692,7 @@ const Report = () => {
}} }}
title="Usuários online/offline" title={i18n.t("reports.listTitles.title3_1")}
columns={ columns={
[ [
@ -724,8 +727,8 @@ const Report = () => {
}, },
{ title: 'Tempo online', field: 'sumOnlineTime.sum' }, { title: 'Tempo online', field: 'sumOnlineTime.sum' },
{ title: 'Data inicio', field: 'startDate' }, { title: `${i18n.t("reports.dateStart")}`, field: 'startDate' },
{ title: 'Data fim', field: 'endDate' }, { title: `${i18n.t("reports.dateStart")}`, field: 'endDate' },
{ title: 'Em atendimento', field: 'sumOpen.count' }, { title: 'Em atendimento', field: 'sumOpen.count' },
{ title: 'Finalizado', field: 'sumClosed.count' }, { title: 'Finalizado', field: 'sumClosed.count' },

View File

@ -38,7 +38,7 @@ import { toast } from "react-toastify";
import toastError from "../../errors/toastError"; import toastError from "../../errors/toastError";
import ConfirmationModal from "../../components/ConfirmationModal"; import ConfirmationModal from "../../components/ConfirmationModal";
import { i18n } from "../../translate/i18n";
const reducerQ = (state, action) => { const reducerQ = (state, action) => {
@ -467,8 +467,8 @@ const SchedulesReminder = () => {
<Item><DatePicker1 func={datePicker1Value} minDate={false} startEmpty={true} reset={resetChild} setReset={setReset} title={i18n.t("report.date.dateStart")} /></Item> <Item><DatePicker1 func={datePicker1Value} minDate={false} startEmpty={true} reset={resetChild} setReset={setReset} title={i18n.t("reports.dateStart")} /></Item>
<Item><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={true} reset={resetChild} setReset={setReset} title={'Data fim'} /></Item> <Item><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={true} reset={resetChild} setReset={setReset} title={i18n.t("reports.dateEnd")} /></Item>
<Item sx={{ gridColumn: '4 / 5' }}> <Item sx={{ gridColumn: '4 / 5' }}>
{/* <Button size="small" variant="contained" onClick={()=>{handleQuery()}}>GO</Button>*/} {/* <Button size="small" variant="contained" onClick={()=>{handleQuery()}}>GO</Button>*/}
@ -503,18 +503,26 @@ const SchedulesReminder = () => {
</ConfirmationModal> </ConfirmationModal>
<MaterialTable <MaterialTable
// title="Lembretes/Agendamentos"
title={i18n.t("report.listTitle.title1")} localization={{
header: {
actions: `${i18n.t("reports.listColumns.column0_1")}`
},
}}
title={i18n.t("reports.listTitles.title0_1")}
columns={ columns={
[ [
{ title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> }, { title: `${i18n.t("reports.listColumns.column0_2")}`, field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> },
{ title: 'Nome', field: 'ticket.contact.name' }, { title: `${i18n.t("reports.listColumns.column0_3")}`, field: 'ticket.contact.name' },
{ title: 'Contato', field: 'ticket.contact.number' }, { title: `${i18n.t("reports.listColumns.column0_4")}`, field: 'ticket.contact.number' },
{ title: 'Lemb/Agen', field: 'scheduleReminder' }, { title: `${i18n.t("reports.listColumns.column0_5")}`, field: 'scheduleReminder' },
{ title: 'Envio', field: 'schedulingTime' }, { title: `${i18n.t("reports.listColumns.column0_6")}`, field: 'schedulingTime' },
{ title: 'Data', field: 'schedulingDate' }, { title: `${i18n.t("reports.listColumns.column0_7")}`, field: 'schedulingDate' },
{ title: 'Mensagem', field: 'message', width: "80%" }, { title: `${i18n.t("reports.listColumns.column0_8")}`, field: 'message', width: "80%" },
] ]
} }

View File

@ -49,6 +49,16 @@ const messages = {
closed: { closed: {
title: "Closed" title: "Closed"
} }
},
table_users:{
title: 'User List',
column0: 'Name',
column1: 'In Service/Finished',
column2: 'Open by Queue',
column3: 'Closed by Queue',
column4: 'Online time',
column5: 'Actions',
} }
}, },
connections: { connections: {
@ -313,7 +323,8 @@ const messages = {
queues: "Queues", queues: "Queues",
administration: "Administration", administration: "Administration",
users: "Users", users: "Users",
settings: "Settings", settings: "Settings",
schedules: "Schedules",
dialogflow: "Dialogflow", dialogflow: "Dialogflow",
}, },
appBar: { appBar: {
@ -323,13 +334,39 @@ const messages = {
}, },
}, },
}, },
report: { reports: {
listTitle: { listTitles: {
title1: "Reminders/Schedules", title0_1: "Reminders/Schedulings",
title1_1: "Calls by attendants",
title2_1: "Whatsapp chat",
title3_1: "Users online/offline"
}, },
search: { listColumns:{
search1: "Number/Name...", column0_1: 'Actions',
} column0_2: 'Pic',
column0_3: 'Name',
column0_4: 'Contact',
column0_5: 'Remin/Sched',
column0_6: 'Send',
column0_7: 'Date',
column0_8: 'Message',
column1_1: 'Store',
column1_2: 'Attendant',
column1_5: 'Subject',
column1_6: 'Status',
column1_7: 'Created',
column1_8: 'Updated',
column1_9: 'Closing status',
column2_1: 'Attendant/Client',
},
search: 'Number/Name...',
dateStart: 'Start date',
dateEnd: 'End date',
user: 'User'
}, },
notifications: { notifications: {
noTickets: "No notifications.", noTickets: "No notifications.",

View File

@ -50,6 +50,17 @@ const messages = {
closed: { closed: {
title: "Finalizado" title: "Finalizado"
} }
},
table_users:{
title: 'Lista de usuarios',
column0: 'Nombre',
column1: 'En servicio/Terminado(S)',
column2: 'Abrir por cola',
column3: 'Cerrado por cola',
column4: 'Tiempo Online',
column5: 'Actions',
} }
}, },
connections: { connections: {
@ -319,6 +330,7 @@ const messages = {
administration: "Administración", administration: "Administración",
users: "Usuarios", users: "Usuarios",
settings: "Configuración", settings: "Configuración",
schedules: "Recordatorio",
dialogflow: "Dialogflow", dialogflow: "Dialogflow",
}, },
appBar: { appBar: {
@ -328,13 +340,38 @@ const messages = {
}, },
}, },
}, },
report: { reports: {
listTitle: { listTitles: {
title1: "Recordatorios/Programación", title0_1: "Recordatorios/Programación",
title1_1: "Llamadas de asistentes",
title2_1: "Chat de whatsapp",
title3_1: "Usuarios online/offline"
}, },
search: { listColumns:{
search1: "Número/Nombre...", column0_1: 'Acción',
} column0_2: 'Pic',
column0_3: 'Nombre',
column0_4: 'Contacto',
column0_5: 'Record/Progr',
column0_6: 'Envío',
column0_7: 'Fecha',
column0_8: 'Mensaje',
column1_1: 'Almacenar',
column1_2: 'Secretario',
column1_5: 'Tema',
column1_6: 'Status',
column1_7: 'Creado',
column1_8: 'Actualizado',
column1_9: 'Estado de cierre',
column2_1: 'Secretario/Cliente',
},
search: 'Número/Nombre...',
dateStart: 'Fecha de inicio',
dateEnd: 'Fecha final',
user: 'Usuario'
}, },
notifications: { notifications: {
noTickets: "Sin notificaciones.", noTickets: "Sin notificaciones.",

View File

@ -49,6 +49,16 @@ const messages = {
closed: { closed: {
title: "Finalizado" title: "Finalizado"
} }
},
table_users:{
title: 'Lista De Usuários',
column0: 'Nome',
column1: 'Em Atendimento/Finalizado(S)',
column2: 'Abertos Por Fila',
column3: 'Fechados Por Fila',
column4: 'Tempo Online',
column5: 'Ações',
} }
}, },
connections: { connections: {
@ -317,6 +327,7 @@ const messages = {
administration: "Administração", administration: "Administração",
users: "Usuários", users: "Usuários",
settings: "Configurações", settings: "Configurações",
schedules: "Lembretes",
dialogflow: "Dialogflow", dialogflow: "Dialogflow",
}, },
appBar: { appBar: {
@ -326,20 +337,40 @@ const messages = {
}, },
}, },
}, },
report: { reports: {
listTitle: { listTitles: {
title1: "Lembretes/Agendamentos", title0_1: "Lembretes/Agendamentos",
title1_1: "Atendimento por atendentes",
title2_1: "Chat do atendimento pelo Whatsapp",
title3_1: "Usuários online/offline"
}, },
search: { listColumns:{
search1: "Numero/Nome...", column0_1: 'Ações',
}, column0_2: 'Foto',
date:{ column0_3: 'Nome',
dateStart: "Data início", column0_4: 'Contato',
dateEnd: "Data fim" column0_5: 'Lemb/Agen',
}, column0_6: 'Envio',
button:{ column0_7: 'Data',
column0_8: 'Mensagem',
column1_1: 'Unidade',
column1_2: 'Atendente',
column1_5: 'Assunto',
column1_6: 'Status',
column1_7: 'Criado',
column1_8: 'Atualizado',
column1_9: 'Status de encerramento',
column2_1: 'Atendente/Cliente',
},
search: 'Numer/Nome...',
dateStart: 'Data início',
dateEnd: 'Data fim',
user: 'Usuário'
}
}, },
notifications: { notifications: {
noTickets: "Nenhuma notificação.", noTickets: "Nenhuma notificação.",