From 8738e7a27f669911f69e721b09ef252ddb8f7fe0 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 2 Mar 2026 10:15:23 -0600 Subject: [PATCH 1/2] fix clientaction not being passed to takeinquiry call --- .../livechat/imports/server/rest/inquiries.ts | 2 +- .../tests/end-to-end/api/livechat/07-queue.ts | 410 ++++++++++++++++++ 2 files changed, 411 insertions(+), 1 deletion(-) diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts index a69604bd083ec..04af97752d22b 100644 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -69,7 +69,7 @@ API.v1.addRoute( return API.v1.failure('The user is invalid'); } return API.v1.success({ - inquiry: await takeInquiry(this.bodyParams.userId || this.userId, this.bodyParams.inquiryId), + inquiry: await takeInquiry(this.bodyParams.userId || this.userId, this.bodyParams.inquiryId, this.bodyParams.options), }); }, }, diff --git a/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts b/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts index 08724bab3305a..ffd0acb52e9da 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts @@ -20,6 +20,8 @@ import { makeAgentAvailable, updateDepartment, startANewLivechatRoomAndTakeIt, + fetchInquiry, + takeInquiry, } from '../../../data/livechat/rooms'; import { createAnOnlineAgent, updateLivechatSettingsForUser } from '../../../data/livechat/users'; import { sleep } from '../../../data/livechat/utils'; @@ -1069,3 +1071,411 @@ describe('LIVECHAT - Queue', () => { }); }); }); + +(IS_EE ? describe : describe.skip)('Livechat - Chat limits - Manual Selection', () => { + let manualUser: { user: IUser; credentials: Credentials }; + let manualDepartment: ILivechatDepartment; + let manualDepartment2: ILivechatDepartment; + const manualRoomsToClose: IOmnichannelRoom[] = []; + const manualVisitorsToDelete: ILivechatVisitor[] = []; + + before((done) => getCredentials(done)); + + before(async () => { + await Promise.all([ + updateSetting('Livechat_enabled', true), + updateSetting('Livechat_Routing_Method', 'Manual_Selection'), + updateSetting('Omnichannel_enable_department_removal', true), + updateEESetting('Livechat_maximum_chats_per_agent', 0), + updateEESetting('Livechat_waiting_queue', true), + ]); + + await sleep(1000); + }); + + before(async () => { + const user = await createUser(); + await createAgent(user.username); + const creds = await login(user.username, password); + await makeAgentAvailable(creds); + + manualUser = { user, credentials: creds }; + }); + + before(async () => { + manualDepartment = await createDepartment([{ agentId: manualUser.user._id }], `${new Date().toISOString()}-manual-dept`, true, { + maxNumberSimultaneousChat: 2, + }); + manualDepartment2 = await createDepartment([{ agentId: manualUser.user._id }], `${new Date().toISOString()}-manual-dept2`, true, { + maxNumberSimultaneousChat: 2, + }); + await updateLivechatSettingsForUser(manualUser.user._id, { maxNumberSimultaneousChat: 1 }, [ + manualDepartment._id, + manualDepartment2._id, + ]); + }); + + after(async () => { + await Promise.all(manualRoomsToClose.map((room) => closeOmnichannelRoom(room._id))); + await Promise.all(manualVisitorsToDelete.map((visitor) => deleteVisitor(visitor.token))); + await Promise.all([ + deleteUser(manualUser.user), + updateEESetting('Livechat_maximum_chats_per_agent', 0), + updateEESetting('Livechat_waiting_queue', false), + updateSetting('Livechat_Routing_Method', 'Auto_Selection'), + deleteDepartment(manualDepartment._id), + deleteDepartment(manualDepartment2._id), + ]); + await updateSetting('Omnichannel_enable_department_removal', false); + }); + + describe('when agent limit is 1 and has 0 chats', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should allow agent to manually take the inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + + describe('when agent limit is 1 and has 1 chat', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should not allow agent to manually take the inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when agent limit is increased to 2', () => { + before(async () => { + await updateLivechatSettingsForUser(manualUser.user._id, { maxNumberSimultaneousChat: 2 }, [ + manualDepartment._id, + manualDepartment2._id, + ]); + }); + + it('should allow agent to take the pending inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + }); + + describe('when agent limit is 2 and already has 2 chats on department A', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment2._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should not allow agent to take inquiry on department B', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when agent limit is increased to 3', () => { + before(async () => { + await updateLivechatSettingsForUser(manualUser.user._id, { maxNumberSimultaneousChat: 3 }, [ + manualDepartment._id, + manualDepartment2._id, + ]); + }); + + it('should allow agent to take the pending inquiry on department B', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + }); + + describe('when agent limit is 0 and department B limit is 2 (agent has 3 chats)', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + await updateLivechatSettingsForUser(manualUser.user._id, { maxNumberSimultaneousChat: 0 }, [ + manualDepartment._id, + manualDepartment2._id, + ]); + + visitor = await createVisitor(manualDepartment2._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should allow agent to take inquiry on department B', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + + describe('when agent has 4 chats and 2 on department B (at department limit)', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment2._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should not allow agent to take inquiry on department B', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when global limit is set to 6', () => { + before(async () => { + await updateEESetting('Livechat_maximum_chats_per_agent', 6); + }); + + it('should not allow agent to take inquiry on department B even if global limit allows it', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when department B limit is removed', () => { + before(async () => { + await updateDepartment({ + departmentId: manualDepartment2._id, + opts: { maxNumberSimultaneousChat: 0 }, + userCredentials: credentials, + }); + }); + + it('should allow agent to take the pending inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + }); + }); + + describe('when agent has 5 chats, global limit is 6, department limit is 0', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment2._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should allow agent to take inquiry on department B', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + + describe('when agent has 6 chats, global limit is 6, department limit is 0', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment2._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should not allow agent to take inquiry on department B', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when global limit is removed', () => { + before(async () => { + await updateEESetting('Livechat_maximum_chats_per_agent', 0); + }); + + it('should allow agent to take the pending inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + }); + + describe('when department A limit is still 2 (agent has 7 chats)', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + visitor = await createVisitor(manualDepartment._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should not allow agent to take inquiry on department A', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when department A limit is removed', () => { + before(async () => { + await updateDepartment({ + departmentId: manualDepartment._id, + opts: { maxNumberSimultaneousChat: 0 }, + userCredentials: credentials, + }); + }); + + it('should allow agent to take the pending inquiry on department A', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + }); + + describe('when agent limit is set to 4 and global limit is high (agent has 8 chats)', () => { + let room: IOmnichannelRoom; + let visitor: ILivechatVisitor; + + before(async () => { + await updateEESetting('Livechat_maximum_chats_per_agent', 100000); + await updateLivechatSettingsForUser(manualUser.user._id, { maxNumberSimultaneousChat: 4 }, [ + manualDepartment._id, + manualDepartment2._id, + ]); + + visitor = await createVisitor(manualDepartment._id); + room = await createLivechatRoom(visitor.token); + manualVisitorsToDelete.push(visitor); + manualRoomsToClose.push(room); + }); + + it('should honor agent limit over global limit and not allow taking inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + + await request + .post(api('livechat/inquiries.take')) + .set(manualUser.credentials) + .send({ userId: manualUser.user._id, inquiryId: inquiry._id, options: { clientAction: true } }) + .expect(400); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.undefined; + }); + + describe('when agent limit is removed', () => { + before(async () => { + await updateLivechatSettingsForUser(manualUser.user._id, { maxNumberSimultaneousChat: 0 }, [ + manualDepartment._id, + manualDepartment2._id, + ]); + }); + + it('should allow agent to take the pending inquiry', async () => { + const inquiry = await fetchInquiry(room._id); + await takeInquiry(inquiry._id, manualUser.credentials); + + const roomInfo = await getLivechatRoomInfo(room._id); + expect(roomInfo.servedBy).to.be.an('object'); + expect(roomInfo.servedBy?._id).to.be.equal(manualUser.user._id); + }); + }); + }); +}); From 8c577b95bc9420f7fefcd2cf06ec5ffecfd1b216 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 2 Mar 2026 10:53:43 -0600 Subject: [PATCH 2/2] Create tame-dolphins-draw.md --- .changeset/tame-dolphins-draw.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tame-dolphins-draw.md diff --git a/.changeset/tame-dolphins-draw.md b/.changeset/tame-dolphins-draw.md new file mode 100644 index 0000000000000..f42810fac68ce --- /dev/null +++ b/.changeset/tame-dolphins-draw.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes `inquiries.take` not failing when attempting to take a chat while over chat limits