From 9eb7977dd782b47b2d51e6017e86805b0cd02279 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:31:22 -0500 Subject: [PATCH] fix: `Waiting Queue` feature not queueing rooms (#34035) --- .changeset/stale-actors-enjoy.md | 5 + .../app/livechat/server/lib/QueueManager.ts | 18 ++- .../server/hooks/beforeRoutingChat.ts | 2 + ...hat-queue-management-autoselection.spec.ts | 118 ++++++++++++++++++ .../e2e/page-objects/omnichannel-livechat.ts | 4 + 5 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 .changeset/stale-actors-enjoy.md create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts diff --git a/.changeset/stale-actors-enjoy.md b/.changeset/stale-actors-enjoy.md new file mode 100644 index 000000000000..baff2b19b667 --- /dev/null +++ b/.changeset/stale-actors-enjoy.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes `waiting queue` feature. When `Livechat_waiting_queue` setting is enabled, incoming conversations should be sent to the queue instead of being assigned directly. diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index c6728d470870..95fa4605b72a 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -94,8 +94,7 @@ export class QueueManager { const inquiryAgent = await RoutingManager.delegateAgent(defaultAgent, inquiry); logger.debug(`Delegating inquiry with id ${inquiry._id} to agent ${defaultAgent?.username}`); - await callbacks.run('livechat.beforeRouteChat', inquiry, inquiryAgent); - const dbInquiry = await LivechatInquiry.findOneById(inquiry._id); + const dbInquiry = await callbacks.run('livechat.beforeRouteChat', inquiry, inquiryAgent); if (!dbInquiry) { throw new Error('inquiry-not-found'); @@ -122,6 +121,10 @@ export class QueueManager { return LivechatInquiryStatus.QUEUED; } + if (settings.get('Livechat_waiting_queue')) { + return LivechatInquiryStatus.QUEUED; + } + if (RoutingManager.getConfig()?.autoAssignAgent) { return LivechatInquiryStatus.READY; } @@ -135,6 +138,7 @@ export class QueueManager { static async queueInquiry(inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, defaultAgent?: SelectedAgent | null) { if (inquiry.status === 'ready') { + logger.debug({ msg: 'Inquiry is ready. Delegating', inquiry, defaultAgent }); return RoutingManager.delegateInquiry(inquiry, defaultAgent, undefined, room); } @@ -261,7 +265,11 @@ export class QueueManager { throw new Error('room-not-found'); } - if (!newRoom.servedBy && settings.get('Omnichannel_calculate_dispatch_service_queue_statistics')) { + if ( + !newRoom.servedBy && + settings.get('Livechat_waiting_queue') && + settings.get('Omnichannel_calculate_dispatch_service_queue_statistics') + ) { const [inq] = await LivechatInquiry.getCurrentSortedQueueAsync({ inquiryId: inquiry._id, department, @@ -329,6 +337,10 @@ export class QueueManager { } private static dispatchInquiryQueued = async (inquiry: ILivechatInquiryRecord, room: IOmnichannelRoom, agent?: SelectedAgent | null) => { + if (RoutingManager.getConfig()?.autoAssignAgent) { + return; + } + logger.debug(`Notifying agents of new inquiry ${inquiry._id} queued`); const { department, rid, v } = inquiry; diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts index a713255e20ba..8b3d37576880 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.ts @@ -63,6 +63,8 @@ callbacks.add( } await saveQueueInquiry(inquiry); + + return LivechatInquiry.findOneById(inquiry._id); }, callbacks.priority.HIGH, 'livechat-before-routing-chat', diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts new file mode 100644 index 000000000000..62bf3111cab7 --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-queue-management-autoselection.spec.ts @@ -0,0 +1,118 @@ +import { createFakeVisitor } from '../../mocks/data'; +import { IS_EE } from '../config/constants'; +import { createAuxContext } from '../fixtures/createAuxContext'; +import { Users } from '../fixtures/userStates'; +import { HomeOmnichannel, OmnichannelLiveChat } from '../page-objects'; +import { test, expect } from '../utils/test'; + +const firstVisitor = createFakeVisitor(); + +const secondVisitor = createFakeVisitor(); + +test.use({ storageState: Users.user1.state }); + +test.describe('OC - Livechat - Queue Management', () => { + test.skip(!IS_EE, 'Enterprise Only'); + + let poHomeOmnichannel: HomeOmnichannel; + let poLiveChat: OmnichannelLiveChat; + + const waitingQueueMessage = 'This is a message from Waiting Queue'; + + test.beforeAll(async ({ api, browser }) => { + await Promise.all([ + api.post('/settings/Livechat_Routing_Method', { value: 'Auto_Selection' }), + api.post('/settings/Livechat_accept_chats_with_no_agents', { value: true }), + api.post('/settings/Livechat_waiting_queue', { value: true }), + api.post('/settings/Livechat_waiting_queue_message', { value: waitingQueueMessage }), + api.post('/livechat/users/agent', { username: 'user1' }), + ]); + + const { page: omniPage } = await createAuxContext(browser, Users.user1, '/', true); + poHomeOmnichannel = new HomeOmnichannel(omniPage); + + // Agent will be offline for these tests + await poHomeOmnichannel.sidenav.switchOmnichannelStatus('offline'); + }); + + test.beforeEach(async ({ browser, api }) => { + const context = await browser.newContext(); + const page2 = await context.newPage(); + + poLiveChat = new OmnichannelLiveChat(page2, api); + await poLiveChat.page.goto('/livechat'); + }); + + test.afterAll(async ({ api }) => { + await Promise.all([ + api.post('/settings/Livechat_waiting_queue', { value: false }), + api.post('/settings/Livechat_waiting_queue_message', { value: '' }), + api.delete('/livechat/users/agent/user1'), + ]); + await poHomeOmnichannel.page.close(); + }); + + test.describe('OC - Queue Management - Auto Selection', () => { + let poLiveChat2: OmnichannelLiveChat; + + test.beforeEach(async ({ browser, api }) => { + const context = await browser.newContext(); + const page = await context.newPage(); + poLiveChat2 = new OmnichannelLiveChat(page, api); + await poLiveChat2.page.goto('/livechat'); + }); + + test.afterEach(async () => { + await poLiveChat2.closeChat(); + await poLiveChat2.page.close(); + await poLiveChat.closeChat(); + await poLiveChat.page.close(); + }); + + test('Update user position on Queue', async () => { + await test.step('should start livechat session', async () => { + await poLiveChat.openAnyLiveChatAndSendMessage({ + liveChatUser: firstVisitor, + message: 'Test message', + isOffline: false, + }); + }); + + await test.step('expect to receive Waiting Queue message on chat', async () => { + await expect(poLiveChat.page.locator(`div >> text=${waitingQueueMessage}`)).toBeVisible(); + }); + + await test.step('expect to be on spot #1', async () => { + await expect(poLiveChat.queuePosition(1)).toBeVisible(); + }); + + await test.step('should start secondary livechat session', async () => { + await poLiveChat2.openAnyLiveChatAndSendMessage({ + liveChatUser: secondVisitor, + message: 'Test message', + isOffline: false, + }); + }); + + await test.step('should start secondary livechat on spot #2', async () => { + await expect(poLiveChat2.queuePosition(2)).toBeVisible(); + }); + + await test.step('should start the queue by making the agent available again', async () => { + await poHomeOmnichannel.sidenav.switchOmnichannelStatus('online'); + }); + + await test.step('user1 should get assigned to the first chat', async () => { + await expect(poLiveChat.queuePosition(1)).not.toBeVisible(); + }); + + await test.step('secondary session should be on position #1', async () => { + await expect(poLiveChat2.queuePosition(1)).toBeVisible(); + }); + + await test.step('secondary session should be taken by user1', async () => { + await expect(poLiveChat2.queuePosition(1)).not.toBeVisible(); + }); + }); + }); +}); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts index e52ae45782c8..1548f390331a 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts @@ -220,4 +220,8 @@ export class OmnichannelLiveChat { await this.fileUploadTarget.dispatchEvent('drop', { dataTransfer }); } + + queuePosition(position: number): Locator { + return this.page.locator(`div[role='alert'] >> text=Your spot is #${position}`); + } }