Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/meteor/app/livechat/server/lib/RoutingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type Routing = {
agent?: SelectedAgent | null,
options?: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } },
room?: IOmnichannelRoom,
): Promise<(IOmnichannelRoom & { chatQueued?: boolean }) | null | void>;
): Promise<(IOmnichannelRoom & { chatQueued?: boolean }) | null | false>;
unassignAgent(
inquiry: ILivechatInquiryRecord,
departmentId?: string,
Expand All @@ -62,7 +62,7 @@ type Routing = {
agent: SelectedAgent | null,
options: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } },
room: IOmnichannelRoom,
): Promise<IOmnichannelRoom | null | void>;
): Promise<IOmnichannelRoom | false>;
transferRoom(room: IOmnichannelRoom, guest: ILivechatVisitor, transferData: TransferData): Promise<boolean>;
delegateAgent(agent: SelectedAgent | undefined, inquiry: ILivechatInquiryRecord): Promise<SelectedAgent | null | undefined>;
removeAllRoomSubscriptions(room: Pick<IOmnichannelRoom, '_id'>, ignoreUser?: { _id: string }): Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ const handleOnAgentAssignmentFailed = async (
},
) => {
if (!inquiry || !room) {
return;
return false;
}

if (!settings.get('Livechat_waiting_queue')) {
return;
return false;
}

const { forwardingToDepartment: { oldDepartmentId } = {}, forwardingToDepartment } = options;
if (!forwardingToDepartment) {
return;
return false;
}

const { department: newDepartmentId } = inquiry;

if (!newDepartmentId || !oldDepartmentId || newDepartmentId === oldDepartmentId) {
return;
return false;
}

return { ...room, chatQueued: true } as IOmnichannelRoom & { chatQueued: boolean };
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/server/lib/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ type ChainedCallbackSignatures = {
};
options: { forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any }; clientAction?: boolean };
},
) => Promise<(IOmnichannelRoom & { chatQueued: boolean }) | undefined>;
) => Promise<(IOmnichannelRoom & { chatQueued: boolean }) | false>;
'beforeGetMentions': (mentionIds: string[], teamMentions: MessageMention[]) => Promise<string[]>;
'livechat.manageDepartmentUnit': (params: { userId: string; departmentId: string; unitId?: string }) => void;
'afterRoomTopicChange': (
Expand Down
7 changes: 6 additions & 1 deletion apps/meteor/server/services/omnichannel/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,12 @@ export class OmnichannelQueue implements IOmnichannelQueue {

const room = await RoutingManager.delegateInquiry(inquiry, defaultAgent, undefined, roomFromDb);

if (room?.servedBy) {
if (!room) {
queueLogger.debug({ msg: 'RoutingManager failed to delegate inquiry', inquiry: inquiry._id, queue });
return false;
}

if (room.servedBy) {
const {
_id: rid,
servedBy: { _id: agentId },
Expand Down
121 changes: 121 additions & 0 deletions apps/meteor/tests/end-to-end/api/livechat/07-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getLivechatRoomInfo,
makeAgentAvailable,
updateDepartment,
startANewLivechatRoomAndTakeIt,
} from '../../../data/livechat/rooms';
import { createAnOnlineAgent, updateLivechatSettingsForUser } from '../../../data/livechat/users';
import { sleep } from '../../../data/livechat/utils';
Expand Down Expand Up @@ -644,6 +645,8 @@ describe('LIVECHAT - Queue', () => {
await makeAgentAvailable(credentials3);
await makeAgentAvailable(credentials4);

await updatePermission('transfer-livechat-guest', ['livechat-agent']);
Comment thread
KevLehman marked this conversation as resolved.

testUser = {
user,
credentials: credentials3,
Expand Down Expand Up @@ -881,4 +884,122 @@ describe('LIVECHAT - Queue', () => {
expect(roomInfo.servedBy).to.be.an('object');
expect(roomInfo.servedBy?._id).to.be.equal(testUser2.user._id);
});

describe('when forwarding a chat to an agent already at their limit', () => {
let forwardingRoom: { _id: string };
let otherRoom: { _id: string };
let visitor1: ILivechatVisitor;
let visitor2: ILivechatVisitor;
let forwardingDept: ILivechatDepartment;
let forwardUserA: { user: IUser; credentials: Credentials };
let forwardUserB: { user: IUser; credentials: Credentials };

before(async () => {
await updateSetting('Livechat_Routing_Method', 'Manual_Selection');

const userA = await createUser();
const userB = await createUser();

await createAgent(userA.username);
await createAgent(userB.username);

const credA = await login(userA.username, password);
const credB = await login(userB.username, password);

await makeAgentAvailable(credA);
await makeAgentAvailable(credB);

forwardUserA = { user: userA, credentials: credA };
forwardUserB = { user: userB, credentials: credB };

forwardingDept = await createDepartment(
[{ agentId: forwardUserA.user._id }, { agentId: forwardUserB.user._id }],
`${new Date().toISOString()}-forward-limit`,
true,
{
maxNumberSimultaneousChat: 1,
},
);

await updateLivechatSettingsForUser(forwardUserA.user._id, { maxNumberSimultaneousChat: 1 }, [forwardingDept._id]);
await updateLivechatSettingsForUser(forwardUserB.user._id, { maxNumberSimultaneousChat: 1 }, [forwardingDept._id]);

// Force agent A to take a room on the dedicated department
const { room: room1, visitor } = await startANewLivechatRoomAndTakeIt({
departmentId: forwardingDept._id,
agent: forwardUserA.credentials,
});
visitor1 = visitor;

const roomInfo1 = await getLivechatRoomInfo(room1._id);
expect(roomInfo1.servedBy).to.be.an('object');
expect(roomInfo1.servedBy?._id).to.be.equal(forwardUserA.user._id);
otherRoom = room1;
});

before(async () => {
// Force agent B to take another room on the same department
const { room: room2, visitor } = await startANewLivechatRoomAndTakeIt({
departmentId: forwardingDept!._id,
agent: forwardUserB.credentials,
});
visitor2 = visitor;

const roomInfo2 = await getLivechatRoomInfo(room2._id);
expect(roomInfo2.servedBy).to.be.an('object');
expect(roomInfo2.servedBy?._id).to.be.equal(forwardUserB.user._id);

forwardingRoom = room2;
});
Comment thread
KevLehman marked this conversation as resolved.

after(async () => {
await closeOmnichannelRoom(forwardingRoom._id);
await closeOmnichannelRoom(otherRoom._id);
await deleteDepartment(forwardingDept._id);
await deleteVisitor(visitor1._id);
await deleteVisitor(visitor2._id);
await deleteUser(forwardUserA.user);
await deleteUser(forwardUserB.user);
});

it('should not allow forwarding and should not add system messages to the room', async () => {
const res = await request.post(api('livechat/room.forward')).set(forwardUserB.credentials).send({
roomId: forwardingRoom._id,
userId: forwardUserA.user._id,
clientAction: true,
comment: 'forward to agent at limit',
});

expect(res.status).to.equal(400);
expect(res.body).to.have.property('success', false);

const messagesResponse = await request.get(api('channels.messages')).set(credentials).query({ roomId: forwardingRoom._id });

expect(messagesResponse.status).to.equal(200);
expect(messagesResponse.body).to.have.property('messages');
const systemMessages = messagesResponse.body.messages.filter((msg: any) => msg.t === 'livechat_transfer_history');
expect(systemMessages).to.have.length(0);
});

it('should allow forwarding with the waiting queue disabled', async () => {
await updateEESetting('Livechat_waiting_queue', false);

const res = await request.post(api('livechat/room.forward')).set(forwardUserB.credentials).send({
roomId: forwardingRoom._id,
userId: forwardUserA.user._id,
clientAction: true,
comment: 'forward to agent at limit with waiting queue disabled',
});

expect(res.status).to.equal(200);
expect(res.body).to.have.property('success', true);

const messagesResponse = await request.get(api('channels.messages')).set(credentials).query({ roomId: forwardingRoom._id });

expect(messagesResponse.status).to.equal(200);
expect(messagesResponse.body).to.have.property('messages');
const systemMessages = messagesResponse.body.messages.filter((msg: any) => msg.t === 'livechat_transfer_history');
expect(systemMessages).to.have.length.greaterThan(0);
});
});
});
Loading