From 25cfbef7b67e56753098d3bd3cd7227e340ad174 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Mar 2024 09:02:03 -0600 Subject: [PATCH 1/5] Fix issue on crm integrtion --- .../app/livechat/server/hooks/sendToCRM.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/meteor/app/livechat/server/hooks/sendToCRM.ts b/apps/meteor/app/livechat/server/hooks/sendToCRM.ts index a39c1076169c8..94ad5639b88d2 100644 --- a/apps/meteor/app/livechat/server/hooks/sendToCRM.ts +++ b/apps/meteor/app/livechat/server/hooks/sendToCRM.ts @@ -35,6 +35,16 @@ type OmnichannelRoomWithExtraFields = IOmnichannelRoom & { oldDepartmentId?: IOmnichannelRoom['departmentId']; }; +type CRMActions = + | 'LivechatSessionStarted' + | 'LivechatSessionQueued' + | 'LivechatSession' + | 'LivechatSessionTaken' + | 'LivechatSessionForwarded' + | 'LivechatEdit' + | 'Message' + | 'LeadCapture'; + const msgNavType = 'livechat_navigation_history'; const msgClosingType = 'livechat-close'; @@ -60,7 +70,7 @@ const sendMessageType = (msgType: string): boolean => { } }; -const getAdditionalFieldsByType = (type: string, room: OmnichannelRoomWithExtraFields): AdditionalFields => { +const getAdditionalFieldsByType = (type: CRMActions, room: OmnichannelRoomWithExtraFields): AdditionalFields => { const { departmentId, servedBy, closedAt, closedBy, closer, oldServedBy, oldDepartmentId } = room; switch (type) { case 'LivechatSessionStarted': @@ -78,7 +88,7 @@ const getAdditionalFieldsByType = (type: string, room: OmnichannelRoomWithExtraF }; async function sendToCRM( - type: string, + type: CRMActions, room: OmnichannelRoomWithExtraFields, includeMessages: boolean | IOmnichannelSystemMessage[] = true, ): Promise { @@ -162,7 +172,7 @@ callbacks.add( return room; } - return sendToCRM('LivechatSessionStart', room); + return sendToCRM('LivechatSessionStarted', room); }, callbacks.priority.MEDIUM, 'livechat-send-crm-start-room', From 7df573ee74d3a31518bb85af5039522b96bc09a6 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Mar 2024 09:08:33 -0600 Subject: [PATCH 2/5] Create slow-jobs-think.md --- .changeset/slow-jobs-think.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/slow-jobs-think.md diff --git a/.changeset/slow-jobs-think.md b/.changeset/slow-jobs-think.md new file mode 100644 index 0000000000000..7345e37214da9 --- /dev/null +++ b/.changeset/slow-jobs-think.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +fix: CRM integration mismatch on callback type vs code validation From c7d07513e7634822292f479852500b8e952f0454 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Mar 2024 14:42:13 -0600 Subject: [PATCH 3/5] breaking change --- apps/meteor/app/livechat/server/hooks/sendToCRM.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/meteor/app/livechat/server/hooks/sendToCRM.ts b/apps/meteor/app/livechat/server/hooks/sendToCRM.ts index 94ad5639b88d2..d115a346d1d1b 100644 --- a/apps/meteor/app/livechat/server/hooks/sendToCRM.ts +++ b/apps/meteor/app/livechat/server/hooks/sendToCRM.ts @@ -36,7 +36,7 @@ type OmnichannelRoomWithExtraFields = IOmnichannelRoom & { }; type CRMActions = - | 'LivechatSessionStarted' + | 'LivechatSessionStart' | 'LivechatSessionQueued' | 'LivechatSession' | 'LivechatSessionTaken' @@ -73,7 +73,7 @@ const sendMessageType = (msgType: string): boolean => { const getAdditionalFieldsByType = (type: CRMActions, room: OmnichannelRoomWithExtraFields): AdditionalFields => { const { departmentId, servedBy, closedAt, closedBy, closer, oldServedBy, oldDepartmentId } = room; switch (type) { - case 'LivechatSessionStarted': + case 'LivechatSessionStart': case 'LivechatSessionQueued': return { departmentId }; case 'LivechatSession': @@ -172,7 +172,7 @@ callbacks.add( return room; } - return sendToCRM('LivechatSessionStarted', room); + return sendToCRM('LivechatSessionStart', room); }, callbacks.priority.MEDIUM, 'livechat-send-crm-start-room', From 4f0a1d0cd370d686ffc5ec13b4c7ce94b3efc407 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 6 Mar 2024 11:43:03 -0600 Subject: [PATCH 4/5] Update slow-jobs-think.md --- .changeset/slow-jobs-think.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/slow-jobs-think.md b/.changeset/slow-jobs-think.md index 7345e37214da9..24d3bdba07aef 100644 --- a/.changeset/slow-jobs-think.md +++ b/.changeset/slow-jobs-think.md @@ -2,4 +2,4 @@ "@rocket.chat/meteor": patch --- -fix: CRM integration mismatch on callback type vs code validation +fix: CRM integration mismatch on callback type vs code validation. Previously, callback was attempting to register a `LivechatStarted` event, however, our internal code was expecting a `LivechatStart` event, causing the hook to receive incomplete data From 3c818cb9224adc959144629cd819aeb58c183dc5 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 11 Mar 2024 08:58:53 -0600 Subject: [PATCH 5/5] tests --- .../app/livechat/server/hooks/sendToCRM.ts | 8 +- .../livechat/server/hooks/sendToCRM.tests.ts | 123 ++++++++++++++++++ 2 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 apps/meteor/tests/unit/app/livechat/server/hooks/sendToCRM.tests.ts diff --git a/apps/meteor/app/livechat/server/hooks/sendToCRM.ts b/apps/meteor/app/livechat/server/hooks/sendToCRM.ts index d115a346d1d1b..5c3a2c0b54ab2 100644 --- a/apps/meteor/app/livechat/server/hooks/sendToCRM.ts +++ b/apps/meteor/app/livechat/server/hooks/sendToCRM.ts @@ -48,15 +48,15 @@ type CRMActions = const msgNavType = 'livechat_navigation_history'; const msgClosingType = 'livechat-close'; -const isOmnichannelNavigationMessage = (message: IMessage): message is IOmnichannelSystemMessage => { +export const isOmnichannelNavigationMessage = (message: IMessage): message is IOmnichannelSystemMessage => { return message.t === msgNavType; }; -const isOmnichannelClosingMessage = (message: IMessage): message is IOmnichannelSystemMessage => { +export const isOmnichannelClosingMessage = (message: IMessage): message is IOmnichannelSystemMessage => { return message.t === msgClosingType; }; -const sendMessageType = (msgType: string): boolean => { +export const sendMessageType = (msgType: string): boolean => { switch (msgType) { case msgClosingType: return true; @@ -70,7 +70,7 @@ const sendMessageType = (msgType: string): boolean => { } }; -const getAdditionalFieldsByType = (type: CRMActions, room: OmnichannelRoomWithExtraFields): AdditionalFields => { +export const getAdditionalFieldsByType = (type: CRMActions, room: OmnichannelRoomWithExtraFields): AdditionalFields => { const { departmentId, servedBy, closedAt, closedBy, closer, oldServedBy, oldDepartmentId } = room; switch (type) { case 'LivechatSessionStart': diff --git a/apps/meteor/tests/unit/app/livechat/server/hooks/sendToCRM.tests.ts b/apps/meteor/tests/unit/app/livechat/server/hooks/sendToCRM.tests.ts new file mode 100644 index 0000000000000..074c7047ccafa --- /dev/null +++ b/apps/meteor/tests/unit/app/livechat/server/hooks/sendToCRM.tests.ts @@ -0,0 +1,123 @@ +import { expect } from 'chai'; +import p from 'proxyquire'; + +const resultObj = { + result: true, +}; + +const { sendMessageType, isOmnichannelNavigationMessage, isOmnichannelClosingMessage, getAdditionalFieldsByType } = p + .noCallThru() + .load('../../../../../../app/livechat/server/hooks/sendToCRM', { + '../../../settings/server': { + settings: { + get() { + return resultObj.result; + }, + }, + }, + '../../../utils/server/functions/normalizeMessageFileUpload': { + normalizeMessageFileUpload: (data: any) => data, + }, + '../lib/LivechatTyped': { + Livechat: {}, + }, + }); + +describe('[OC] Send TO CRM', () => { + describe('isOmnichannelNavigationMessage', () => { + it('should return true if the message is a navigation message', () => { + const message = { t: 'livechat_navigation_history' } as any; + expect(isOmnichannelNavigationMessage(message)).to.be.true; + }); + + it('should return false if the message is not a navigation message', () => { + const message = { t: 'livechat-close' } as any; + expect(isOmnichannelNavigationMessage(message)).to.be.false; + }); + }); + + describe('isOmnichannelClosingMessage', () => { + it('should return true if the message is a closing message', () => { + const message = { t: 'livechat-close' } as any; + expect(isOmnichannelClosingMessage(message)).to.be.true; + }); + + it('should return false if the message is not a closing message', () => { + const message = { t: 'livechat_navigation_history' } as any; + expect(isOmnichannelClosingMessage(message)).to.be.false; + }); + }); + + describe('sendMessageType', () => { + it('should return true if the message type is a closing message', () => { + expect(sendMessageType('livechat-close')).to.be.true; + }); + + it('should return true if the message type is a navigation message and the settings are enabled', () => { + expect(sendMessageType('livechat_navigation_history')).to.be.true; + }); + + it('should return false if the message type is a navigation message and the settings are disabled', () => { + resultObj.result = false; + expect(sendMessageType('livechat_navigation_history')).to.be.false; + }); + + it('should return false if the message type is not a closing or navigation message', () => { + expect(sendMessageType('message')).to.be.false; + }); + }); + + describe('getAdditionalFieldsByType', () => { + it('should return the correct fields for the LivechatSessionStart type', () => { + const room = { departmentId: 'departmentId' } as any; + expect(getAdditionalFieldsByType('LivechatSessionStart', room)).to.deep.equal({ departmentId: 'departmentId' }); + }); + + it('should return the correct fields for the LivechatSessionQueued type', () => { + const room = { departmentId: 'departmentId' } as any; + expect(getAdditionalFieldsByType('LivechatSessionQueued', room)).to.deep.equal({ departmentId: 'departmentId' }); + }); + + it('should return the correct fields for the LivechatSession type', () => { + const room = { + departmentId: 'departmentId', + servedBy: 'servedBy', + closedAt: 'closedAt', + closedBy: 'closedBy', + closer: 'closer', + } as any; + expect(getAdditionalFieldsByType('LivechatSession', room)).to.deep.equal({ + departmentId: 'departmentId', + servedBy: 'servedBy', + closedAt: 'closedAt', + closedBy: 'closedBy', + closer: 'closer', + }); + }); + + it('should return the correct fields for the LivechatSessionTaken type', () => { + const room = { departmentId: 'departmentId', servedBy: 'servedBy' } as any; + expect(getAdditionalFieldsByType('LivechatSessionTaken', room)).to.deep.equal({ departmentId: 'departmentId', servedBy: 'servedBy' }); + }); + + it('should return the correct fields for the LivechatSessionForwarded type', () => { + const room = { + departmentId: 'departmentId', + servedBy: 'servedBy', + oldDepartmentId: 'oldDepartmentId', + oldServedBy: 'oldServedBy', + } as any; + expect(getAdditionalFieldsByType('LivechatSessionForwarded', room)).to.deep.equal({ + departmentId: 'departmentId', + servedBy: 'servedBy', + oldDepartmentId: 'oldDepartmentId', + oldServedBy: 'oldServedBy', + }); + }); + + it('should return an empty object for an unknown type', () => { + const room = {} as any; + expect(getAdditionalFieldsByType('unknownType' as any, room)).to.deep.equal({}); + }); + }); +});