Skip to content

Commit b25f05a

Browse files
authored
feat: Send to queue while supporting default agent (RocketChat#36617)
1 parent 83eeed0 commit b25f05a

6 files changed

Lines changed: 78 additions & 9 deletions

File tree

.changeset/few-dryers-repeat.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@rocket.chat/meteor": patch
3+
"@rocket.chat/model-typings": patch
4+
"@rocket.chat/models": patch
5+
---
6+
7+
Allows agents to set a default agent when the chat being transferred ends up in the queue

apps/meteor/app/livechat/server/lib/Helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ export const forwardRoomToDepartment = async (room: IOmnichannelRoom, guest: ILi
657657
isWaitingQueueEnabled,
658658
});
659659
await saveTransferHistory(room, transferData);
660-
return RoutingManager.unassignAgent(inquiry, departmentId, true);
660+
return RoutingManager.unassignAgent(inquiry, departmentId, true, agent);
661661
}
662662

663663
// Fake the department to forward the inquiry - Case the forward process does not success

apps/meteor/app/livechat/server/lib/RoutingManager.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ type Routing = {
4848
options?: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } },
4949
room?: IOmnichannelRoom,
5050
): Promise<(IOmnichannelRoom & { chatQueued?: boolean }) | null | void>;
51-
unassignAgent(inquiry: ILivechatInquiryRecord, departmentId?: string, shouldQueue?: boolean): Promise<boolean>;
51+
unassignAgent(
52+
inquiry: ILivechatInquiryRecord,
53+
departmentId?: string,
54+
shouldQueue?: boolean,
55+
agent?: SelectedAgent | null,
56+
): Promise<boolean>;
5257
takeInquiry(
5358
inquiry: Omit<
5459
ILivechatInquiryRecord,
@@ -157,11 +162,19 @@ export const RoutingManager: Routing = {
157162
return { inquiry, user };
158163
},
159164

160-
async unassignAgent(inquiry, departmentId, shouldQueue = false) {
165+
async unassignAgent(inquiry, departmentId, shouldQueue = false, defaultAgent?: SelectedAgent | null) {
161166
const { rid, department } = inquiry;
162167
const room = await LivechatRooms.findOneById(rid);
163168

164-
logger.debug(`Removing assignations of inquiry ${inquiry._id}`);
169+
logger.debug({
170+
msg: 'Removing assignations of inquiry',
171+
inquiryId: inquiry._id,
172+
departmentId,
173+
room: { _id: room?._id, open: room?.open, servedBy: room?.servedBy },
174+
shouldQueue,
175+
defaultAgent,
176+
});
177+
165178
if (!room?.open) {
166179
logger.debug(`Cannot unassign agent from inquiry ${inquiry._id}: Room already closed`);
167180
return false;
@@ -187,7 +200,7 @@ export const RoutingManager: Routing = {
187200
}
188201

189202
if (shouldQueue) {
190-
const queuedInquiry = await LivechatInquiry.queueInquiry(inquiry._id, room.lastMessage);
203+
const queuedInquiry = await LivechatInquiry.queueInquiry(inquiry._id, room.lastMessage, defaultAgent);
191204
if (queuedInquiry) {
192205
inquiry = queuedInquiry;
193206
void notifyOnLivechatInquiryChanged(inquiry, 'updated', {

apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,44 @@ describe('LIVECHAT - rooms', () => {
12781278
]);
12791279
});
12801280

1281+
(IS_EE ? it : it.skip)(
1282+
'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',
1283+
async () => {
1284+
const { department: initialDepartment } = await createDepartmentWithAnOnlineAgent();
1285+
const { department: forwardToOfflineDepartment, agent: onlineAgent } = await createDepartmentWithAnOnlineAgent();
1286+
await updateSetting('Livechat_waiting_queue', true);
1287+
1288+
const newVisitor = await createVisitor(initialDepartment._id);
1289+
const newRoom = await createLivechatRoom(newVisitor.token);
1290+
1291+
const manager = await createUser();
1292+
const managerCredentials = await login(manager.username, password);
1293+
await createManager(manager.username);
1294+
1295+
await request.post(api('livechat/room.forward')).set(managerCredentials).send({
1296+
roomId: newRoom._id,
1297+
departmentId: forwardToOfflineDepartment._id,
1298+
userId: onlineAgent.user._id,
1299+
clientAction: true,
1300+
comment: 'test comment',
1301+
});
1302+
1303+
const inquiry = await fetchInquiry(newRoom._id);
1304+
1305+
expect(inquiry).to.have.property('status', 'queued');
1306+
expect(inquiry)
1307+
.to.have.property('defaultAgent')
1308+
.to.deep.equal({ agentId: onlineAgent.user._id, username: onlineAgent.user.username });
1309+
1310+
await Promise.all([
1311+
updateSetting('Livechat_waiting_queue', false),
1312+
deleteDepartment(initialDepartment._id),
1313+
deleteDepartment(forwardToOfflineDepartment._id),
1314+
closeOmnichannelRoom(newRoom._id),
1315+
]);
1316+
},
1317+
);
1318+
12811319
(IS_EE ? it : it.skip)(
12821320
'when manager forward to offline (agent away, accept when agent idle off) department the inquiry should be set to the queue',
12831321
async () => {

packages/model-typings/src/models/ILivechatInquiryModel.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IMessage, ILivechatInquiryRecord, LivechatInquiryStatus } from '@rocket.chat/core-typings';
1+
import type { IMessage, ILivechatInquiryRecord, LivechatInquiryStatus, SelectedAgent } from '@rocket.chat/core-typings';
22
import type { FindOptions, Document, UpdateResult, DeleteResult, FindCursor, DeleteOptions, AggregateOptions } from 'mongodb';
33

44
import type { IBaseModel } from './IBaseModel';
@@ -33,7 +33,7 @@ export interface ILivechatInquiryModel extends IBaseModel<ILivechatInquiryRecord
3333
getQueuedInquiries(options?: FindOptions<ILivechatInquiryRecord>): FindCursor<ILivechatInquiryRecord>;
3434
takeInquiry(inquiryId: string): Promise<void>;
3535
openInquiry(inquiryId: string): Promise<UpdateResult>;
36-
queueInquiry(inquiryId: string, lastMessage?: IMessage): Promise<ILivechatInquiryRecord | null>;
36+
queueInquiry(inquiryId: string, lastMessage?: IMessage, defaultAgent?: SelectedAgent | null): Promise<ILivechatInquiryRecord | null>;
3737
queueInquiryAndRemoveDefaultAgent(inquiryId: string): Promise<UpdateResult>;
3838
readyInquiry(inquiryId: string): Promise<UpdateResult>;
3939
changeDepartmentIdByRoomId(rid: string, department: string): Promise<UpdateResult>;

packages/models/src/models/LivechatInquiry.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import type { ILivechatInquiryRecord, IMessage, RocketChatRecordDeleted, ILivechatPriority } from '@rocket.chat/core-typings';
1+
import type {
2+
ILivechatInquiryRecord,
3+
IMessage,
4+
RocketChatRecordDeleted,
5+
ILivechatPriority,
6+
SelectedAgent,
7+
} from '@rocket.chat/core-typings';
28
import { LivechatInquiryStatus } from '@rocket.chat/core-typings';
39
import type { ILivechatInquiryModel } from '@rocket.chat/model-typings';
410
import type {
@@ -331,7 +337,11 @@ export class LivechatInquiryRaw extends BaseRaw<ILivechatInquiryRecord> implemen
331337
);
332338
}
333339

334-
async queueInquiry(inquiryId: string, lastMessage?: IMessage): Promise<ILivechatInquiryRecord | null> {
340+
async queueInquiry(
341+
inquiryId: string,
342+
lastMessage?: IMessage,
343+
defaultAgent?: SelectedAgent | null,
344+
): Promise<ILivechatInquiryRecord | null> {
335345
return this.findOneAndUpdate(
336346
{
337347
_id: inquiryId,
@@ -341,6 +351,7 @@ export class LivechatInquiryRaw extends BaseRaw<ILivechatInquiryRecord> implemen
341351
status: LivechatInquiryStatus.QUEUED,
342352
queuedAt: new Date(),
343353
...(lastMessage && { lastMessage }),
354+
...(defaultAgent && { defaultAgent }),
344355
},
345356
$unset: { takenAt: 1 },
346357
},

0 commit comments

Comments
 (0)