Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions .changeset/few-dryers-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/model-typings": patch
"@rocket.chat/models": patch
---

Allows agents to set a default agent when the chat being transferred ends up in the queue
2 changes: 1 addition & 1 deletion apps/meteor/app/livechat/server/lib/Helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ export const forwardRoomToDepartment = async (room: IOmnichannelRoom, guest: ILi
isWaitingQueueEnabled,
});
await saveTransferHistory(room, transferData);
return RoutingManager.unassignAgent(inquiry, departmentId, true);
return RoutingManager.unassignAgent(inquiry, departmentId, true, agent);
}

// Fake the department to forward the inquiry - Case the forward process does not success
Expand Down
21 changes: 17 additions & 4 deletions apps/meteor/app/livechat/server/lib/RoutingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ type Routing = {
options?: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } },
room?: IOmnichannelRoom,
): Promise<(IOmnichannelRoom & { chatQueued?: boolean }) | null | void>;
unassignAgent(inquiry: ILivechatInquiryRecord, departmentId?: string, shouldQueue?: boolean): Promise<boolean>;
unassignAgent(
inquiry: ILivechatInquiryRecord,
departmentId?: string,
shouldQueue?: boolean,
agent?: SelectedAgent | null,
): Promise<boolean>;
takeInquiry(
inquiry: Omit<
ILivechatInquiryRecord,
Expand Down Expand Up @@ -157,11 +162,19 @@ export const RoutingManager: Routing = {
return { inquiry, user };
},

async unassignAgent(inquiry, departmentId, shouldQueue = false) {
async unassignAgent(inquiry, departmentId, shouldQueue = false, defaultAgent?: SelectedAgent | null) {
const { rid, department } = inquiry;
const room = await LivechatRooms.findOneById(rid);

logger.debug(`Removing assignations of inquiry ${inquiry._id}`);
logger.debug({
msg: 'Removing assignations of inquiry',
inquiryId: inquiry._id,
departmentId,
room: { _id: room?._id, open: room?.open, servedBy: room?.servedBy },
shouldQueue,
defaultAgent,
});

if (!room?.open) {
logger.debug(`Cannot unassign agent from inquiry ${inquiry._id}: Room already closed`);
return false;
Expand All @@ -187,7 +200,7 @@ export const RoutingManager: Routing = {
}

if (shouldQueue) {
const queuedInquiry = await LivechatInquiry.queueInquiry(inquiry._id, room.lastMessage);
const queuedInquiry = await LivechatInquiry.queueInquiry(inquiry._id, room.lastMessage, defaultAgent);
if (queuedInquiry) {
inquiry = queuedInquiry;
void notifyOnLivechatInquiryChanged(inquiry, 'updated', {
Expand Down
38 changes: 38 additions & 0 deletions apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,44 @@ describe('LIVECHAT - rooms', () => {
]);
});

(IS_EE ? it : it.skip)(
'when manager forwards to department & passes an agent on the request while waiting queue is active, the inquiry should be set to the queue with default agent',
async () => {
const { department: initialDepartment } = await createDepartmentWithAnOnlineAgent();
const { department: forwardToOfflineDepartment, agent: onlineAgent } = await createDepartmentWithAnOnlineAgent();
await updateSetting('Livechat_waiting_queue', 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);

await request.post(api('livechat/room.forward')).set(managerCredentials).send({
roomId: newRoom._id,
departmentId: forwardToOfflineDepartment._id,
userId: onlineAgent.user._id,
clientAction: true,
comment: 'test comment',
});

const inquiry = await fetchInquiry(newRoom._id);

expect(inquiry).to.have.property('status', 'queued');
expect(inquiry)
.to.have.property('defaultAgent')
.to.deep.equal({ agentId: onlineAgent.user._id, username: onlineAgent.user.username });

await Promise.all([
updateSetting('Livechat_waiting_queue', false),
deleteDepartment(initialDepartment._id),
deleteDepartment(forwardToOfflineDepartment._id),
closeOmnichannelRoom(newRoom._id),
]);
},
);

(IS_EE ? it : it.skip)(
'when manager forward to offline (agent away, accept when agent idle off) department the inquiry should be set to the queue',
async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/model-typings/src/models/ILivechatInquiryModel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IMessage, ILivechatInquiryRecord, LivechatInquiryStatus } from '@rocket.chat/core-typings';
import type { IMessage, ILivechatInquiryRecord, LivechatInquiryStatus, SelectedAgent } from '@rocket.chat/core-typings';
import type { FindOptions, Document, UpdateResult, DeleteResult, FindCursor, DeleteOptions, AggregateOptions } from 'mongodb';

import type { IBaseModel } from './IBaseModel';
Expand Down Expand Up @@ -33,7 +33,7 @@ export interface ILivechatInquiryModel extends IBaseModel<ILivechatInquiryRecord
getQueuedInquiries(options?: FindOptions<ILivechatInquiryRecord>): FindCursor<ILivechatInquiryRecord>;
takeInquiry(inquiryId: string): Promise<void>;
openInquiry(inquiryId: string): Promise<UpdateResult>;
queueInquiry(inquiryId: string, lastMessage?: IMessage): Promise<ILivechatInquiryRecord | null>;
queueInquiry(inquiryId: string, lastMessage?: IMessage, defaultAgent?: SelectedAgent | null): Promise<ILivechatInquiryRecord | null>;
queueInquiryAndRemoveDefaultAgent(inquiryId: string): Promise<UpdateResult>;
readyInquiry(inquiryId: string): Promise<UpdateResult>;
changeDepartmentIdByRoomId(rid: string, department: string): Promise<UpdateResult>;
Expand Down
15 changes: 13 additions & 2 deletions packages/models/src/models/LivechatInquiry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { ILivechatInquiryRecord, IMessage, RocketChatRecordDeleted, ILivechatPriority } from '@rocket.chat/core-typings';
import type {
ILivechatInquiryRecord,
IMessage,
RocketChatRecordDeleted,
ILivechatPriority,
SelectedAgent,
} from '@rocket.chat/core-typings';
import { LivechatInquiryStatus } from '@rocket.chat/core-typings';
import type { ILivechatInquiryModel } from '@rocket.chat/model-typings';
import type {
Expand Down Expand Up @@ -331,7 +337,11 @@ export class LivechatInquiryRaw extends BaseRaw<ILivechatInquiryRecord> implemen
);
}

async queueInquiry(inquiryId: string, lastMessage?: IMessage): Promise<ILivechatInquiryRecord | null> {
async queueInquiry(
inquiryId: string,
lastMessage?: IMessage,
defaultAgent?: SelectedAgent | null,
): Promise<ILivechatInquiryRecord | null> {
return this.findOneAndUpdate(
{
_id: inquiryId,
Expand All @@ -341,6 +351,7 @@ export class LivechatInquiryRaw extends BaseRaw<ILivechatInquiryRecord> implemen
status: LivechatInquiryStatus.QUEUED,
queuedAt: new Date(),
...(lastMessage && { lastMessage }),
...(defaultAgent && { defaultAgent }),
},
$unset: { takenAt: 1 },
},
Expand Down
Loading