diff --git a/.changeset/brown-houses-rush.md b/.changeset/brown-houses-rush.md new file mode 100644 index 0000000000000..67fcb02f95e42 --- /dev/null +++ b/.changeset/brown-houses-rush.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed a problem that caused Business Hours feature (Multiple) to make bot agents not available when turning on the feature, and not making them available after that. Now, Business Hours will ignore Bot users, allowing admins to decide manually if a bot should be or not be active during a period of time diff --git a/apps/meteor/server/models/raw/Users.js b/apps/meteor/server/models/raw/Users.js index 0d56fc76bccf8..a4b7bfe9a397a 100644 --- a/apps/meteor/server/models/raw/Users.js +++ b/apps/meteor/server/models/raw/Users.js @@ -1036,7 +1036,7 @@ export class UsersRaw extends BaseRaw { updateLivechatStatusBasedOnBusinessHours(userIds = []) { const query = { $or: [{ openBusinessHours: { $exists: false } }, { openBusinessHours: { $size: 0 } }], - roles: 'livechat-agent', + $and: [{ roles: 'livechat-agent' }, { roles: { $ne: 'bot' } }], // exclude deactivated users active: true, // Avoid unnecessary updates @@ -1075,10 +1075,18 @@ export class UsersRaw extends BaseRaw { async isAgentWithinBusinessHours(agentId) { const query = { _id: agentId, - openBusinessHours: { - $exists: true, - $not: { $size: 0 }, - }, + $or: [ + { + openBusinessHours: { + $exists: true, + $not: { $size: 0 }, + }, + }, + { + // Bots can ignore Business Hours and be always available + roles: 'bot', + }, + ], }; return (await this.col.countDocuments(query)) > 0; } diff --git a/apps/meteor/tests/data/livechat/department.ts b/apps/meteor/tests/data/livechat/department.ts index 8aba28addfcf7..3d18f9c394b99 100644 --- a/apps/meteor/tests/data/livechat/department.ts +++ b/apps/meteor/tests/data/livechat/department.ts @@ -57,15 +57,17 @@ new Promise((resolve, reject) => { }); }); -export const createDepartmentWithAnOnlineAgent = async (): Promise<{department: ILivechatDepartment, agent: { - credentials: IUserCredentialsHeader; +type OnlineAgent = { user: WithRequiredProperty; -}}> => { + credentials: IUserCredentialsHeader; +}; + +export const createDepartmentWithAnOnlineAgent = async (): Promise<{department: ILivechatDepartment, agent: OnlineAgent }> => { const { user, credentials } = await createAnOnlineAgent(); const department = await createDepartmentWithMethod() as ILivechatDepartment; - await addOrRemoveAgentFromDepartment(department._id, {agentId: user._id, username: user.username}, true); + await addOrRemoveAgentFromDepartment(department._id, { agentId: user._id, username: user.username }, true); return { department, @@ -76,6 +78,21 @@ export const createDepartmentWithAnOnlineAgent = async (): Promise<{department: }; }; +export const createDepartmentWithAgent = async (agent: OnlineAgent): Promise<{ department: ILivechatDepartment; agent: OnlineAgent }> => { + const { user, credentials } = agent; + const department = await createDepartmentWithMethod() as ILivechatDepartment; + + await addOrRemoveAgentFromDepartment(department._id, { agentId: user._id, username: user.username }, true); + + return { + department, + agent: { + credentials, + user, + } + }; +} + export const addOrRemoveAgentFromDepartment = async (departmentId: string, agent: { agentId: string; username: string; count?: number; order?: number }, add: boolean) => { const response = await request.post(api('livechat/department/' + departmentId + '/agents')).set(credentials).send({ ...add ? { upsert: [agent], remove: [] } : { remove: [agent], upsert: [] }, diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index b6527fbc2bb24..8b6dc224377f9 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -18,6 +18,7 @@ import { addOrRemoveAgentFromDepartment, archiveDepartment, createDepartmentWithAnOnlineAgent, + createDepartmentWithAgent, disableDepartment, getDepartmentById, deleteDepartment, @@ -321,6 +322,21 @@ describe('LIVECHAT - business hours', function () { expect(latestAgent.openBusinessHours).to.be.an('array').of.length(0); expect(latestAgent.statusLivechat).to.be.equal(ILivechatAgentStatus.NOT_AVAILABLE); }); + + it('should create a custom business hour which is closed by default, but a bot agent shouldnt be affected', async () => { + const bot = await createUser({ roles: ['bot', 'livechat-agent'] }); + const creds = await login(bot.username, password); + await makeAgentAvailable(creds); + + const { department } = await createDepartmentWithAgent({ user: bot, credentials: creds }); + + await createCustomBusinessHour([department._id], false); + + const latestAgent: ILivechatAgent = await getMe(creds); + expect(latestAgent).to.be.an('object'); + expect(latestAgent.openBusinessHours).to.be.an('array').of.length(0); + expect(latestAgent.statusLivechat).to.be.equal(ILivechatAgentStatus.AVAILABLE); + }); }); // Scenario: Assume we have a BH linked to a department, and we archive the department