diff --git a/.changeset/fluffy-cougars-trade.md b/.changeset/fluffy-cougars-trade.md new file mode 100644 index 0000000000000..843e312ac18af --- /dev/null +++ b/.changeset/fluffy-cougars-trade.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes a behavior when transferring a room to another department that was not considering the `waiting queue` setting and attempted to route the chat to an agent instead of leaving it on the department's queue diff --git a/apps/meteor/app/livechat/server/lib/Helper.ts b/apps/meteor/app/livechat/server/lib/Helper.ts index 8974c3dcd3655..0178f7a4e18f7 100644 --- a/apps/meteor/app/livechat/server/lib/Helper.ts +++ b/apps/meteor/app/livechat/server/lib/Helper.ts @@ -635,12 +635,27 @@ export const forwardRoomToDepartment = async (room: IOmnichannelRoom, guest: ILi }, }); + // Cases: + // 1. Routing is manual + // 2. Server is out of macs + // 3. Department allows to forward when offline and department is offline + // 4. Department is online && waiting queue is enabled + const onlineAgents = await checkOnlineAgents(departmentId); + const isWaitingQueueEnabled = settings.get('Livechat_waiting_queue'); if ( !RoutingManager.getConfig()?.autoAssignAgent || !(await Omnichannel.isWithinMACLimit(room)) || - (department?.allowReceiveForwardOffline && !(await checkOnlineAgents(departmentId))) + (department?.allowReceiveForwardOffline && !onlineAgents) || + (isWaitingQueueEnabled && onlineAgents) ) { - logger.debug(`Room ${room._id} will be on department queue`); + logger.debug({ + msg: 'Room will be on department queue', + roomId: room._id, + departmentId, + departmentAllowOffline: department?.allowReceiveForwardOffline, + areAgentsOnline: onlineAgents, + isWaitingQueueEnabled, + }); await saveTransferHistory(room, transferData); return RoutingManager.unassignAgent(inquiry, departmentId, true); } diff --git a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts index 1a49ab5bf33be..d5ec44278abd9 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts @@ -1248,6 +1248,178 @@ describe('LIVECHAT - rooms', () => { }, ); + (IS_EE ? it : it.skip)( + 'when manager forwards a chat that hasnt been assigned to a user to another department with no online agents, chat should end ready in department (not queued)', + async () => { + await updateSetting('Livechat_accept_chats_with_no_agents', true); + await updateSetting('Livechat_Routing_Method', 'Auto_Selection'); + const { department: initialDepartment } = await createDepartmentWithAnOfflineAgent({}); + const { department: forwardToOfflineDepartment } = await createDepartmentWithAnOfflineAgent({}); + + const newVisitor = await createVisitor(initialDepartment._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + const manager = await createUser(); + const managerCredentials = await login(manager.username, password); + await createManager(manager.username); + + await request.post(api('livechat/room.forward')).set(managerCredentials).send({ + roomId: newRoom._id, + departmentId: forwardToOfflineDepartment._id, + clientAction: true, + comment: 'test comment', + }); + + const inquiry = await fetchInquiry(newRoom._id); + + // Inquiry status doesn't change, it was ready when created, it keeps ready after forwarding as no assignment was done + expect(inquiry.status).to.equal('ready'); + expect(inquiry.department).to.equal(forwardToOfflineDepartment._id); + + await Promise.all([deleteDepartment(initialDepartment._id), deleteDepartment(forwardToOfflineDepartment._id)]); + }, + ); + + (IS_EE ? it : it.skip)( + 'when manager forwards a chat that hasnt been assigned to a user to another department with no online agents when waiting queue is active, chat should end queued in department', + async () => { + await updateSetting('Livechat_Routing_Method', 'Auto_Selection'); + await updateSetting('Livechat_waiting_queue', true); + const { department: initialDepartment } = await createDepartmentWithAnOfflineAgent({}); + const { department: forwardToOfflineDepartment } = await createDepartmentWithAnOfflineAgent({}); + + const newVisitor = await createVisitor(initialDepartment._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + const manager = await createUser(); + const managerCredentials = await login(manager.username, password); + await createManager(manager.username); + + expect(newRoom.servedBy).to.be.undefined; + await request.post(api('livechat/room.forward')).set(managerCredentials).send({ + roomId: newRoom._id, + departmentId: forwardToOfflineDepartment._id, + clientAction: true, + comment: 'test comment', + }); + + const inquiry = await fetchInquiry(newRoom._id); + + expect(inquiry.status).to.equal('queued'); + expect(inquiry.department).to.equal(forwardToOfflineDepartment._id); + + await Promise.all([ + deleteDepartment(initialDepartment._id), + deleteDepartment(forwardToOfflineDepartment._id), + updateSetting('Livechat_waiting_queue', true), + updateSetting('Livechat_accept_chats_with_no_agents', false), + ]); + }, + ); + + (IS_EE ? it : it.skip)( + 'when manager forward to a department while waiting_queue is active and allowReceiveForwardOffline is true, chat should end in departments queue', + async () => { + await updateSetting('Livechat_Routing_Method', 'Auto_Selection'); + const { department: initialDepartment } = await createDepartmentWithAnOnlineAgent(); + const { department: forwardToOfflineDepartment } = await createDepartmentWithAnAwayAgent({ allowReceiveForwardOffline: true }); + + const newVisitor = await createVisitor(initialDepartment._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + const manager = await createUser(); + const managerCredentials = await login(manager.username, password); + await createManager(manager.username); + + // Waiting queue enabled after assignement but before transfer, otherwise, chat will fall on previous test case + await updateSetting('Livechat_waiting_queue', true); + await request.post(api('livechat/room.forward')).set(managerCredentials).send({ + roomId: newRoom._id, + departmentId: forwardToOfflineDepartment._id, + clientAction: true, + comment: 'test comment', + }); + + const inquiry = await fetchInquiry(newRoom._id); + + expect(inquiry.status).to.equal('queued'); + expect(inquiry.department).to.equal(forwardToOfflineDepartment._id); + + await Promise.all([ + deleteDepartment(initialDepartment._id), + deleteDepartment(forwardToOfflineDepartment._id), + updateSetting('Livechat_waiting_queue', false), + ]); + }, + ); + + (IS_EE ? it : it.skip)( + 'when manager forward to a department while waiting_queue is active and allowReceiveForwardOffline is false, transfer should fail', + async () => { + await updateSetting('Livechat_Routing_Method', 'Auto_Selection'); + const { department: initialDepartment } = await createDepartmentWithAnOnlineAgent(); + const { department: forwardToOfflineDepartment } = await createDepartmentWithAnAwayAgent({ allowReceiveForwardOffline: false }); + + const newVisitor = await createVisitor(initialDepartment._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + const manager = await createUser(); + const managerCredentials = await login(manager.username, password); + await createManager(manager.username); + + // Waiting queue enabled after assignement but before transfer, otherwise, chat will fall on previous test case + await updateSetting('Livechat_waiting_queue', true); + const res = await request.post(api('livechat/room.forward')).set(managerCredentials).send({ + roomId: newRoom._id, + departmentId: forwardToOfflineDepartment._id, + clientAction: true, + comment: 'test comment', + }); + + expect(res.status).to.equal(400); + expect(res.body).to.have.property('error', 'error-no-agents-online-in-department'); + + await Promise.all([ + deleteDepartment(initialDepartment._id), + deleteDepartment(forwardToOfflineDepartment._id), + updateSetting('Livechat_waiting_queue', false), + ]); + }, + ); + + (IS_EE ? it : it.skip)( + 'when manager forward to a department while waiting_queue is disabled and allowReceiveForwardOffline is false, but department is online, transfer should succeed', + async () => { + await updateSetting('Livechat_Routing_Method', 'Auto_Selection'); + const { department: initialDepartment } = await createDepartmentWithAnOnlineAgent(); + const { department: targetDepartment } = await createDepartmentWithAnOnlineAgent(); + + const newVisitor = await createVisitor(initialDepartment._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + const manager = await createUser(); + const managerCredentials = await login(manager.username, password); + await createManager(manager.username); + + expect(newRoom).to.have.property('servedBy'); + const res = await request.post(api('livechat/room.forward')).set(managerCredentials).send({ + roomId: newRoom._id, + departmentId: targetDepartment._id, + clientAction: true, + comment: 'test comment', + }); + + expect(res.status).to.equal(200); + + const inquiry = await fetchInquiry(newRoom._id); + + expect(inquiry).to.have.property('department', targetDepartment._id); + expect(inquiry).to.have.property('status', 'taken'); + + await Promise.all([deleteDepartment(initialDepartment._id), deleteDepartment(targetDepartment._id)]); + }, + ); + (IS_EE ? it : it.skip)( 'when manager forward to online (agent away, accept when agent idle on) department the inquiry should not be set to the queue', async () => { @@ -1285,6 +1457,45 @@ describe('LIVECHAT - rooms', () => { }, ); + (IS_EE ? it : it.skip)( + 'when manager forward to a department while waiting_queue is enabled, but department is online, transfer should succeed but it should end queued on target', + async () => { + await updateSetting('Livechat_Routing_Method', 'Auto_Selection'); + const { department: initialDepartment } = await createDepartmentWithAnOnlineAgent(); + const { department: targetDepartment } = await createDepartmentWithAnOnlineAgent(); + + const newVisitor = await createVisitor(initialDepartment._id); + const newRoom = await createLivechatRoom(newVisitor.token); + + const manager = await createUser(); + const managerCredentials = await login(manager.username, password); + await createManager(manager.username); + + expect(newRoom).to.have.property('servedBy'); + + await updateSetting('Livechat_waiting_queue', true); + const res = await request.post(api('livechat/room.forward')).set(managerCredentials).send({ + roomId: newRoom._id, + departmentId: targetDepartment._id, + clientAction: true, + comment: 'test comment', + }); + + expect(res.status).to.equal(200); + + const inquiry = await fetchInquiry(newRoom._id); + + expect(inquiry).to.have.property('department', targetDepartment._id); + expect(inquiry).to.have.property('status', 'queued'); + + await Promise.all([ + deleteDepartment(initialDepartment._id), + deleteDepartment(targetDepartment._id), + updateSetting('Livechat_waiting_queue', false), + ]); + }, + ); + (IS_EE ? it : it.skip)( 'should update inquiry last message when manager forward to offline department and the inquiry returns to queued', async () => {