[NEW] Assign new Livechat conversations to bot agents first (#15317)

* Add a new setting to allow routing new Livechat conversations to Bot Agents first.

* Removed invalid console.log.
pull/9058/head^2
Renato Becker 7 years ago committed by Rodrigo Nascimento
parent 28e290cc46
commit 0e696d7119
  1. 8
      app/livechat/server/config.js
  2. 16
      app/livechat/server/hooks/beforeGetNextAgent.js
  3. 1
      app/livechat/server/index.js
  4. 23
      app/livechat/server/lib/Livechat.js
  5. 2
      app/livechat/server/lib/QueueManager.js
  6. 15
      app/livechat/server/lib/RoutingManager.js
  7. 62
      app/models/server/models/LivechatDepartmentAgents.js
  8. 56
      app/models/server/models/Users.js
  9. 2
      packages/rocketchat-i18n/i18n/en.i18n.json
  10. 2
      packages/rocketchat-i18n/i18n/pt-BR.i18n.json

@ -398,6 +398,14 @@ Meteor.startup(function() {
i18nDescription: 'Accept_incoming_livechat_requests_even_if_there_are_no_online_agents',
});
settings.add('Livechat_assign_new_conversation_to_bot', false, {
type: 'boolean',
group: 'Livechat',
section: 'Routing',
i18nLabel: 'Assign_new_conversations_to_bot_agent',
i18nDescription: 'Assign_new_conversations_to_bot_agent_description',
});
settings.add('Livechat_guest_pool_max_number_incoming_livechats_displayed', 0, {
type: 'int',
group: 'Livechat',

@ -0,0 +1,16 @@
import { callbacks } from '../../../callbacks';
import { settings } from '../../../settings';
import { Users, LivechatDepartmentAgents } from '../../../models';
callbacks.add('livechat.beforeGetNextAgent', (department) => {
if (!settings.get('Livechat_assign_new_conversation_to_bot')) {
return null;
}
if (department) {
return LivechatDepartmentAgents.getNextBotForDepartment(department);
}
return Users.getNextBotAgent();
}, callbacks.priority.HIGH, 'livechat-before-get-next-agent');

@ -6,6 +6,7 @@ import './permissions';
import '../lib/messageTypes';
import './config';
import './roomType';
import './hooks/beforeGetNextAgent';
import './hooks/externalMessage';
import './hooks/leadCapture';
import './hooks/markRoomResponded';

@ -48,12 +48,23 @@ export const Livechat = {
}),
online() {
if (settings.get('Livechat_accept_chats_with_no_agents')) {
return true;
}
if (settings.get('Livechat_assign_new_conversation_to_bot')) {
const botAgents = Livechat.getBotAgents();
if (botAgents && botAgents.count() > 0) {
return true;
}
}
const onlineAgents = Livechat.getOnlineAgents();
return (onlineAgents && onlineAgents.count() > 0) || settings.get('Livechat_accept_chats_with_no_agents');
},
getNextAgent(department) {
return RoutingManager.getMethod().getNextAgent(department);
return RoutingManager.getNextAgent(department);
},
getAgents(department) {
@ -62,12 +73,22 @@ export const Livechat = {
}
return Users.findAgents();
},
getOnlineAgents(department) {
if (department) {
return LivechatDepartmentAgents.getOnlineForDepartment(department);
}
return Users.findOnlineAgents();
},
getBotAgents(department) {
if (department) {
return LivechatDepartmentAgents.getBotsForDepartment(department);
}
return Users.findBotAgents();
},
getRequiredDepartment(onlineRequired = true) {
const departments = LivechatDepartment.findEnabledWithAgents();

@ -36,7 +36,7 @@ export const QueueManager = {
agent = RoutingManager.getMethod().delegateAgent(agent, inquiry);
}
inquiry = await callbacks.run('livechat.beforeRouteChat', inquiry);
inquiry = await callbacks.run('livechat.beforeRouteChat', inquiry, agent);
if (inquiry.status !== 'ready') {
return room;
}

@ -35,19 +35,28 @@ export const RoutingManager = {
return this.getMethod().config || {};
},
async getNextAgent(department) {
let agent = callbacks.run('livechat.beforeGetNextAgent', department);
if (!agent) {
agent = await this.getMethod().getNextAgent(department);
}
return agent;
},
async delegateInquiry(inquiry, agent) {
// return Room Object
const { department, rid } = inquiry;
if (!agent || (agent.username && !Users.findOneOnlineAgentByUsername(agent.username))) {
agent = await this.getMethod().getNextAgent(department);
agent = await this.getNextAgent(department);
}
if (!agent) {
return LivechatRooms.findOneById(rid);
}
const room = this.takeInquiry(inquiry, agent);
return room;
return this.takeInquiry(inquiry, agent);
},
assignAgent(inquiry, agent) {

@ -12,6 +12,7 @@ export class LivechatDepartmentAgents extends Base {
this.tryEnsureIndex({ departmentId: 1 });
this.tryEnsureIndex({ agentId: 1 });
this.tryEnsureIndex({ username: 1 });
}
findByDepartmentId(departmentId) {
@ -102,6 +103,67 @@ export class LivechatDepartmentAgents extends Base {
return this.find(query);
}
getBotsForDepartment(departmentId) {
const agents = this.findByDepartmentId(departmentId).fetch();
if (agents.length === 0) {
return;
}
const botUsers = Users.findBotAgents(_.pluck(agents, 'username'));
const botUsernames = _.pluck(botUsers.fetch(), 'username');
const query = {
departmentId,
username: {
$in: botUsernames,
},
};
return this.find(query);
}
getNextBotForDepartment(departmentId) {
const agents = this.findByDepartmentId(departmentId).fetch();
if (agents.length === 0) {
return;
}
const botUsers = Users.findBotAgents(_.pluck(agents, 'username'));
const botUsernames = _.pluck(botUsers.fetch(), 'username');
const query = {
departmentId,
username: {
$in: botUsernames,
},
};
const sort = {
count: 1,
order: 1,
username: 1,
};
const update = {
$inc: {
count: 1,
},
};
const collectionObj = this.model.rawCollection();
const findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj);
const bot = findAndModify(query, sort, update);
if (bot && bot.value) {
return {
agentId: bot.value.agentId,
username: bot.value.username,
};
}
return null;
}
findUsersInQueue(usersList) {
const query = {};

@ -86,6 +86,31 @@ export class Users extends Base {
return this.find(query);
}
findBotAgents(usernameList) {
const query = {
roles: {
$all: ['bot', 'livechat-agent'],
},
...usernameList && {
username: {
$in: [].concat(usernameList),
},
},
};
return this.find(query);
}
findOneBotAgent() {
const query = {
roles: {
$all: ['bot', 'livechat-agent'],
},
};
return this.findOne(query);
}
findOneOnlineAgentByUsername(username) {
const query = {
username,
@ -172,6 +197,37 @@ export class Users extends Base {
return null;
}
getNextBotAgent() {
const query = {
roles: {
$all: ['bot', 'livechat-agent'],
},
};
const collectionObj = this.model.rawCollection();
const findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj);
const sort = {
livechatCount: 1,
username: 1,
};
const update = {
$inc: {
livechatCount: 1,
},
};
const user = findAndModify(query, sort, update);
if (user && user.value) {
return {
agentId: user.value._id,
username: user.value.username,
};
}
return null;
}
setLastRoutingTime(userId) {
const query = {
_id: userId,

@ -391,6 +391,8 @@
"assign-admin-role": "Assign Admin Role",
"assign-admin-role_description": "Permission to assign the admin role to other users",
"Assign_admin": "Assigning admin",
"Assign_new_conversations_to_bot_agent": "Assign new conversations to bot agent",
"Assign_new_conversations_to_bot_agent_description": "The routing system will attempt to find a bot agent before addressing new conversations to a human agent.",
"assign-roles": "Assign Roles",
"at": "at",
"At_least_one_added_token_is_required_by_the_user": "At least one added token is required by the user",

@ -368,6 +368,8 @@
"assign-admin-role": "Atribuir papel de administrador",
"assign-admin-role_description": "Permissão para atribuir a função de administrador a outros usuários",
"Assign_admin": "Atribuindo administrador",
"Assign_new_conversations_to_bot_agent": "Atribuir novas conversas para um agente bot",
"Assign_new_conversations_to_bot_agent_description": "O sistema de roteamento irá procurar por um agente bot antes de encaminhar novas conversas para um agente humano.",
"assign-roles": "Atribuir papéis",
"at": "em",
"At_least_one_added_token_is_required_by_the_user": "Pelo menos um token adicionado é requerido pelo usuário",

Loading…
Cancel
Save