@webex/contact-center 3.9.0-next.1 → 3.9.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/services/core/Utils.js +45 -1
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/task/TaskManager.js +1 -1
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/index.js +19 -19
- package/dist/services/task/index.js.map +1 -1
- package/dist/types/services/core/Utils.d.ts +14 -0
- package/dist/types/services/task/index.d.ts +1 -1
- package/dist/webex.js +1 -1
- package/package.json +2 -2
- package/src/services/core/Utils.ts +49 -0
- package/src/services/task/TaskManager.ts +1 -1
- package/src/services/task/index.ts +37 -29
- package/test/unit/spec/services/task/TaskManager.ts +8 -1
- package/test/unit/spec/services/task/index.ts +63 -11
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import {CALL_EVENT_KEYS, LocalMicrophoneStream} from '@webex/calling';
|
|
3
3
|
import {CallId} from '@webex/calling/dist/types/common/types';
|
|
4
|
-
import {getErrorDetails} from '../core/Utils';
|
|
4
|
+
import {getErrorDetails, deriveConsultTransferDestinationType} from '../core/Utils';
|
|
5
5
|
import {LoginOption} from '../../types';
|
|
6
6
|
import {TASK_FILE} from '../../constants';
|
|
7
7
|
import {METHODS} from './constants';
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
ConsultEndPayload,
|
|
20
20
|
TransferPayLoad,
|
|
21
21
|
DESTINATION_TYPE,
|
|
22
|
-
CONSULT_TRANSFER_DESTINATION_TYPE,
|
|
23
22
|
ConsultTransferPayLoad,
|
|
24
23
|
MEDIA_CHANNEL,
|
|
25
24
|
} from './types';
|
|
@@ -1308,61 +1307,70 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1308
1307
|
* ```
|
|
1309
1308
|
*/
|
|
1310
1309
|
public async consultTransfer(
|
|
1311
|
-
consultTransferPayload
|
|
1310
|
+
consultTransferPayload?: ConsultTransferPayLoad
|
|
1312
1311
|
): Promise<TaskResponse> {
|
|
1313
1312
|
try {
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
});
|
|
1313
|
+
// Resolve the target id (queue consult transfers go to the accepted agent)
|
|
1314
|
+
if (!this.data.destAgentId) {
|
|
1315
|
+
throw new Error('No agent has accepted this queue consult yet');
|
|
1316
|
+
}
|
|
1319
1317
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1318
|
+
LoggerProxy.info(
|
|
1319
|
+
`Initiating consult transfer to ${consultTransferPayload?.to || this.data.destAgentId}`,
|
|
1320
|
+
{
|
|
1321
|
+
module: TASK_FILE,
|
|
1322
|
+
method: METHODS.CONSULT_TRANSFER,
|
|
1323
|
+
interactionId: this.data.interactionId,
|
|
1324
1324
|
}
|
|
1325
|
+
);
|
|
1326
|
+
// Obtain payload based on desktop logic using TaskData
|
|
1327
|
+
const finalDestinationType = deriveConsultTransferDestinationType(this.data);
|
|
1325
1328
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
}
|
|
1329
|
+
// By default we always use `destAgentId` as the target id
|
|
1330
|
+
const consultTransferRequest: ConsultTransferPayLoad = {
|
|
1331
|
+
to: this.data.destAgentId,
|
|
1332
|
+
destinationType: finalDestinationType,
|
|
1333
|
+
};
|
|
1332
1334
|
|
|
1333
1335
|
const result = await this.contact.consultTransfer({
|
|
1334
1336
|
interactionId: this.data.interactionId,
|
|
1335
|
-
data:
|
|
1337
|
+
data: consultTransferRequest,
|
|
1336
1338
|
});
|
|
1337
1339
|
|
|
1338
1340
|
this.metricsManager.trackEvent(
|
|
1339
1341
|
METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
|
|
1340
1342
|
{
|
|
1341
1343
|
taskId: this.data.interactionId,
|
|
1342
|
-
destination:
|
|
1343
|
-
destinationType:
|
|
1344
|
+
destination: consultTransferRequest.to,
|
|
1345
|
+
destinationType: consultTransferRequest.destinationType,
|
|
1344
1346
|
isConsultTransfer: true,
|
|
1345
1347
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
|
|
1346
1348
|
},
|
|
1347
1349
|
['operational', 'behavioral', 'business']
|
|
1348
1350
|
);
|
|
1349
1351
|
|
|
1350
|
-
LoggerProxy.log(
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1352
|
+
LoggerProxy.log(
|
|
1353
|
+
`Consult transfer completed successfully to ${
|
|
1354
|
+
consultTransferPayload?.to || this.data.destAgentId
|
|
1355
|
+
}`,
|
|
1356
|
+
{
|
|
1357
|
+
module: TASK_FILE,
|
|
1358
|
+
method: METHODS.CONSULT_TRANSFER,
|
|
1359
|
+
trackingId: result.trackingId,
|
|
1360
|
+
interactionId: this.data.interactionId,
|
|
1361
|
+
}
|
|
1362
|
+
);
|
|
1356
1363
|
|
|
1357
1364
|
return result;
|
|
1358
1365
|
} catch (error) {
|
|
1359
1366
|
const {error: detailedError} = getErrorDetails(error, METHODS.CONSULT_TRANSFER, TASK_FILE);
|
|
1367
|
+
const failedDestinationType = deriveConsultTransferDestinationType(this.data);
|
|
1360
1368
|
this.metricsManager.trackEvent(
|
|
1361
1369
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
1362
1370
|
{
|
|
1363
1371
|
taskId: this.data.interactionId,
|
|
1364
|
-
destination:
|
|
1365
|
-
destinationType:
|
|
1372
|
+
destination: this.data.destAgentId || '',
|
|
1373
|
+
destinationType: failedDestinationType,
|
|
1366
1374
|
isConsultTransfer: true,
|
|
1367
1375
|
error: error.toString(),
|
|
1368
1376
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
@@ -658,6 +658,13 @@ describe('TaskManager', () => {
|
|
|
658
658
|
});
|
|
659
659
|
|
|
660
660
|
it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
|
|
661
|
+
const initialConsultingPayload = {
|
|
662
|
+
data: {
|
|
663
|
+
...initalPayload.data,
|
|
664
|
+
type: CC_EVENTS.AGENT_OFFER_CONSULT,
|
|
665
|
+
},
|
|
666
|
+
};
|
|
667
|
+
|
|
661
668
|
const consultingPayload = {
|
|
662
669
|
data: {
|
|
663
670
|
...initalPayload.data,
|
|
@@ -672,8 +679,8 @@ describe('TaskManager', () => {
|
|
|
672
679
|
});
|
|
673
680
|
|
|
674
681
|
const taskEmitSpy = jest.spyOn(taskManager.getTask(taskId), 'emit');
|
|
682
|
+
webSocketManagerMock.emit('message', JSON.stringify(initialConsultingPayload));
|
|
675
683
|
webSocketManagerMock.emit('message', JSON.stringify(consultingPayload));
|
|
676
|
-
expect(taskManager.getTask(taskId).updateTaskData).toHaveBeenCalledWith(consultingPayload.data);
|
|
677
684
|
expect(taskManager.getTask(taskId).data.isConsulted).toBe(true);
|
|
678
685
|
expect(taskEmitSpy).toHaveBeenCalledWith(
|
|
679
686
|
TASK_EVENTS.TASK_CONSULT_ACCEPTED,
|
|
@@ -754,29 +754,81 @@ describe('Task', () => {
|
|
|
754
754
|
expect(contactMock.consult).toHaveBeenCalledWith({interactionId: taskId, data: consultPayload});
|
|
755
755
|
expect(response).toEqual(expectedResponse);
|
|
756
756
|
|
|
757
|
-
const
|
|
758
|
-
to: '1234',
|
|
759
|
-
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
760
|
-
};
|
|
761
|
-
|
|
762
|
-
const consultTransferResponse = await task.consultTransfer(consultTransferPayload);
|
|
757
|
+
const consultTransferResponse = await task.consultTransfer();
|
|
763
758
|
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
764
759
|
interactionId: taskId,
|
|
765
|
-
data:
|
|
760
|
+
data: {
|
|
761
|
+
to: taskDataMock.destAgentId,
|
|
762
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
763
|
+
},
|
|
766
764
|
});
|
|
767
765
|
expect(mockMetricsManager.trackEvent).toHaveBeenNthCalledWith(
|
|
768
766
|
2,
|
|
769
767
|
METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
|
|
770
768
|
{
|
|
771
769
|
taskId: taskDataMock.interactionId,
|
|
772
|
-
destination:
|
|
773
|
-
destinationType:
|
|
770
|
+
destination: taskDataMock.destAgentId,
|
|
771
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
774
772
|
isConsultTransfer: true,
|
|
775
773
|
},
|
|
776
774
|
['operational', 'behavioral', 'business']
|
|
777
775
|
);
|
|
778
776
|
});
|
|
779
777
|
|
|
778
|
+
it('should send DIALNUMBER when task destinationType is DN during consultTransfer', async () => {
|
|
779
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
780
|
+
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
781
|
+
|
|
782
|
+
// Ensure task data indicates DN scenario
|
|
783
|
+
task.data.destinationType = 'DN' as unknown as string;
|
|
784
|
+
|
|
785
|
+
await task.consultTransfer();
|
|
786
|
+
|
|
787
|
+
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
788
|
+
interactionId: taskId,
|
|
789
|
+
data: {
|
|
790
|
+
to: taskDataMock.destAgentId,
|
|
791
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER,
|
|
792
|
+
},
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
it('should send ENTRYPOINT when task destinationType is EPDN during consultTransfer', async () => {
|
|
797
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
798
|
+
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
799
|
+
|
|
800
|
+
// Ensure task data indicates EP/EPDN scenario
|
|
801
|
+
task.data.destinationType = 'EPDN' as unknown as string;
|
|
802
|
+
|
|
803
|
+
await task.consultTransfer();
|
|
804
|
+
|
|
805
|
+
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
806
|
+
interactionId: taskId,
|
|
807
|
+
data: {
|
|
808
|
+
to: taskDataMock.destAgentId,
|
|
809
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT,
|
|
810
|
+
},
|
|
811
|
+
});
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it('should keep AGENT when task destinationType is neither DN nor EPDN/ENTRYPOINT', async () => {
|
|
815
|
+
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
816
|
+
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
817
|
+
|
|
818
|
+
// Ensure task data indicates non-DN and non-EP/EPDN scenario
|
|
819
|
+
task.data.destinationType = 'SOMETHING_ELSE' as unknown as string;
|
|
820
|
+
|
|
821
|
+
await task.consultTransfer();
|
|
822
|
+
|
|
823
|
+
expect(contactMock.consultTransfer).toHaveBeenCalledWith({
|
|
824
|
+
interactionId: taskId,
|
|
825
|
+
data: {
|
|
826
|
+
to: taskDataMock.destAgentId,
|
|
827
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
828
|
+
},
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
|
|
780
832
|
it('should do consult transfer to a queue by using the destAgentId from task data', async () => {
|
|
781
833
|
const expectedResponse: TaskResponse = {data: {interactionId: taskId}} as AgentContact;
|
|
782
834
|
contactMock.consultTransfer.mockResolvedValue(expectedResponse);
|
|
@@ -855,8 +907,8 @@ describe('Task', () => {
|
|
|
855
907
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
856
908
|
{
|
|
857
909
|
taskId: taskDataMock.interactionId,
|
|
858
|
-
destination:
|
|
859
|
-
destinationType:
|
|
910
|
+
destination: taskDataMock.destAgentId,
|
|
911
|
+
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
860
912
|
isConsultTransfer: true,
|
|
861
913
|
error: error.toString(),
|
|
862
914
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details),
|