@webex/contact-center 3.10.0-next.2 → 3.10.0-next.21
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/cc.js +13 -1
- package/dist/cc.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +2 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +12 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +4 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +2 -3
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/EntryPoint.js +2 -3
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +2 -3
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebCallingService.js +1 -1
- package/dist/services/WebCallingService.js.map +1 -1
- package/dist/services/agent/index.js +1 -2
- package/dist/services/agent/index.js.map +1 -1
- package/dist/services/agent/types.js +10 -0
- package/dist/services/agent/types.js.map +1 -1
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +1 -1
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +2 -2
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +92 -74
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/WebexRequest.js +1 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +2 -3
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/constants.js +17 -1
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +1 -2
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/connection-service.js +1 -1
- package/dist/services/core/websocket/connection-service.js.map +1 -1
- package/dist/services/core/websocket/keepalive.worker.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/AutoWrapup.js +1 -1
- package/dist/services/task/AutoWrapup.js.map +1 -1
- package/dist/services/task/TaskManager.js +177 -56
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +122 -5
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +3 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +0 -2
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/index.js +46 -40
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +377 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +6 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/services/config/types.d.ts +4 -4
- package/dist/types/services/core/Utils.d.ts +32 -17
- package/dist/types/services/core/constants.d.ts +14 -0
- package/dist/types/services/task/TaskUtils.d.ts +59 -3
- package/dist/types/services/task/constants.d.ts +2 -0
- package/dist/types/services/task/types.d.ts +57 -13
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +1 -1
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex-config.js.map +1 -1
- package/dist/webex.js +2 -2
- package/dist/webex.js.map +1 -1
- package/package.json +8 -8
- package/src/cc.ts +12 -0
- package/src/index.ts +1 -0
- package/src/metrics/behavioral-events.ts +12 -0
- package/src/metrics/constants.ts +4 -0
- package/src/services/config/types.ts +2 -2
- package/src/services/core/Utils.ts +101 -85
- package/src/services/core/constants.ts +16 -0
- package/src/services/task/TaskManager.ts +204 -36
- package/src/services/task/TaskUtils.ts +145 -5
- package/src/services/task/constants.ts +2 -0
- package/src/services/task/index.ts +50 -63
- package/src/services/task/types.ts +60 -13
- package/test/unit/spec/cc.ts +1 -0
- package/test/unit/spec/metrics/behavioral-events.ts +14 -0
- package/test/unit/spec/services/core/Utils.ts +262 -31
- package/test/unit/spec/services/task/TaskManager.ts +748 -5
- package/test/unit/spec/services/task/TaskUtils.ts +311 -9
- package/test/unit/spec/services/task/index.ts +323 -68
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -1,12 +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 {
|
|
5
|
-
generateTaskErrorObject,
|
|
6
|
-
deriveConsultTransferDestinationType,
|
|
7
|
-
getDestinationAgentId,
|
|
8
|
-
buildConsultConferenceParamData,
|
|
9
|
-
} from '../core/Utils';
|
|
4
|
+
import {generateTaskErrorObject, calculateDestAgentId, calculateDestType} from '../core/Utils';
|
|
10
5
|
import {Failure} from '../core/GlobalTypes';
|
|
11
6
|
import {LoginOption} from '../../types';
|
|
12
7
|
import {TASK_FILE} from '../../constants';
|
|
@@ -1447,35 +1442,31 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1447
1442
|
public async consultTransfer(
|
|
1448
1443
|
consultTransferPayload?: ConsultTransferPayLoad
|
|
1449
1444
|
): Promise<TaskResponse> {
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
const destAgentId = getDestinationAgentId(
|
|
1453
|
-
this.data.interaction?.participants,
|
|
1454
|
-
this.data.agentId
|
|
1455
|
-
);
|
|
1456
|
-
|
|
1457
|
-
// Resolve the target id (queue consult transfers go to the accepted agent)
|
|
1458
|
-
if (!destAgentId) {
|
|
1459
|
-
throw new Error('No agent has accepted this queue consult yet');
|
|
1460
|
-
}
|
|
1445
|
+
// Get the destination agent ID using custom logic from participants data
|
|
1446
|
+
const destAgentId = calculateDestAgentId(this.data.interaction, this.agentId);
|
|
1461
1447
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
method: METHODS.CONSULT_TRANSFER,
|
|
1467
|
-
interactionId: this.data.interactionId,
|
|
1468
|
-
}
|
|
1469
|
-
);
|
|
1470
|
-
// Obtain payload based on desktop logic using TaskData
|
|
1471
|
-
const finalDestinationType = deriveConsultTransferDestinationType(this.data);
|
|
1472
|
-
|
|
1473
|
-
// By default we always use the computed destAgentId as the target id
|
|
1474
|
-
const consultTransferRequest: ConsultTransferPayLoad = {
|
|
1475
|
-
to: destAgentId,
|
|
1476
|
-
destinationType: finalDestinationType,
|
|
1477
|
-
};
|
|
1448
|
+
// Resolve the target id (queue consult transfers go to the accepted agent)
|
|
1449
|
+
if (!destAgentId) {
|
|
1450
|
+
throw new Error('No agent has accepted this queue consult yet');
|
|
1451
|
+
}
|
|
1478
1452
|
|
|
1453
|
+
LoggerProxy.info(
|
|
1454
|
+
`Initiating consult transfer to ${consultTransferPayload?.to || destAgentId}`,
|
|
1455
|
+
{
|
|
1456
|
+
module: TASK_FILE,
|
|
1457
|
+
method: METHODS.CONSULT_TRANSFER,
|
|
1458
|
+
interactionId: this.data.interactionId,
|
|
1459
|
+
}
|
|
1460
|
+
);
|
|
1461
|
+
|
|
1462
|
+
// Derive destination type from the participant's type property
|
|
1463
|
+
const destType = calculateDestType(this.data.interaction, this.agentId);
|
|
1464
|
+
// By default we always use the computed destAgentId as the target id
|
|
1465
|
+
const consultTransferRequest: ConsultTransferPayLoad = {
|
|
1466
|
+
to: destAgentId,
|
|
1467
|
+
destinationType: destType,
|
|
1468
|
+
};
|
|
1469
|
+
try {
|
|
1479
1470
|
const result = await this.contact.consultTransfer({
|
|
1480
1471
|
interactionId: this.data.interactionId,
|
|
1481
1472
|
data: consultTransferRequest,
|
|
@@ -1513,17 +1504,12 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1513
1504
|
errorData: err.data?.errorData,
|
|
1514
1505
|
reasonCode: err.data?.reasonCode,
|
|
1515
1506
|
};
|
|
1516
|
-
const failedDestinationType = deriveConsultTransferDestinationType(this.data);
|
|
1517
|
-
const failedDestAgentId = getDestinationAgentId(
|
|
1518
|
-
this.data.interaction?.participants,
|
|
1519
|
-
this.data.agentId
|
|
1520
|
-
);
|
|
1521
1507
|
this.metricsManager.trackEvent(
|
|
1522
1508
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
1523
1509
|
{
|
|
1524
1510
|
taskId: this.data.interactionId,
|
|
1525
|
-
destination:
|
|
1526
|
-
destinationType:
|
|
1511
|
+
destination: destAgentId || '',
|
|
1512
|
+
destinationType: destType,
|
|
1527
1513
|
isConsultTransfer: true,
|
|
1528
1514
|
error: error.toString(),
|
|
1529
1515
|
...taskErrorProps,
|
|
@@ -1556,28 +1542,36 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1556
1542
|
* ```
|
|
1557
1543
|
*/
|
|
1558
1544
|
public async consultConference(): Promise<TaskResponse> {
|
|
1545
|
+
// Get the destination agent ID dynamically from participants
|
|
1546
|
+
// This handles multi-party conference scenarios, CBT (Capacity Based Team), and EP-DN cases
|
|
1547
|
+
const destAgentId = calculateDestAgentId(this.data.interaction, this.agentId);
|
|
1548
|
+
|
|
1549
|
+
// Validate that we have a destination agent (for queue consult scenarios)
|
|
1550
|
+
if (!destAgentId) {
|
|
1551
|
+
throw new Error('No agent has accepted this queue consult yet');
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// Get the destination agent ID for fetching destination type
|
|
1555
|
+
// This helps determine the correct participant type for CBT (Capacity Based Team) and EP-DN scenarios
|
|
1556
|
+
const destAgentType = calculateDestType(this.data.interaction, this.agentId);
|
|
1557
|
+
|
|
1559
1558
|
// Extract consultation conference data from task data (used in both try and catch)
|
|
1560
1559
|
const consultationData = {
|
|
1561
1560
|
agentId: this.agentId,
|
|
1562
|
-
|
|
1563
|
-
destinationType: this.data.destinationType || 'agent',
|
|
1561
|
+
to: destAgentId,
|
|
1562
|
+
destinationType: destAgentType || this.data.destinationType || 'agent',
|
|
1564
1563
|
};
|
|
1565
1564
|
|
|
1566
1565
|
try {
|
|
1567
|
-
LoggerProxy.info(`Initiating consult conference to ${
|
|
1566
|
+
LoggerProxy.info(`Initiating consult conference to ${destAgentId}`, {
|
|
1568
1567
|
module: TASK_FILE,
|
|
1569
1568
|
method: METHODS.CONSULT_CONFERENCE,
|
|
1570
1569
|
interactionId: this.data.interactionId,
|
|
1571
1570
|
});
|
|
1572
1571
|
|
|
1573
|
-
const paramsDataForConferenceV2 = buildConsultConferenceParamData(
|
|
1574
|
-
consultationData,
|
|
1575
|
-
this.data.interactionId
|
|
1576
|
-
);
|
|
1577
|
-
|
|
1578
1572
|
const response = await this.contact.consultConference({
|
|
1579
|
-
interactionId:
|
|
1580
|
-
data:
|
|
1573
|
+
interactionId: this.data.interactionId,
|
|
1574
|
+
data: consultationData,
|
|
1581
1575
|
});
|
|
1582
1576
|
|
|
1583
1577
|
// Track success metrics (following consultTransfer pattern)
|
|
@@ -1585,9 +1579,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1585
1579
|
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS,
|
|
1586
1580
|
{
|
|
1587
1581
|
taskId: this.data.interactionId,
|
|
1588
|
-
destination:
|
|
1589
|
-
destinationType:
|
|
1590
|
-
agentId:
|
|
1582
|
+
destination: consultationData.to,
|
|
1583
|
+
destinationType: consultationData.destinationType,
|
|
1584
|
+
agentId: consultationData.agentId,
|
|
1591
1585
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1592
1586
|
},
|
|
1593
1587
|
['operational', 'behavioral', 'business']
|
|
@@ -1610,20 +1604,13 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1610
1604
|
reasonCode: err.data?.reasonCode,
|
|
1611
1605
|
};
|
|
1612
1606
|
|
|
1613
|
-
// Track failure metrics (following consultTransfer pattern)
|
|
1614
|
-
// Build conference data for error tracking using extracted data
|
|
1615
|
-
const failedParamsData = buildConsultConferenceParamData(
|
|
1616
|
-
consultationData,
|
|
1617
|
-
this.data.interactionId
|
|
1618
|
-
);
|
|
1619
|
-
|
|
1620
1607
|
this.metricsManager.trackEvent(
|
|
1621
1608
|
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED,
|
|
1622
1609
|
{
|
|
1623
1610
|
taskId: this.data.interactionId,
|
|
1624
|
-
destination:
|
|
1625
|
-
destinationType:
|
|
1626
|
-
agentId:
|
|
1611
|
+
destination: consultationData.to,
|
|
1612
|
+
destinationType: consultationData.destinationType,
|
|
1613
|
+
agentId: consultationData.agentId,
|
|
1627
1614
|
error: error.toString(),
|
|
1628
1615
|
...taskErrorProps,
|
|
1629
1616
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
@@ -347,6 +347,18 @@ export enum TASK_EVENTS {
|
|
|
347
347
|
*/
|
|
348
348
|
TASK_REJECT = 'task:rejected',
|
|
349
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Triggered when an outdial call fails
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* task.on(TASK_EVENTS.TASK_OUTDIAL_FAILED, (reason: string) => {
|
|
355
|
+
* console.log('Outdial failed:', reason);
|
|
356
|
+
* // Handle outdial failure
|
|
357
|
+
* });
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
TASK_OUTDIAL_FAILED = 'task:outdialFailed',
|
|
361
|
+
|
|
350
362
|
/**
|
|
351
363
|
* Triggered when a task is populated with data
|
|
352
364
|
* @example
|
|
@@ -371,6 +383,22 @@ export enum TASK_EVENTS {
|
|
|
371
383
|
*/
|
|
372
384
|
TASK_OFFER_CONTACT = 'task:offerContact',
|
|
373
385
|
|
|
386
|
+
/**
|
|
387
|
+
* Triggered when a task has been successfully auto-answered
|
|
388
|
+
* This event is emitted after the SDK automatically accepts a task due to:
|
|
389
|
+
* - WebRTC calls with auto-answer enabled
|
|
390
|
+
* - Agent-initiated outdial calls
|
|
391
|
+
* - Other auto-answer scenarios
|
|
392
|
+
* @example
|
|
393
|
+
* ```typescript
|
|
394
|
+
* task.on(TASK_EVENTS.TASK_AUTO_ANSWERED, (task: ITask) => {
|
|
395
|
+
* console.log('Task auto-answered:', task.data.interactionId);
|
|
396
|
+
* // Update UI - enable cancel button, etc.
|
|
397
|
+
* });
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
TASK_AUTO_ANSWERED = 'task:autoAnswered',
|
|
401
|
+
|
|
374
402
|
/**
|
|
375
403
|
* Triggered when a conference is being established
|
|
376
404
|
* @example
|
|
@@ -490,6 +518,30 @@ export enum TASK_EVENTS {
|
|
|
490
518
|
* ```
|
|
491
519
|
*/
|
|
492
520
|
TASK_PARTICIPANT_LEFT_FAILED = 'task:participantLeftFailed',
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Triggered when a contact is merged
|
|
524
|
+
* @example
|
|
525
|
+
* ```typescript
|
|
526
|
+
* task.on(TASK_EVENTS.TASK_MERGED, (task: ITask) => {
|
|
527
|
+
* console.log('Contact merged:', task.data.interactionId);
|
|
528
|
+
* // Handle contact merge
|
|
529
|
+
* });
|
|
530
|
+
* ```
|
|
531
|
+
*/
|
|
532
|
+
TASK_MERGED = 'task:merged',
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Triggered when a participant enters post-call activity state
|
|
536
|
+
* @example
|
|
537
|
+
* ```typescript
|
|
538
|
+
* task.on(TASK_EVENTS.TASK_POST_CALL_ACTIVITY, (task: ITask) => {
|
|
539
|
+
* console.log('Participant in post-call activity:', task.data.interactionId);
|
|
540
|
+
* // Handle post-call activity
|
|
541
|
+
* });
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
TASK_POST_CALL_ACTIVITY = 'task:postCallActivity',
|
|
493
545
|
}
|
|
494
546
|
|
|
495
547
|
/**
|
|
@@ -636,6 +688,8 @@ export type Interaction = {
|
|
|
636
688
|
BLIND_TRANSFER_IN_PROGRESS?: boolean;
|
|
637
689
|
/** Desktop view configuration for Flow Control */
|
|
638
690
|
fcDesktopView?: string;
|
|
691
|
+
/** Agent ID who initiated the outdial call */
|
|
692
|
+
outdialAgentId?: string;
|
|
639
693
|
};
|
|
640
694
|
/** Main interaction identifier for related interactions */
|
|
641
695
|
mainInteractionId?: string;
|
|
@@ -757,8 +811,14 @@ export type TaskData = {
|
|
|
757
811
|
isWebCallMute?: boolean;
|
|
758
812
|
/** Identifier for reservation interaction */
|
|
759
813
|
reservationInteractionId?: string;
|
|
814
|
+
/** Identifier for the reserved agent channel (used for campaign tasks) */
|
|
815
|
+
reservedAgentChannelId?: string;
|
|
760
816
|
/** Indicates if wrap-up is required for this task */
|
|
761
817
|
wrapUpRequired?: boolean;
|
|
818
|
+
/** Indicates if auto-answer is in progress for this task */
|
|
819
|
+
isAutoAnswering?: boolean;
|
|
820
|
+
/** Indicates if wrap-up is required for this task */
|
|
821
|
+
agentsPendingWrapUp?: string[];
|
|
762
822
|
};
|
|
763
823
|
|
|
764
824
|
/**
|
|
@@ -1005,19 +1065,6 @@ export type ConsultConferenceData = {
|
|
|
1005
1065
|
destinationType: string;
|
|
1006
1066
|
};
|
|
1007
1067
|
|
|
1008
|
-
/**
|
|
1009
|
-
* Legacy consultation conference data type matching Agent Desktop
|
|
1010
|
-
* @public
|
|
1011
|
-
*/
|
|
1012
|
-
export type consultConferencePayloadData = {
|
|
1013
|
-
/** Identifier of the agent initiating consult/conference */
|
|
1014
|
-
agentId: string;
|
|
1015
|
-
/** Type of destination (e.g., 'agent', 'queue') */
|
|
1016
|
-
destinationType: string;
|
|
1017
|
-
/** Identifier of the destination agent */
|
|
1018
|
-
destAgentId: string;
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
1068
|
/**
|
|
1022
1069
|
* Parameters required for cancelling a consult to queue operation
|
|
1023
1070
|
* @public
|
package/test/unit/spec/cc.ts
CHANGED
|
@@ -152,6 +152,20 @@ describe('metrics/behavioral-events', () => {
|
|
|
152
152
|
verb: 'fail',
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_AUTO_ANSWER_SUCCESS)).toEqual({
|
|
156
|
+
product,
|
|
157
|
+
agent: 'user',
|
|
158
|
+
target: 'task_auto_answer',
|
|
159
|
+
verb: 'complete',
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(getEventTaxonomy(METRIC_EVENT_NAMES.TASK_AUTO_ANSWER_FAILED)).toEqual({
|
|
163
|
+
product,
|
|
164
|
+
agent: 'user',
|
|
165
|
+
target: 'task_auto_answer',
|
|
166
|
+
verb: 'fail',
|
|
167
|
+
});
|
|
168
|
+
|
|
155
169
|
expect(getEventTaxonomy('' as METRIC_EVENT_NAMES)).toEqual(undefined);
|
|
156
170
|
});
|
|
157
171
|
});
|
|
@@ -229,7 +229,7 @@ describe('Utils', () => {
|
|
|
229
229
|
});
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
-
it('should return DUPLICATE_LOCATION message and fieldName for
|
|
232
|
+
it('should return DUPLICATE_LOCATION message and fieldName for dial number', () => {
|
|
233
233
|
const failure = {data: {reason: 'DUPLICATE_LOCATION'}} as Failure;
|
|
234
234
|
const result = Utils.getStationLoginErrorData(failure, LoginOption.AGENT_DN);
|
|
235
235
|
expect(result).toEqual({
|
|
@@ -277,53 +277,284 @@ describe('Utils', () => {
|
|
|
277
277
|
});
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
describe('
|
|
281
|
-
const currentAgentId = 'agent-
|
|
280
|
+
describe('getConsultedAgentId', () => {
|
|
281
|
+
const currentAgentId = 'agent-123';
|
|
282
282
|
|
|
283
|
-
it('
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
it('should return consulted agent ID from consult media', () => {
|
|
284
|
+
const media: any = {
|
|
285
|
+
mainCall: {
|
|
286
|
+
mType: 'mainCall',
|
|
287
|
+
participants: [currentAgentId, 'customer-1'],
|
|
288
|
+
},
|
|
289
|
+
consultCall: {
|
|
290
|
+
mType: 'consult',
|
|
291
|
+
participants: [currentAgentId, 'agent-456'],
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const result = Utils.getConsultedAgentId(media, currentAgentId);
|
|
296
|
+
expect(result).toBe('agent-456');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should return empty string when no consult media exists', () => {
|
|
300
|
+
const media: any = {
|
|
301
|
+
mainCall: {
|
|
302
|
+
mType: 'mainCall',
|
|
303
|
+
participants: [currentAgentId, 'customer-1'],
|
|
304
|
+
},
|
|
288
305
|
};
|
|
289
306
|
|
|
290
|
-
const result = Utils.
|
|
291
|
-
expect(result).toBe('
|
|
307
|
+
const result = Utils.getConsultedAgentId(media, currentAgentId);
|
|
308
|
+
expect(result).toBe('');
|
|
292
309
|
});
|
|
293
310
|
|
|
294
|
-
it('
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
311
|
+
it('should return empty string when current agent is not in consult participants', () => {
|
|
312
|
+
const media: any = {
|
|
313
|
+
consultCall: {
|
|
314
|
+
mType: 'consult',
|
|
315
|
+
participants: ['other-agent-1', 'other-agent-2'],
|
|
316
|
+
},
|
|
298
317
|
};
|
|
299
318
|
|
|
300
|
-
const result = Utils.
|
|
319
|
+
const result = Utils.getConsultedAgentId(media, currentAgentId);
|
|
320
|
+
expect(result).toBe('');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should handle empty media object', () => {
|
|
324
|
+
const result = Utils.getConsultedAgentId({}, currentAgentId);
|
|
301
325
|
expect(result).toBe('');
|
|
302
326
|
});
|
|
303
327
|
|
|
304
|
-
it('
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
328
|
+
it('should handle multiple media entries and find consult', () => {
|
|
329
|
+
const media: any = {
|
|
330
|
+
media1: {mType: 'mainCall', participants: [currentAgentId]},
|
|
331
|
+
media2: {mType: 'hold', participants: []},
|
|
332
|
+
media3: {mType: 'consult', participants: [currentAgentId, 'consulted-agent']},
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const result = Utils.getConsultedAgentId(media, currentAgentId);
|
|
336
|
+
expect(result).toBe('consulted-agent');
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe('getDestAgentIdForCBT', () => {
|
|
341
|
+
it('should return destination agent ID for CBT scenario', () => {
|
|
342
|
+
const interaction: any = {
|
|
343
|
+
participants: {
|
|
344
|
+
'agent-uuid-123': {
|
|
345
|
+
type: 'Agent',
|
|
346
|
+
pType: 'dn',
|
|
347
|
+
dn: '5551234567',
|
|
348
|
+
id: 'agent-uuid-123',
|
|
349
|
+
},
|
|
350
|
+
'customer-1': {
|
|
351
|
+
type: 'Customer',
|
|
352
|
+
pType: 'Customer',
|
|
353
|
+
id: 'customer-1',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
const consultingAgent = '5551234567'; // Phone number, not in participants as key
|
|
358
|
+
|
|
359
|
+
const result = Utils.getDestAgentIdForCBT(interaction, consultingAgent);
|
|
360
|
+
expect(result).toBe('agent-uuid-123');
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('should return empty string when consultingAgent is in participants (non-CBT)', () => {
|
|
364
|
+
const interaction: any = {
|
|
365
|
+
participants: {
|
|
366
|
+
'agent-123': {
|
|
367
|
+
type: 'Agent',
|
|
368
|
+
pType: 'Agent',
|
|
369
|
+
id: 'agent-123',
|
|
370
|
+
},
|
|
371
|
+
},
|
|
308
372
|
};
|
|
309
|
-
|
|
373
|
+
const consultingAgent = 'agent-123'; // Exists as key in participants
|
|
374
|
+
|
|
375
|
+
const result = Utils.getDestAgentIdForCBT(interaction, consultingAgent);
|
|
376
|
+
expect(result).toBe('');
|
|
377
|
+
});
|
|
310
378
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
379
|
+
it('should return empty string when no matching dial number found', () => {
|
|
380
|
+
const interaction: any = {
|
|
381
|
+
participants: {
|
|
382
|
+
'agent-uuid-123': {
|
|
383
|
+
type: 'Agent',
|
|
384
|
+
pType: 'dn',
|
|
385
|
+
dn: '5559999999',
|
|
386
|
+
id: 'agent-uuid-123',
|
|
387
|
+
},
|
|
388
|
+
},
|
|
314
389
|
};
|
|
315
|
-
|
|
390
|
+
const consultingAgent = '5551234567'; // Different number
|
|
391
|
+
|
|
392
|
+
const result = Utils.getDestAgentIdForCBT(interaction, consultingAgent);
|
|
393
|
+
expect(result).toBe('');
|
|
394
|
+
});
|
|
316
395
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
396
|
+
it('should return empty string when consultingAgent is empty', () => {
|
|
397
|
+
const interaction: any = {
|
|
398
|
+
participants: {
|
|
399
|
+
'agent-uuid-123': {
|
|
400
|
+
type: 'Agent',
|
|
401
|
+
pType: 'dn',
|
|
402
|
+
dn: '5551234567',
|
|
403
|
+
},
|
|
404
|
+
},
|
|
320
405
|
};
|
|
321
|
-
|
|
406
|
+
|
|
407
|
+
const result = Utils.getDestAgentIdForCBT(interaction, '');
|
|
408
|
+
expect(result).toBe('');
|
|
322
409
|
});
|
|
323
410
|
|
|
324
|
-
it('
|
|
325
|
-
|
|
326
|
-
|
|
411
|
+
it('should match only when participant type is dial number and type is Agent', () => {
|
|
412
|
+
const interaction: any = {
|
|
413
|
+
participants: {
|
|
414
|
+
'participant-1': {
|
|
415
|
+
type: 'Customer',
|
|
416
|
+
pType: 'dn',
|
|
417
|
+
dn: '5551234567',
|
|
418
|
+
},
|
|
419
|
+
'participant-2': {
|
|
420
|
+
type: 'Agent',
|
|
421
|
+
pType: 'Agent',
|
|
422
|
+
dn: '5551234567',
|
|
423
|
+
},
|
|
424
|
+
'participant-3': {
|
|
425
|
+
type: 'Agent',
|
|
426
|
+
pType: 'dn',
|
|
427
|
+
dn: '5551234567',
|
|
428
|
+
id: 'correct-agent',
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const result = Utils.getDestAgentIdForCBT(interaction, '5551234567');
|
|
434
|
+
expect(result).toBe('participant-3');
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('should handle case-insensitive participant type comparison', () => {
|
|
438
|
+
const interaction: any = {
|
|
439
|
+
participants: {
|
|
440
|
+
'agent-uuid': {
|
|
441
|
+
type: 'Agent',
|
|
442
|
+
pType: 'DN', // Uppercase (dial number)
|
|
443
|
+
dn: '5551234567',
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
const result = Utils.getDestAgentIdForCBT(interaction, '5551234567');
|
|
449
|
+
expect(result).toBe('agent-uuid');
|
|
327
450
|
});
|
|
328
451
|
});
|
|
452
|
+
|
|
453
|
+
describe('calculateDestAgentId', () => {
|
|
454
|
+
const currentAgentId = 'agent-123';
|
|
455
|
+
|
|
456
|
+
it('should return destAgentIdCBT when found', () => {
|
|
457
|
+
const interaction: any = {
|
|
458
|
+
media: {
|
|
459
|
+
consult: {
|
|
460
|
+
mType: 'consult',
|
|
461
|
+
participants: [currentAgentId, '5551234567'],
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
participants: {
|
|
465
|
+
'agent-uuid-456': {
|
|
466
|
+
type: 'Agent',
|
|
467
|
+
pType: 'dn',
|
|
468
|
+
dn: '5551234567',
|
|
469
|
+
id: 'agent-uuid-456',
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const result = Utils.calculateDestAgentId(interaction, currentAgentId);
|
|
475
|
+
expect(result).toBe('agent-uuid-456');
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should return participant id for regular agent when not CBT', () => {
|
|
479
|
+
const consultedAgentId = 'agent-456';
|
|
480
|
+
const interaction: any = {
|
|
481
|
+
media: {
|
|
482
|
+
consult: {
|
|
483
|
+
mType: 'consult',
|
|
484
|
+
participants: [currentAgentId, consultedAgentId],
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
participants: {
|
|
488
|
+
[consultedAgentId]: {
|
|
489
|
+
type: 'Agent',
|
|
490
|
+
id: consultedAgentId,
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
const result = Utils.calculateDestAgentId(interaction, currentAgentId);
|
|
496
|
+
expect(result).toBe(consultedAgentId);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should return epId for EpDn type participants', () => {
|
|
500
|
+
const consultedAgentId = 'epdn-456';
|
|
501
|
+
const interaction: any = {
|
|
502
|
+
media: {
|
|
503
|
+
consult: {
|
|
504
|
+
mType: 'consult',
|
|
505
|
+
participants: [currentAgentId, consultedAgentId],
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
participants: {
|
|
509
|
+
[consultedAgentId]: {
|
|
510
|
+
type: 'EpDn',
|
|
511
|
+
id: consultedAgentId,
|
|
512
|
+
epId: 'entry-point-id-789',
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
const result = Utils.calculateDestAgentId(interaction, currentAgentId);
|
|
518
|
+
expect(result).toBe('entry-point-id-789');
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it('should return undefined when no consulting agent found', () => {
|
|
522
|
+
const interaction: any = {
|
|
523
|
+
media: {
|
|
524
|
+
mainCall: {
|
|
525
|
+
mType: 'mainCall',
|
|
526
|
+
participants: [currentAgentId],
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
participants: {},
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const result = Utils.calculateDestAgentId(interaction, currentAgentId);
|
|
533
|
+
expect(result).toBeUndefined();
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it('should handle CBT scenario when phone number is not a direct participant key', () => {
|
|
537
|
+
const interaction: any = {
|
|
538
|
+
media: {
|
|
539
|
+
consult: {
|
|
540
|
+
mType: 'consult',
|
|
541
|
+
participants: [currentAgentId, '5551234567'], // Phone number in media
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
participants: {
|
|
545
|
+
// Note: '5551234567' is NOT a key - this is CBT
|
|
546
|
+
'agent-uuid-cbt': {
|
|
547
|
+
type: 'Agent',
|
|
548
|
+
pType: 'dn',
|
|
549
|
+
dn: '5551234567', // Found by matching DN
|
|
550
|
+
id: 'agent-uuid-cbt',
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const result = Utils.calculateDestAgentId(interaction, currentAgentId);
|
|
556
|
+
expect(result).toBe('agent-uuid-cbt'); // Returns the CBT agent
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
329
560
|
});
|