[NEW] Livechat analytics functions (#15666)
* Livechat analytics functions * Move analytics functions to models * Fix params * Fix collection namepull/15764/head^2
parent
d86a3ed4ad
commit
485210f2f9
@ -0,0 +1,48 @@ |
||||
import { Users } from '../../../../models/server/raw'; |
||||
|
||||
const findAllAverageServiceTimeAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
agents: await Users.findAllAverageServiceTime({ start, end, options }), |
||||
total: (await Users.findAllAverageServiceTime({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAllServiceTimeAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
agents: await Users.findAllServiceTime({ start, end, options }), |
||||
total: (await Users.findAllServiceTime({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAvailableServiceTimeHistoryAsync = async ({ |
||||
start, |
||||
end, |
||||
fullReport, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
agents: await Users.findAvailableServiceTimeHistory({ start, end, fullReport, options }), |
||||
total: (await Users.findAvailableServiceTimeHistory({ start, end, fullReport })).length, |
||||
}; |
||||
}; |
||||
|
||||
export const findAllAverageServiceTime = ({ start, end, options }) => Promise.await(findAllAverageServiceTimeAsync({ start, end, options })); |
||||
export const findAllServiceTime = ({ start, end, options }) => Promise.await(findAllServiceTimeAsync({ start, end, options })); |
||||
export const findAvailableServiceTimeHistory = ({ start, end, fullReport, options }) => Promise.await(findAvailableServiceTimeHistoryAsync({ start, end, fullReport, options })); |
@ -0,0 +1,108 @@ |
||||
import { LivechatDepartment } from '../../../../models/server/raw'; |
||||
|
||||
const findAllRoomsAsync = async ({ |
||||
start, |
||||
end, |
||||
answered, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findAllRooms({ start, answered, end, options }), |
||||
total: (await LivechatDepartment.findAllRooms({ start, answered, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAllAverageServiceTimeAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findAllAverageServiceTime({ start, end, options }), |
||||
total: (await LivechatDepartment.findAllAverageServiceTime({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAllServiceTimeAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findAllServiceTime({ start, end, options }), |
||||
total: (await LivechatDepartment.findAllServiceTime({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAllAverageWaitingTimeAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findAllAverageWaitingTime({ start, end, options }), |
||||
total: (await LivechatDepartment.findAllAverageWaitingTime({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAllNumberOfTransferedRoomsAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findAllNumberOfTransferedRooms({ start, end, options }), |
||||
total: (await LivechatDepartment.findAllNumberOfTransferedRooms({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findAllNumberOfAbandonedRoomsAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findAllNumberOfAbandonedRooms({ start, end, options }), |
||||
total: (await LivechatDepartment.findAllNumberOfAbandonedRooms({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
const findPercentageOfAbandonedRoomsAsync = async ({ |
||||
start, |
||||
end, |
||||
options = {}, |
||||
}) => { |
||||
if (!start || !end) { |
||||
throw new Error('"start" and "end" must be provided'); |
||||
} |
||||
return { |
||||
departments: await LivechatDepartment.findPercentageOfAbandonedRooms({ start, end, options }), |
||||
total: (await LivechatDepartment.findPercentageOfAbandonedRooms({ start, end })).length, |
||||
}; |
||||
}; |
||||
|
||||
export const findAllAverageServiceTime = ({ start, end, options }) => Promise.await(findAllAverageServiceTimeAsync({ start, end, options })); |
||||
export const findAllRooms = ({ start, end, answered, options }) => Promise.await(findAllRoomsAsync({ start, end, answered, options })); |
||||
export const findAllServiceTime = ({ start, end, options }) => Promise.await(findAllServiceTimeAsync({ start, end, options })); |
||||
export const findAllAverageWaitingTime = ({ start, end, options }) => Promise.await(findAllAverageWaitingTimeAsync({ start, end, options })); |
||||
export const findAllNumberOfTransferedRooms = ({ start, end, options }) => Promise.await(findAllNumberOfTransferedRoomsAsync({ start, end, options })); |
||||
export const findAllNumberOfAbandonedRooms = ({ start, end, options }) => Promise.await(findAllNumberOfAbandonedRoomsAsync({ start, end, options })); |
||||
export const findPercentageOfAbandonedRooms = ({ start, end, options }) => Promise.await(findPercentageOfAbandonedRoomsAsync({ start, end, options })); |
@ -1,5 +1,418 @@ |
||||
import { BaseRaw } from './BaseRaw'; |
||||
import { getValue } from '../../../settings/server/raw'; |
||||
|
||||
export class LivechatDepartmentRaw extends BaseRaw { |
||||
findAllRooms({ start, end, answered, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
]; |
||||
if (answered !== undefined) { |
||||
roomsFilter.push({ [answered ? '$ne' : '$eq']: ['$$room.waitingResponse', true] }); |
||||
} |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const project = { |
||||
$project: { |
||||
name: 1, |
||||
description: 1, |
||||
enabled: 1, |
||||
rooms: { |
||||
$size: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}; |
||||
const params = [lookup, project]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
|
||||
findAllAverageServiceTime({ start, end, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
]; |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const projects = [ |
||||
{ |
||||
$project: { |
||||
department: '$$ROOT', |
||||
rooms: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
$project: { |
||||
department: '$department', |
||||
chats: { $size: '$rooms' }, |
||||
chatsDuration: { $sum: '$rooms.metrics.chatDuration' }, |
||||
}, |
||||
}, |
||||
{ |
||||
$project: { |
||||
name: '$department.name', |
||||
description: '$department.description', |
||||
enabled: '$department.enabled', |
||||
averageServiceTimeInSeconds: { $ceil: { $cond: [{ $eq: ['$chats', 0] }, 0, { $divide: ['$chatsDuration', '$chats'] }] } }, |
||||
}, |
||||
}]; |
||||
const params = [lookup, ...projects]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
|
||||
findAllServiceTime({ start, end, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
]; |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const projects = [ |
||||
{ |
||||
$project: { |
||||
department: '$$ROOT', |
||||
rooms: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
$project: { |
||||
name: '$department.name', |
||||
description: '$department.description', |
||||
enabled: '$department.enabled', |
||||
chats: { $size: '$rooms' }, |
||||
chatsDuration: { $ceil: { $sum: '$rooms.metrics.chatDuration' } }, |
||||
}, |
||||
}]; |
||||
const params = [lookup, ...projects]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
|
||||
findAllAverageWaitingTime({ start, end, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
{ $ne: ['$$room.waitingResponse', true] }, |
||||
]; |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const projects = [{ |
||||
$project: { |
||||
department: '$$ROOT', |
||||
rooms: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
$project: { |
||||
department: '$department', |
||||
chats: { $size: '$rooms' }, |
||||
chatsFirstResponses: { $sum: '$rooms.metrics.response.ft' }, |
||||
}, |
||||
}, |
||||
{ |
||||
$project: { |
||||
name: '$department.name', |
||||
description: '$department.description', |
||||
enabled: '$department.enabled', |
||||
averageWaitingTimeInSeconds: { $ceil: { $cond: [{ $eq: ['$chats', 0] }, 0, { $divide: ['$chatsFirstResponses', '$chats'] }] } }, |
||||
}, |
||||
}]; |
||||
const params = [lookup, ...projects]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
|
||||
findAllNumberOfTransferedRooms({ start, end, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
]; |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const projectRooms = { |
||||
$project: { |
||||
department: '$$ROOT', |
||||
rooms: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}; |
||||
const projectTransfersSize = { |
||||
$project: { |
||||
department: '$department', |
||||
transfers: { $size: { $ifNull: ['$rooms.transferHistory', []] } }, |
||||
}, |
||||
}; |
||||
const group = { |
||||
$group: { |
||||
_id: { |
||||
departmentId: '$department._id', |
||||
name: '$department.name', |
||||
description: '$department.description', |
||||
enabled: '$department.enabled', |
||||
}, |
||||
numberOfTransferedRooms: { $sum: '$transfers' }, |
||||
}, |
||||
}; |
||||
const presentationProject = { |
||||
$project: { |
||||
_id: '$_id.departmentId', |
||||
name: '$_id.name', |
||||
description: '$_id.description', |
||||
enabled: '$_id.enabled', |
||||
numberOfTransferedRooms: 1, |
||||
}, |
||||
}; |
||||
const unwind = { |
||||
$unwind: { |
||||
path: '$rooms', |
||||
preserveNullAndEmptyArrays: true, |
||||
}, |
||||
}; |
||||
const params = [lookup, projectRooms, unwind, projectTransfersSize, group, presentationProject]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
|
||||
async findAllNumberOfAbandonedRooms({ start, end, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
{ $gte: ['$$room.metrics.visitorInactivity', await getValue('Livechat_visitor_inactivity_timeout')] }, |
||||
]; |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const projects = [{ |
||||
$project: { |
||||
department: '$$ROOT', |
||||
rooms: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
$project: { |
||||
name: '$department.name', |
||||
description: '$department.description', |
||||
enabled: '$department.enabled', |
||||
abandonedRooms: { $size: '$rooms' }, |
||||
}, |
||||
}]; |
||||
const params = [lookup, ...projects]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
|
||||
findPercentageOfAbandonedRooms({ start, end, options = {} }) { |
||||
const roomsFilter = [ |
||||
{ $gte: ['$$room.ts', new Date(start)] }, |
||||
{ $lte: ['$$room.ts', new Date(end)] }, |
||||
]; |
||||
const lookup = { |
||||
$lookup: { |
||||
from: 'rocketchat_room', |
||||
localField: '_id', |
||||
foreignField: 'departmentId', |
||||
as: 'rooms', |
||||
}, |
||||
}; |
||||
const projectRooms = { |
||||
$project: { |
||||
department: '$$ROOT', |
||||
rooms: { |
||||
$filter: { |
||||
input: '$rooms', |
||||
as: 'room', |
||||
cond: { |
||||
$and: roomsFilter, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}; |
||||
const unwind = { |
||||
$unwind: { |
||||
path: '$rooms', |
||||
preserveNullAndEmptyArrays: true, |
||||
}, |
||||
}; |
||||
const group = { |
||||
$group: { |
||||
_id: { |
||||
departmentId: '$department._id', |
||||
name: '$department.name', |
||||
description: '$department.description', |
||||
enabled: '$department.enabled', |
||||
}, |
||||
abandonedChats: { |
||||
$sum: { |
||||
$cond: [{ |
||||
$and: [ |
||||
{ $ifNull: ['$rooms.metrics.visitorInactivity', false] }, |
||||
{ $gte: ['$rooms.metrics.visitorInactivity', 1] }, |
||||
], |
||||
}, 1, 0], |
||||
}, |
||||
}, |
||||
chats: { $sum: 1 }, |
||||
}, |
||||
}; |
||||
const presentationProject = { |
||||
$project: { |
||||
_id: '$_id.departmentId', |
||||
name: '$_id.name', |
||||
description: '$_id.description', |
||||
enabled: '$_id.enabled', |
||||
percentageOfAbandonedChats: { |
||||
$floor: { |
||||
$cond: [ |
||||
{ $eq: ['$chats', 0] }, |
||||
0, |
||||
{ $divide: [{ $multiply: ['$abandonedChats', 100] }, '$chats'] }, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
}; |
||||
const params = [lookup, projectRooms, unwind, group, presentationProject]; |
||||
if (options.offset) { |
||||
params.push({ $skip: options.offset }); |
||||
} |
||||
if (options.count) { |
||||
params.push({ $limit: options.count }); |
||||
} |
||||
if (options.sort) { |
||||
params.push({ $sort: { name: 1 } }); |
||||
} |
||||
return this.col.aggregate(params).toArray(); |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue