diff --git a/apps/meteor/app/livechat/server/lib/Helper.ts b/apps/meteor/app/livechat/server/lib/Helper.ts index 453869d4425a..a565b05e8622 100644 --- a/apps/meteor/app/livechat/server/lib/Helper.ts +++ b/apps/meteor/app/livechat/server/lib/Helper.ts @@ -435,9 +435,14 @@ export const forwardRoomToAgent = async (room: IOmnichannelRoom, transferData: T // There are some Enterprise features that may interrupt the forwarding process // Due to that we need to check whether the agent has been changed or not logger.debug(`Forwarding inquiry ${inquiry._id} to agent ${agent.agentId}`); - const roomTaken = await RoutingManager.takeInquiry(inquiry, agent, { - ...(clientAction && { clientAction }), - }); + const roomTaken = await RoutingManager.takeInquiry( + inquiry, + agent, + { + ...(clientAction && { clientAction }), + }, + room, + ); if (!roomTaken) { logger.debug(`Cannot forward inquiry ${inquiry._id}`); return false; @@ -562,10 +567,15 @@ export const forwardRoomToDepartment = async (room: IOmnichannelRoom, guest: ILi // Fake the department to forward the inquiry - Case the forward process does not success // the inquiry will stay in the same original department inquiry.department = departmentId; - const roomTaken = await RoutingManager.delegateInquiry(inquiry, agent, { - forwardingToDepartment: { oldDepartmentId }, - ...(clientAction && { clientAction }), - }); + const roomTaken = await RoutingManager.delegateInquiry( + inquiry, + agent, + { + forwardingToDepartment: { oldDepartmentId }, + ...(clientAction && { clientAction }), + }, + room, + ); if (!roomTaken) { logger.debug(`Cannot forward room ${room._id}. Unable to delegate inquiry`); return false; diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.ts b/apps/meteor/app/livechat/server/lib/QueueManager.ts index 8be71aa4c991..1592b208ddeb 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.ts +++ b/apps/meteor/app/livechat/server/lib/QueueManager.ts @@ -38,7 +38,7 @@ export const queueInquiry = async (inquiry: ILivechatInquiryRecord, defaultAgent if (dbInquiry.status === 'ready') { logger.debug(`Inquiry with id ${inquiry._id} is ready. Delegating to agent ${inquiryAgent?.username}`); - return RoutingManager.delegateInquiry(dbInquiry, inquiryAgent); + return RoutingManager.delegateInquiry(dbInquiry, inquiryAgent, undefined, room); } }; diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.ts b/apps/meteor/app/livechat/server/lib/RoutingManager.ts index 288f8875a714..7841fd1be0e2 100644 --- a/apps/meteor/app/livechat/server/lib/RoutingManager.ts +++ b/apps/meteor/app/livechat/server/lib/RoutingManager.ts @@ -44,8 +44,8 @@ type Routing = { inquiry: InquiryWithAgentInfo, agent?: SelectedAgent | null, options?: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } }, + room?: IOmnichannelRoom, ): Promise<(IOmnichannelRoom & { chatQueued?: boolean }) | null | void>; - assignAgent(inquiry: InquiryWithAgentInfo, agent: SelectedAgent): Promise; unassignAgent(inquiry: ILivechatInquiryRecord, departmentId?: string, shouldQueue?: boolean): Promise; takeInquiry( inquiry: Omit< @@ -53,11 +53,14 @@ type Routing = { 'estimatedInactivityCloseTimeAt' | 'message' | 't' | 'source' | 'estimatedWaitingTimeQueue' | 'priorityWeight' | '_updatedAt' >, agent: SelectedAgent | null, - options?: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } }, + options: { clientAction?: boolean; forwardingToDepartment?: { oldDepartmentId?: string; transferData?: any } }, + room: IOmnichannelRoom, ): Promise; transferRoom(room: IOmnichannelRoom, guest: ILivechatVisitor, transferData: TransferData): Promise; delegateAgent(agent: SelectedAgent | undefined, inquiry: ILivechatInquiryRecord): Promise; removeAllRoomSubscriptions(room: Pick, ignoreUser?: { _id: string }): Promise; + + assignAgent(inquiry: InquiryWithAgentInfo, room: IOmnichannelRoom, agent: SelectedAgent): Promise; }; export const RoutingManager: Routing = { @@ -99,7 +102,7 @@ export const RoutingManager: Routing = { return this.getMethod().getNextAgent(department, ignoreAgentId); }, - async delegateInquiry(inquiry, agent, options = {}) { + async delegateInquiry(inquiry, agent, options = {}, room) { const { department, rid } = inquiry; logger.debug(`Attempting to delegate inquiry ${inquiry._id}`); if (!agent || (agent.username && !(await Users.findOneOnlineAgentByUserList(agent.username)) && !(await allowAgentSkipQueue(agent)))) { @@ -115,11 +118,15 @@ export const RoutingManager: Routing = { return LivechatRooms.findOneById(rid); } + if (!room) { + throw new Meteor.Error('error-invalid-room'); + } + logger.debug(`Inquiry ${inquiry._id} will be taken by agent ${agent.agentId}`); - return this.takeInquiry(inquiry, agent, options); + return this.takeInquiry(inquiry, agent, options, room); }, - async assignAgent(inquiry, agent) { + async assignAgent(inquiry: InquiryWithAgentInfo, room: IOmnichannelRoom, agent: SelectedAgent): Promise { check( agent, Match.ObjectIncluding({ @@ -140,19 +147,14 @@ export const RoutingManager: Routing = { await Rooms.incUsersCountById(rid, 1); const user = await Users.findOneById(agent.agentId); - const room = await LivechatRooms.findOneById(rid); if (user) { await Promise.all([Message.saveSystemMessage('command', rid, 'connected', user), Message.saveSystemMessage('uj', rid, '', user)]); } - if (!room) { - logger.debug(`Cannot assign agent to inquiry ${inquiry._id}: Room not found`); - throw new Meteor.Error('error-room-not-found', 'Room not found'); - } - await dispatchAgentDelegated(rid, agent.agentId); - logger.debug(`Agent ${agent.agentId} assigned to inquriy ${inquiry._id}. Instances notified`); + + logger.debug(`Agent ${agent.agentId} assigned to inquiry ${inquiry._id}. Instances notified`); void Apps.self?.getBridges()?.getListenerBridge().livechatEvent(AppEvents.IPostLivechatAgentAssigned, { room, user }); return inquiry; @@ -195,7 +197,7 @@ export const RoutingManager: Routing = { return true; }, - async takeInquiry(inquiry, agent, options = { clientAction: false }) { + async takeInquiry(inquiry, agent, options = { clientAction: false }, room) { check( agent, Match.ObjectIncluding({ @@ -216,7 +218,6 @@ export const RoutingManager: Routing = { logger.debug(`Attempting to take Inquiry ${inquiry._id} [Agent ${agent.agentId}] `); const { _id, rid } = inquiry; - const room = await LivechatRooms.findOneById(rid); if (!room?.open) { logger.debug(`Cannot take Inquiry ${inquiry._id}: Room is closed`); return room; @@ -250,13 +251,13 @@ export const RoutingManager: Routing = { } await LivechatInquiry.takeInquiry(_id); - const inq = await this.assignAgent(inquiry as InquiryWithAgentInfo, agent); + logger.info(`Inquiry ${inquiry._id} taken by agent ${agent.agentId}`); callbacks.runAsync( 'livechat.afterTakeInquiry', { - inquiry: inq, + inquiry: await this.assignAgent(inquiry as InquiryWithAgentInfo, room, agent), room, }, agent, diff --git a/apps/meteor/app/livechat/server/methods/takeInquiry.ts b/apps/meteor/app/livechat/server/methods/takeInquiry.ts index 3433b4a33ae8..30a5dabb5717 100644 --- a/apps/meteor/app/livechat/server/methods/takeInquiry.ts +++ b/apps/meteor/app/livechat/server/methods/takeInquiry.ts @@ -60,7 +60,7 @@ export const takeInquiry = async ( }; try { - await RoutingManager.takeInquiry(inquiry, agent, options); + await RoutingManager.takeInquiry(inquiry, agent, options ?? {}, room); } catch (e: any) { throw new Meteor.Error(e.message); } diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts index 65a7c8facc70..2af34aabf879 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts @@ -86,10 +86,6 @@ settings.watch('Livechat_auto_transfer_chat_timeout', (value) => { return; } - if (!autoTransferTimeout || autoTransferTimeout <= 0) { - return inquiry; - } - // const room = await LivechatRooms.findOneById(rid, { projection: { _id: 1, autoTransferredAt: 1, autoTransferOngoing: 1 } }); // if (!room) { // return inquiry; diff --git a/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts b/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts index c3e6d434cf7f..d708f8941269 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts @@ -73,7 +73,7 @@ Meteor.methods({ const { servedBy: { _id: agentId, username }, } = room; - await RoutingManager.takeInquiry(inquiry, { agentId, username }, options); + await RoutingManager.takeInquiry(inquiry, { agentId, username }, options, room); const onHoldChatResumedBy = options.clientAction ? await Meteor.userAsync() : await Users.findOneById('rocket.cat'); if (!onHoldChatResumedBy) { diff --git a/apps/meteor/server/models/raw/LivechatRooms.ts b/apps/meteor/server/models/raw/LivechatRooms.ts index c85b633dd677..8469b397fd17 100644 --- a/apps/meteor/server/models/raw/LivechatRooms.ts +++ b/apps/meteor/server/models/raw/LivechatRooms.ts @@ -2296,15 +2296,11 @@ export class LivechatRoomsRaw extends BaseRaw implements ILive servedBy: { _id: newAgent.agentId, username: newAgent.username, - ts: new Date(), + ts: newAgent.ts ?? new Date(), }, }, }; - if (newAgent.ts) { - update.$set.servedBy.ts = newAgent.ts; - } - return this.updateOne(query, update); } diff --git a/apps/meteor/server/services/omnichannel/queue.ts b/apps/meteor/server/services/omnichannel/queue.ts index 642575c06db5..00197e6000b8 100644 --- a/apps/meteor/server/services/omnichannel/queue.ts +++ b/apps/meteor/server/services/omnichannel/queue.ts @@ -1,4 +1,3 @@ -import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; import { type InquiryWithAgentInfo, type IOmnichannelQueue } from '@rocket.chat/core-typings'; import { License } from '@rocket.chat/license'; import { LivechatInquiry, LivechatRooms } from '@rocket.chat/models'; @@ -185,9 +184,7 @@ export class OmnichannelQueue implements IOmnichannelQueue { queueLogger.debug(`Processing inquiry ${inquiry._id} from queue ${queue}`); const { defaultAgent } = inquiry; - const roomFromDb = await LivechatRooms.findOneById>(inquiry.rid, { - projection: { servedBy: 1, closedAt: 1 }, - }); + const roomFromDb = await LivechatRooms.findOneById(inquiry.rid); // This is a precaution to avoid taking inquiries tied to rooms that no longer exist. // This should never happen. @@ -205,7 +202,7 @@ export class OmnichannelQueue implements IOmnichannelQueue { return this.reconciliation('closed', { roomId: inquiry.rid, inquiryId: inquiry._id }); } - const room = await RoutingManager.delegateInquiry(inquiry, defaultAgent); + const room = await RoutingManager.delegateInquiry(inquiry, defaultAgent, undefined, roomFromDb); if (room?.servedBy) { const {