@webex/contact-center 3.9.0 → 3.10.0-next.10
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 +207 -47
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/logger-proxy.js +24 -1
- package/dist/logger-proxy.js.map +1 -1
- package/dist/metrics/MetricsManager.js +1 -1
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +89 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +32 -2
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +271 -0
- package/dist/services/AddressBook.js.map +1 -0
- package/dist/services/EntryPoint.js +227 -0
- package/dist/services/EntryPoint.js.map +1 -0
- package/dist/services/Queue.js +261 -0
- package/dist/services/Queue.js.map +1 -0
- package/dist/services/config/constants.js +36 -2
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +29 -21
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +33 -1
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/GlobalTypes.js.map +1 -1
- package/dist/services/core/Utils.js +181 -2
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +0 -4
- 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/websocket/WebSocketManager.js +0 -4
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/task/TaskManager.js +151 -7
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +104 -0
- package/dist/services/task/TaskUtils.js.map +1 -0
- package/dist/services/task/constants.js +26 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +86 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/index.js +428 -91
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +12 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +121 -35
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/index.d.ts +4 -3
- package/dist/types/metrics/constants.d.ts +25 -1
- package/dist/types/services/AddressBook.d.ts +74 -0
- package/dist/types/services/EntryPoint.d.ts +67 -0
- package/dist/types/services/Queue.d.ts +76 -0
- package/dist/types/services/config/constants.d.ts +35 -1
- package/dist/types/services/config/index.d.ts +6 -9
- package/dist/types/services/config/types.d.ts +79 -58
- package/dist/types/services/core/GlobalTypes.d.ts +25 -0
- package/dist/types/services/core/Utils.d.ts +55 -1
- package/dist/types/services/core/constants.d.ts +14 -0
- package/dist/types/services/task/TaskUtils.d.ts +42 -0
- package/dist/types/services/task/constants.d.ts +23 -0
- package/dist/types/services/task/contact.d.ts +10 -0
- package/dist/types/services/task/index.d.ts +85 -4
- package/dist/types/services/task/types.d.ts +245 -21
- package/dist/types/types.d.ts +162 -0
- package/dist/types/utils/PageCache.d.ts +173 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +192 -0
- package/dist/utils/PageCache.js.map +1 -0
- package/dist/webex.js +1 -1
- package/package.json +10 -9
- package/src/cc.ts +232 -52
- package/src/constants.ts +1 -0
- package/src/index.ts +17 -2
- package/src/logger-proxy.ts +24 -1
- package/src/metrics/MetricsManager.ts +1 -1
- package/src/metrics/behavioral-events.ts +94 -0
- package/src/metrics/constants.ts +37 -1
- package/src/services/AddressBook.ts +291 -0
- package/src/services/EntryPoint.ts +241 -0
- package/src/services/Queue.ts +277 -0
- package/src/services/config/constants.ts +42 -2
- package/src/services/config/index.ts +30 -30
- package/src/services/config/types.ts +59 -58
- package/src/services/core/GlobalTypes.ts +27 -0
- package/src/services/core/Utils.ts +215 -1
- package/src/services/core/aqm-reqs.ts +0 -5
- package/src/services/core/constants.ts +16 -0
- package/src/services/core/websocket/WebSocketManager.ts +0 -4
- package/src/services/task/TaskManager.ts +182 -9
- package/src/services/task/TaskUtils.ts +113 -0
- package/src/services/task/constants.ts +25 -0
- package/src/services/task/contact.ts +80 -0
- package/src/services/task/index.ts +497 -71
- package/src/services/task/types.ts +264 -20
- package/src/types.ts +180 -0
- package/src/utils/PageCache.ts +252 -0
- package/test/unit/spec/cc.ts +282 -85
- package/test/unit/spec/metrics/MetricsManager.ts +0 -1
- package/test/unit/spec/metrics/behavioral-events.ts +42 -0
- package/test/unit/spec/services/AddressBook.ts +332 -0
- package/test/unit/spec/services/EntryPoint.ts +259 -0
- package/test/unit/spec/services/Queue.ts +323 -0
- package/test/unit/spec/services/config/index.ts +279 -65
- package/test/unit/spec/services/core/Utils.ts +282 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +1 -3
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +0 -4
- package/test/unit/spec/services/task/TaskManager.ts +760 -2
- package/test/unit/spec/services/task/TaskUtils.ts +131 -0
- package/test/unit/spec/services/task/contact.ts +31 -1
- package/test/unit/spec/services/task/index.ts +873 -163
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
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 {
|
|
4
|
+
import {generateTaskErrorObject, calculateDestAgentId, calculateDestType} from '../core/Utils';
|
|
5
|
+
import {Failure} from '../core/GlobalTypes';
|
|
5
6
|
import {LoginOption} from '../../types';
|
|
6
7
|
import {TASK_FILE} from '../../constants';
|
|
7
|
-
import {METHODS} from './constants';
|
|
8
|
+
import {METHODS, KEYS_TO_NOT_DELETE} from './constants';
|
|
8
9
|
import routingContact from './contact';
|
|
9
10
|
import LoggerProxy from '../../logger-proxy';
|
|
10
11
|
import {
|
|
@@ -19,14 +20,12 @@ import {
|
|
|
19
20
|
ConsultEndPayload,
|
|
20
21
|
TransferPayLoad,
|
|
21
22
|
DESTINATION_TYPE,
|
|
22
|
-
CONSULT_TRANSFER_DESTINATION_TYPE,
|
|
23
23
|
ConsultTransferPayLoad,
|
|
24
24
|
MEDIA_CHANNEL,
|
|
25
25
|
} from './types';
|
|
26
26
|
import WebCallingService from '../WebCallingService';
|
|
27
27
|
import MetricsManager from '../../metrics/MetricsManager';
|
|
28
28
|
import {METRIC_EVENT_NAMES} from '../../metrics/constants';
|
|
29
|
-
import {Failure} from '../core/GlobalTypes';
|
|
30
29
|
import AutoWrapup from './AutoWrapup';
|
|
31
30
|
import {WrapupData} from '../config/types';
|
|
32
31
|
|
|
@@ -135,6 +134,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
135
134
|
public webCallMap: Record<TaskId, CallId>;
|
|
136
135
|
private wrapupData: WrapupData;
|
|
137
136
|
public autoWrapup?: AutoWrapup;
|
|
137
|
+
private agentId: string;
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* Creates a new Task instance which provides the following features:
|
|
@@ -147,7 +147,8 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
147
147
|
contact: ReturnType<typeof routingContact>,
|
|
148
148
|
webCallingService: WebCallingService,
|
|
149
149
|
data: TaskData,
|
|
150
|
-
wrapupData: WrapupData
|
|
150
|
+
wrapupData: WrapupData,
|
|
151
|
+
agentId: string
|
|
151
152
|
) {
|
|
152
153
|
super();
|
|
153
154
|
this.contact = contact;
|
|
@@ -158,6 +159,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
158
159
|
this.metricsManager = MetricsManager.getInstance();
|
|
159
160
|
this.registerWebCallListeners();
|
|
160
161
|
this.setupAutoWrapupTimer();
|
|
162
|
+
this.agentId = agentId;
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
/**
|
|
@@ -274,9 +276,24 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
274
276
|
* @private
|
|
275
277
|
*/
|
|
276
278
|
private reconcileData(oldData: TaskData, newData: TaskData): TaskData {
|
|
279
|
+
// Remove keys from oldData that are not in newData
|
|
280
|
+
Object.keys(oldData).forEach((key) => {
|
|
281
|
+
if (!(key in newData) && !KEYS_TO_NOT_DELETE.includes(key as string)) {
|
|
282
|
+
delete oldData[key];
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Merge or update keys from newData
|
|
277
287
|
Object.keys(newData).forEach((key) => {
|
|
278
|
-
if (
|
|
279
|
-
|
|
288
|
+
if (
|
|
289
|
+
newData[key] &&
|
|
290
|
+
typeof newData[key] === 'object' &&
|
|
291
|
+
!Array.isArray(newData[key]) &&
|
|
292
|
+
oldData[key] &&
|
|
293
|
+
typeof oldData[key] === 'object' &&
|
|
294
|
+
!Array.isArray(oldData[key])
|
|
295
|
+
) {
|
|
296
|
+
this.reconcileData(oldData[key], newData[key]);
|
|
280
297
|
} else {
|
|
281
298
|
oldData[key] = newData[key];
|
|
282
299
|
}
|
|
@@ -373,17 +390,25 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
373
390
|
|
|
374
391
|
return Promise.resolve(); // TODO: reject for extension as part of refactor
|
|
375
392
|
} catch (error) {
|
|
376
|
-
const
|
|
393
|
+
const err = generateTaskErrorObject(error, METHODS.ACCEPT, TASK_FILE);
|
|
394
|
+
const taskErrorProps = {
|
|
395
|
+
trackingId: err.data?.trackingId,
|
|
396
|
+
errorMessage: err.data?.message,
|
|
397
|
+
errorType: err.data?.errorType,
|
|
398
|
+
errorData: err.data?.errorData,
|
|
399
|
+
reasonCode: err.data?.reasonCode,
|
|
400
|
+
};
|
|
377
401
|
this.metricsManager.trackEvent(
|
|
378
402
|
METRIC_EVENT_NAMES.TASK_ACCEPT_FAILED,
|
|
379
403
|
{
|
|
380
404
|
taskId: this.data.interactionId,
|
|
381
405
|
error: error.toString(),
|
|
406
|
+
...taskErrorProps,
|
|
382
407
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details as Failure),
|
|
383
408
|
},
|
|
384
409
|
['operational', 'behavioral', 'business']
|
|
385
410
|
);
|
|
386
|
-
throw
|
|
411
|
+
throw err;
|
|
387
412
|
}
|
|
388
413
|
}
|
|
389
414
|
|
|
@@ -422,8 +447,8 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
422
447
|
|
|
423
448
|
return Promise.resolve();
|
|
424
449
|
} catch (error) {
|
|
425
|
-
const
|
|
426
|
-
throw
|
|
450
|
+
const err = generateTaskErrorObject(error, METHODS.TOGGLE_MUTE, TASK_FILE);
|
|
451
|
+
throw err;
|
|
427
452
|
}
|
|
428
453
|
}
|
|
429
454
|
|
|
@@ -470,17 +495,25 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
470
495
|
|
|
471
496
|
return Promise.resolve();
|
|
472
497
|
} catch (error) {
|
|
473
|
-
const
|
|
498
|
+
const err = generateTaskErrorObject(error, METHODS.DECLINE, TASK_FILE);
|
|
499
|
+
const taskErrorProps = {
|
|
500
|
+
trackingId: err.data?.trackingId,
|
|
501
|
+
errorMessage: err.data?.message,
|
|
502
|
+
errorType: err.data?.errorType,
|
|
503
|
+
errorData: err.data?.errorData,
|
|
504
|
+
reasonCode: err.data?.reasonCode,
|
|
505
|
+
};
|
|
474
506
|
this.metricsManager.trackEvent(
|
|
475
507
|
METRIC_EVENT_NAMES.TASK_DECLINE_FAILED,
|
|
476
508
|
{
|
|
477
509
|
taskId: this.data.interactionId,
|
|
478
510
|
error: error.toString(),
|
|
511
|
+
...taskErrorProps,
|
|
479
512
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
480
513
|
},
|
|
481
514
|
['operational', 'behavioral']
|
|
482
515
|
);
|
|
483
|
-
throw
|
|
516
|
+
throw err;
|
|
484
517
|
}
|
|
485
518
|
}
|
|
486
519
|
|
|
@@ -488,6 +521,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
488
521
|
* Puts the current task/interaction on hold.
|
|
489
522
|
* Emits task:hold event when successful. For voice tasks, this mutes the audio.
|
|
490
523
|
*
|
|
524
|
+
* @param mediaResourceId - Optional media resource ID to use for the hold operation. If not provided, uses the task's current mediaResourceId
|
|
491
525
|
* @returns Promise<TaskResponse>
|
|
492
526
|
* @throws Error if hold operation fails
|
|
493
527
|
* @example
|
|
@@ -508,9 +542,17 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
508
542
|
* console.error('Failed to place task on hold:', error);
|
|
509
543
|
* // Handle error (e.g., show error message, reset UI state)
|
|
510
544
|
* }
|
|
545
|
+
*
|
|
546
|
+
* // Place task on hold with custom mediaResourceId
|
|
547
|
+
* try {
|
|
548
|
+
* await task.hold('custom-media-resource-id');
|
|
549
|
+
* console.log('Successfully placed task on hold with custom mediaResourceId');
|
|
550
|
+
* } catch (error) {
|
|
551
|
+
* console.error('Failed to place task on hold:', error);
|
|
552
|
+
* }
|
|
511
553
|
* ```
|
|
512
554
|
*/
|
|
513
|
-
public async hold(): Promise<TaskResponse> {
|
|
555
|
+
public async hold(mediaResourceId?: string): Promise<TaskResponse> {
|
|
514
556
|
try {
|
|
515
557
|
LoggerProxy.info(`Holding task`, {
|
|
516
558
|
module: TASK_FILE,
|
|
@@ -523,9 +565,11 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
523
565
|
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
524
566
|
]);
|
|
525
567
|
|
|
568
|
+
const effectiveMediaResourceId = mediaResourceId ?? this.data.mediaResourceId;
|
|
569
|
+
|
|
526
570
|
const response = await this.contact.hold({
|
|
527
571
|
interactionId: this.data.interactionId,
|
|
528
|
-
data: {mediaResourceId:
|
|
572
|
+
data: {mediaResourceId: effectiveMediaResourceId},
|
|
529
573
|
});
|
|
530
574
|
|
|
531
575
|
this.metricsManager.trackEvent(
|
|
@@ -533,7 +577,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
533
577
|
{
|
|
534
578
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
535
579
|
taskId: this.data.interactionId,
|
|
536
|
-
mediaResourceId:
|
|
580
|
+
mediaResourceId: effectiveMediaResourceId,
|
|
537
581
|
},
|
|
538
582
|
['operational', 'behavioral']
|
|
539
583
|
);
|
|
@@ -547,18 +591,28 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
547
591
|
|
|
548
592
|
return response;
|
|
549
593
|
} catch (error) {
|
|
550
|
-
const
|
|
594
|
+
const err = generateTaskErrorObject(error, METHODS.HOLD, TASK_FILE);
|
|
595
|
+
const taskErrorProps = {
|
|
596
|
+
trackingId: err.data?.trackingId,
|
|
597
|
+
errorMessage: err.data?.message,
|
|
598
|
+
errorType: err.data?.errorType,
|
|
599
|
+
errorData: err.data?.errorData,
|
|
600
|
+
reasonCode: err.data?.reasonCode,
|
|
601
|
+
};
|
|
602
|
+
const effectiveMediaResourceId = mediaResourceId ?? this.data.mediaResourceId;
|
|
603
|
+
|
|
551
604
|
this.metricsManager.trackEvent(
|
|
552
605
|
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
553
606
|
{
|
|
554
607
|
taskId: this.data.interactionId,
|
|
555
|
-
mediaResourceId:
|
|
608
|
+
mediaResourceId: effectiveMediaResourceId,
|
|
556
609
|
error: error.toString(),
|
|
610
|
+
...taskErrorProps,
|
|
557
611
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
558
612
|
},
|
|
559
613
|
['operational', 'behavioral']
|
|
560
614
|
);
|
|
561
|
-
throw
|
|
615
|
+
throw err;
|
|
562
616
|
}
|
|
563
617
|
}
|
|
564
618
|
|
|
@@ -566,6 +620,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
566
620
|
* Resumes the task/interaction that was previously put on hold.
|
|
567
621
|
* Emits task:resume event when successful. For voice tasks, this restores the audio.
|
|
568
622
|
*
|
|
623
|
+
* @param mediaResourceId - Optional media resource ID to use for the resume operation. If not provided, uses the task's current mediaResourceId from interaction media
|
|
569
624
|
* @returns Promise<TaskResponse>
|
|
570
625
|
* @throws Error if resume operation fails
|
|
571
626
|
* @example
|
|
@@ -586,9 +641,17 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
586
641
|
* console.error('Failed to resume task:', error);
|
|
587
642
|
* // Handle error (e.g., show error message)
|
|
588
643
|
* }
|
|
644
|
+
*
|
|
645
|
+
* // Resume task from hold with custom mediaResourceId
|
|
646
|
+
* try {
|
|
647
|
+
* await task.resume('custom-media-resource-id');
|
|
648
|
+
* console.log('Successfully resumed task from hold with custom mediaResourceId');
|
|
649
|
+
* } catch (error) {
|
|
650
|
+
* console.error('Failed to resume task:', error);
|
|
651
|
+
* }
|
|
589
652
|
* ```
|
|
590
653
|
*/
|
|
591
|
-
public async resume(): Promise<TaskResponse> {
|
|
654
|
+
public async resume(mediaResourceId?: string): Promise<TaskResponse> {
|
|
592
655
|
try {
|
|
593
656
|
LoggerProxy.info(`Resuming task`, {
|
|
594
657
|
module: TASK_FILE,
|
|
@@ -596,7 +659,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
596
659
|
interactionId: this.data.interactionId,
|
|
597
660
|
});
|
|
598
661
|
const {mainInteractionId} = this.data.interaction;
|
|
599
|
-
const
|
|
662
|
+
const defaultMediaResourceId =
|
|
663
|
+
this.data.interaction.media[mainInteractionId]?.mediaResourceId;
|
|
664
|
+
const effectiveMediaResourceId = mediaResourceId ?? defaultMediaResourceId;
|
|
600
665
|
|
|
601
666
|
this.metricsManager.timeEvent([
|
|
602
667
|
METRIC_EVENT_NAMES.TASK_RESUME_SUCCESS,
|
|
@@ -605,7 +670,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
605
670
|
|
|
606
671
|
const response = await this.contact.unHold({
|
|
607
672
|
interactionId: this.data.interactionId,
|
|
608
|
-
data: {mediaResourceId},
|
|
673
|
+
data: {mediaResourceId: effectiveMediaResourceId},
|
|
609
674
|
});
|
|
610
675
|
|
|
611
676
|
this.metricsManager.trackEvent(
|
|
@@ -613,7 +678,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
613
678
|
{
|
|
614
679
|
taskId: this.data.interactionId,
|
|
615
680
|
mainInteractionId,
|
|
616
|
-
mediaResourceId,
|
|
681
|
+
mediaResourceId: effectiveMediaResourceId,
|
|
617
682
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
618
683
|
},
|
|
619
684
|
['operational', 'behavioral']
|
|
@@ -628,21 +693,32 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
628
693
|
|
|
629
694
|
return response;
|
|
630
695
|
} catch (error) {
|
|
631
|
-
const
|
|
696
|
+
const err = generateTaskErrorObject(error, METHODS.RESUME, TASK_FILE);
|
|
632
697
|
const mainInteractionId = this.data.interaction?.mainInteractionId;
|
|
698
|
+
const defaultMediaResourceId = mainInteractionId
|
|
699
|
+
? this.data.interaction.media[mainInteractionId]?.mediaResourceId
|
|
700
|
+
: '';
|
|
701
|
+
const effectiveMediaResourceId = mediaResourceId ?? defaultMediaResourceId;
|
|
702
|
+
|
|
703
|
+
const taskErrorProps = {
|
|
704
|
+
trackingId: err.data?.trackingId,
|
|
705
|
+
errorMessage: err.data?.message,
|
|
706
|
+
errorType: err.data?.errorType,
|
|
707
|
+
errorData: err.data?.errorData,
|
|
708
|
+
reasonCode: err.data?.reasonCode,
|
|
709
|
+
};
|
|
633
710
|
this.metricsManager.trackEvent(
|
|
634
711
|
METRIC_EVENT_NAMES.TASK_RESUME_FAILED,
|
|
635
712
|
{
|
|
636
713
|
taskId: this.data.interactionId,
|
|
637
714
|
mainInteractionId,
|
|
638
|
-
mediaResourceId:
|
|
639
|
-
|
|
640
|
-
: '',
|
|
715
|
+
mediaResourceId: effectiveMediaResourceId,
|
|
716
|
+
...taskErrorProps,
|
|
641
717
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
642
718
|
},
|
|
643
719
|
['operational', 'behavioral']
|
|
644
720
|
);
|
|
645
|
-
throw
|
|
721
|
+
throw err;
|
|
646
722
|
}
|
|
647
723
|
}
|
|
648
724
|
|
|
@@ -722,16 +798,24 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
722
798
|
|
|
723
799
|
return response;
|
|
724
800
|
} catch (error) {
|
|
725
|
-
const
|
|
801
|
+
const err = generateTaskErrorObject(error, METHODS.END, TASK_FILE);
|
|
802
|
+
const taskErrorProps = {
|
|
803
|
+
trackingId: err.data?.trackingId,
|
|
804
|
+
errorMessage: err.data?.message,
|
|
805
|
+
errorType: err.data?.errorType,
|
|
806
|
+
errorData: err.data?.errorData,
|
|
807
|
+
reasonCode: err.data?.reasonCode,
|
|
808
|
+
};
|
|
726
809
|
this.metricsManager.trackEvent(
|
|
727
810
|
METRIC_EVENT_NAMES.TASK_END_FAILED,
|
|
728
811
|
{
|
|
729
812
|
taskId: this.data.interactionId,
|
|
813
|
+
...taskErrorProps,
|
|
730
814
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
731
815
|
},
|
|
732
816
|
['operational', 'behavioral', 'business']
|
|
733
817
|
);
|
|
734
|
-
throw
|
|
818
|
+
throw err;
|
|
735
819
|
}
|
|
736
820
|
}
|
|
737
821
|
|
|
@@ -826,18 +910,26 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
826
910
|
|
|
827
911
|
return response;
|
|
828
912
|
} catch (error) {
|
|
829
|
-
const
|
|
913
|
+
const err = generateTaskErrorObject(error, METHODS.WRAPUP, TASK_FILE);
|
|
914
|
+
const taskErrorProps = {
|
|
915
|
+
trackingId: err.data?.trackingId,
|
|
916
|
+
errorMessage: err.data?.message,
|
|
917
|
+
errorType: err.data?.errorType,
|
|
918
|
+
errorData: err.data?.errorData,
|
|
919
|
+
reasonCode: err.data?.reasonCode,
|
|
920
|
+
};
|
|
830
921
|
this.metricsManager.trackEvent(
|
|
831
922
|
METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED,
|
|
832
923
|
{
|
|
833
924
|
taskId: this.data.interactionId,
|
|
834
925
|
wrapUpCode: wrapupPayload.auxCodeId,
|
|
835
926
|
wrapUpReason: wrapupPayload.wrapUpReason,
|
|
927
|
+
...taskErrorProps,
|
|
836
928
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
837
929
|
},
|
|
838
930
|
['operational', 'behavioral', 'business']
|
|
839
931
|
);
|
|
840
|
-
throw
|
|
932
|
+
throw err;
|
|
841
933
|
}
|
|
842
934
|
}
|
|
843
935
|
|
|
@@ -906,17 +998,25 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
906
998
|
|
|
907
999
|
return result;
|
|
908
1000
|
} catch (error) {
|
|
909
|
-
const
|
|
1001
|
+
const err = generateTaskErrorObject(error, METHODS.PAUSE_RECORDING, TASK_FILE);
|
|
1002
|
+
const taskErrorProps = {
|
|
1003
|
+
trackingId: err.data?.trackingId,
|
|
1004
|
+
errorMessage: err.data?.message,
|
|
1005
|
+
errorType: err.data?.errorType,
|
|
1006
|
+
errorData: err.data?.errorData,
|
|
1007
|
+
reasonCode: err.data?.reasonCode,
|
|
1008
|
+
};
|
|
910
1009
|
this.metricsManager.trackEvent(
|
|
911
1010
|
METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED,
|
|
912
1011
|
{
|
|
913
1012
|
taskId: this.data.interactionId,
|
|
914
1013
|
error: error.toString(),
|
|
1014
|
+
...taskErrorProps,
|
|
915
1015
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
916
1016
|
},
|
|
917
1017
|
['operational', 'behavioral', 'business']
|
|
918
1018
|
);
|
|
919
|
-
throw
|
|
1019
|
+
throw err;
|
|
920
1020
|
}
|
|
921
1021
|
}
|
|
922
1022
|
|
|
@@ -997,17 +1097,25 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
997
1097
|
|
|
998
1098
|
return result;
|
|
999
1099
|
} catch (error) {
|
|
1000
|
-
const
|
|
1100
|
+
const err = generateTaskErrorObject(error, METHODS.RESUME_RECORDING, TASK_FILE);
|
|
1101
|
+
const taskErrorProps = {
|
|
1102
|
+
trackingId: err.data?.trackingId,
|
|
1103
|
+
errorMessage: err.data?.message,
|
|
1104
|
+
errorType: err.data?.errorType,
|
|
1105
|
+
errorData: err.data?.errorData,
|
|
1106
|
+
reasonCode: err.data?.reasonCode,
|
|
1107
|
+
};
|
|
1001
1108
|
this.metricsManager.trackEvent(
|
|
1002
1109
|
METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED,
|
|
1003
1110
|
{
|
|
1004
1111
|
taskId: this.data.interactionId,
|
|
1005
1112
|
error: error.toString(),
|
|
1113
|
+
...taskErrorProps,
|
|
1006
1114
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1007
1115
|
},
|
|
1008
1116
|
['operational', 'behavioral', 'business']
|
|
1009
1117
|
);
|
|
1010
|
-
throw
|
|
1118
|
+
throw err;
|
|
1011
1119
|
}
|
|
1012
1120
|
}
|
|
1013
1121
|
|
|
@@ -1082,7 +1190,14 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1082
1190
|
|
|
1083
1191
|
return result;
|
|
1084
1192
|
} catch (error) {
|
|
1085
|
-
const
|
|
1193
|
+
const err = generateTaskErrorObject(error, METHODS.CONSULT, TASK_FILE);
|
|
1194
|
+
const taskErrorProps = {
|
|
1195
|
+
trackingId: err.data?.trackingId,
|
|
1196
|
+
errorMessage: err.data?.message,
|
|
1197
|
+
errorType: err.data?.errorType,
|
|
1198
|
+
errorData: err.data?.errorData,
|
|
1199
|
+
reasonCode: err.data?.reasonCode,
|
|
1200
|
+
};
|
|
1086
1201
|
this.metricsManager.trackEvent(
|
|
1087
1202
|
METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED,
|
|
1088
1203
|
{
|
|
@@ -1090,11 +1205,12 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1090
1205
|
destination: consultPayload.to,
|
|
1091
1206
|
destinationType: consultPayload.destinationType,
|
|
1092
1207
|
error: error.toString(),
|
|
1208
|
+
...taskErrorProps,
|
|
1093
1209
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1094
1210
|
},
|
|
1095
1211
|
['operational', 'behavioral', 'business']
|
|
1096
1212
|
);
|
|
1097
|
-
throw
|
|
1213
|
+
throw err;
|
|
1098
1214
|
}
|
|
1099
1215
|
}
|
|
1100
1216
|
|
|
@@ -1167,17 +1283,25 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1167
1283
|
|
|
1168
1284
|
return result;
|
|
1169
1285
|
} catch (error) {
|
|
1170
|
-
const
|
|
1286
|
+
const err = generateTaskErrorObject(error, METHODS.END_CONSULT, TASK_FILE);
|
|
1287
|
+
const taskErrorProps = {
|
|
1288
|
+
trackingId: err.data?.trackingId,
|
|
1289
|
+
errorMessage: err.data?.message,
|
|
1290
|
+
errorType: err.data?.errorType,
|
|
1291
|
+
errorData: err.data?.errorData,
|
|
1292
|
+
reasonCode: err.data?.reasonCode,
|
|
1293
|
+
};
|
|
1171
1294
|
this.metricsManager.trackEvent(
|
|
1172
1295
|
METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED,
|
|
1173
1296
|
{
|
|
1174
1297
|
taskId: this.data.interactionId,
|
|
1175
1298
|
error: error.toString(),
|
|
1299
|
+
...taskErrorProps,
|
|
1176
1300
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1177
1301
|
},
|
|
1178
1302
|
['operational', 'behavioral', 'business']
|
|
1179
1303
|
);
|
|
1180
|
-
throw
|
|
1304
|
+
throw err;
|
|
1181
1305
|
}
|
|
1182
1306
|
}
|
|
1183
1307
|
|
|
@@ -1258,7 +1382,14 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1258
1382
|
|
|
1259
1383
|
return result;
|
|
1260
1384
|
} catch (error) {
|
|
1261
|
-
const
|
|
1385
|
+
const err = generateTaskErrorObject(error, METHODS.TRANSFER, TASK_FILE);
|
|
1386
|
+
const taskErrorProps = {
|
|
1387
|
+
trackingId: err.data?.trackingId,
|
|
1388
|
+
errorMessage: err.data?.message,
|
|
1389
|
+
errorType: err.data?.errorType,
|
|
1390
|
+
errorData: err.data?.errorData,
|
|
1391
|
+
reasonCode: err.data?.reasonCode,
|
|
1392
|
+
};
|
|
1262
1393
|
this.metricsManager.trackEvent(
|
|
1263
1394
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
1264
1395
|
{
|
|
@@ -1267,11 +1398,12 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1267
1398
|
destinationType: transferPayload.destinationType,
|
|
1268
1399
|
isConsultTransfer: false,
|
|
1269
1400
|
error: error.toString(),
|
|
1401
|
+
...taskErrorProps,
|
|
1270
1402
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1271
1403
|
},
|
|
1272
1404
|
['operational', 'behavioral', 'business']
|
|
1273
1405
|
);
|
|
1274
|
-
throw
|
|
1406
|
+
throw err;
|
|
1275
1407
|
}
|
|
1276
1408
|
}
|
|
1277
1409
|
|
|
@@ -1308,68 +1440,362 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1308
1440
|
* ```
|
|
1309
1441
|
*/
|
|
1310
1442
|
public async consultTransfer(
|
|
1311
|
-
consultTransferPayload
|
|
1443
|
+
consultTransferPayload?: ConsultTransferPayLoad
|
|
1312
1444
|
): Promise<TaskResponse> {
|
|
1313
|
-
|
|
1314
|
-
|
|
1445
|
+
// Get the destination agent ID using custom logic from participants data
|
|
1446
|
+
const destAgentId = calculateDestAgentId(this.data.interaction, this.agentId);
|
|
1447
|
+
|
|
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
|
+
}
|
|
1452
|
+
|
|
1453
|
+
LoggerProxy.info(
|
|
1454
|
+
`Initiating consult transfer to ${consultTransferPayload?.to || destAgentId}`,
|
|
1455
|
+
{
|
|
1315
1456
|
module: TASK_FILE,
|
|
1316
1457
|
method: METHODS.CONSULT_TRANSFER,
|
|
1317
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 {
|
|
1470
|
+
const result = await this.contact.consultTransfer({
|
|
1471
|
+
interactionId: this.data.interactionId,
|
|
1472
|
+
data: consultTransferRequest,
|
|
1318
1473
|
});
|
|
1319
1474
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1475
|
+
this.metricsManager.trackEvent(
|
|
1476
|
+
METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS,
|
|
1477
|
+
{
|
|
1478
|
+
taskId: this.data.interactionId,
|
|
1479
|
+
destination: consultTransferRequest.to,
|
|
1480
|
+
destinationType: consultTransferRequest.destinationType,
|
|
1481
|
+
isConsultTransfer: true,
|
|
1482
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
|
|
1483
|
+
},
|
|
1484
|
+
['operational', 'behavioral', 'business']
|
|
1485
|
+
);
|
|
1486
|
+
|
|
1487
|
+
LoggerProxy.log(
|
|
1488
|
+
`Consult transfer completed successfully to ${consultTransferPayload?.to || destAgentId}`,
|
|
1489
|
+
{
|
|
1490
|
+
module: TASK_FILE,
|
|
1491
|
+
method: METHODS.CONSULT_TRANSFER,
|
|
1492
|
+
trackingId: result.trackingId,
|
|
1493
|
+
interactionId: this.data.interactionId,
|
|
1324
1494
|
}
|
|
1495
|
+
);
|
|
1496
|
+
|
|
1497
|
+
return result;
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
const err = generateTaskErrorObject(error, METHODS.CONSULT_TRANSFER, TASK_FILE);
|
|
1500
|
+
const taskErrorProps = {
|
|
1501
|
+
trackingId: err.data?.trackingId,
|
|
1502
|
+
errorMessage: err.data?.message,
|
|
1503
|
+
errorType: err.data?.errorType,
|
|
1504
|
+
errorData: err.data?.errorData,
|
|
1505
|
+
reasonCode: err.data?.reasonCode,
|
|
1506
|
+
};
|
|
1507
|
+
this.metricsManager.trackEvent(
|
|
1508
|
+
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
1509
|
+
{
|
|
1510
|
+
taskId: this.data.interactionId,
|
|
1511
|
+
destination: destAgentId || '',
|
|
1512
|
+
destinationType: destType,
|
|
1513
|
+
isConsultTransfer: true,
|
|
1514
|
+
error: error.toString(),
|
|
1515
|
+
...taskErrorProps,
|
|
1516
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1517
|
+
},
|
|
1518
|
+
['operational', 'behavioral', 'business']
|
|
1519
|
+
);
|
|
1520
|
+
throw err;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
/**
|
|
1525
|
+
* Starts a consultation conference by merging the consultation call with the main call
|
|
1526
|
+
*
|
|
1527
|
+
* Creates a three-way conference between the agent, customer, and consulted party
|
|
1528
|
+
* Extracts required consultation data from the current task data
|
|
1529
|
+
* On success, emits a `task:conferenceStarted` event
|
|
1530
|
+
*
|
|
1531
|
+
* @returns Promise<TaskResponse> - Response from the consultation conference API
|
|
1532
|
+
* @throws Error if the operation fails or if consultation data is invalid
|
|
1533
|
+
*
|
|
1534
|
+
* @example
|
|
1535
|
+
* ```typescript
|
|
1536
|
+
* try {
|
|
1537
|
+
* await task.consultConference();
|
|
1538
|
+
* console.log('Conference started successfully');
|
|
1539
|
+
* } catch (error) {
|
|
1540
|
+
* console.error('Failed to start conference:', error);
|
|
1541
|
+
* }
|
|
1542
|
+
* ```
|
|
1543
|
+
*/
|
|
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
|
+
|
|
1558
|
+
// Extract consultation conference data from task data (used in both try and catch)
|
|
1559
|
+
const consultationData = {
|
|
1560
|
+
agentId: this.agentId,
|
|
1561
|
+
to: destAgentId,
|
|
1562
|
+
destinationType: destAgentType || this.data.destinationType || 'agent',
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1565
|
+
try {
|
|
1566
|
+
LoggerProxy.info(`Initiating consult conference to ${destAgentId}`, {
|
|
1567
|
+
module: TASK_FILE,
|
|
1568
|
+
method: METHODS.CONSULT_CONFERENCE,
|
|
1569
|
+
interactionId: this.data.interactionId,
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
const response = await this.contact.consultConference({
|
|
1573
|
+
interactionId: this.data.interactionId,
|
|
1574
|
+
data: consultationData,
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
// Track success metrics (following consultTransfer pattern)
|
|
1578
|
+
this.metricsManager.trackEvent(
|
|
1579
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS,
|
|
1580
|
+
{
|
|
1581
|
+
taskId: this.data.interactionId,
|
|
1582
|
+
destination: consultationData.to,
|
|
1583
|
+
destinationType: consultationData.destinationType,
|
|
1584
|
+
agentId: consultationData.agentId,
|
|
1585
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1586
|
+
},
|
|
1587
|
+
['operational', 'behavioral', 'business']
|
|
1588
|
+
);
|
|
1589
|
+
|
|
1590
|
+
LoggerProxy.log(`Consult conference started successfully`, {
|
|
1591
|
+
module: TASK_FILE,
|
|
1592
|
+
method: METHODS.CONSULT_CONFERENCE,
|
|
1593
|
+
interactionId: this.data.interactionId,
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
return response;
|
|
1597
|
+
} catch (error) {
|
|
1598
|
+
const err = generateTaskErrorObject(error, METHODS.CONSULT_CONFERENCE, TASK_FILE);
|
|
1599
|
+
const taskErrorProps = {
|
|
1600
|
+
trackingId: err.data?.trackingId,
|
|
1601
|
+
errorMessage: err.data?.message,
|
|
1602
|
+
errorType: err.data?.errorType,
|
|
1603
|
+
errorData: err.data?.errorData,
|
|
1604
|
+
reasonCode: err.data?.reasonCode,
|
|
1605
|
+
};
|
|
1606
|
+
|
|
1607
|
+
this.metricsManager.trackEvent(
|
|
1608
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED,
|
|
1609
|
+
{
|
|
1610
|
+
taskId: this.data.interactionId,
|
|
1611
|
+
destination: consultationData.to,
|
|
1612
|
+
destinationType: consultationData.destinationType,
|
|
1613
|
+
agentId: consultationData.agentId,
|
|
1614
|
+
error: error.toString(),
|
|
1615
|
+
...taskErrorProps,
|
|
1616
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1617
|
+
},
|
|
1618
|
+
['operational', 'behavioral', 'business']
|
|
1619
|
+
);
|
|
1620
|
+
|
|
1621
|
+
LoggerProxy.error(`Failed to start consult conference`, {
|
|
1622
|
+
module: TASK_FILE,
|
|
1623
|
+
method: METHODS.CONSULT_CONFERENCE,
|
|
1624
|
+
interactionId: this.data.interactionId,
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
throw err;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
/**
|
|
1632
|
+
* Exits the current conference by removing the agent from the conference call
|
|
1633
|
+
*
|
|
1634
|
+
* Exits the agent from the conference, leaving the customer and consulted party connected
|
|
1635
|
+
* On success, emits a `task:conferenceEnded` event
|
|
1636
|
+
*
|
|
1637
|
+
* @returns Promise<TaskResponse> - Response from the conference exit API
|
|
1638
|
+
* @throws Error if the operation fails or if no active conference exists
|
|
1639
|
+
*
|
|
1640
|
+
* @example
|
|
1641
|
+
* ```typescript
|
|
1642
|
+
* try {
|
|
1643
|
+
* await task.exitConference();
|
|
1644
|
+
* console.log('Successfully exited conference');
|
|
1645
|
+
* } catch (error) {
|
|
1646
|
+
* console.error('Failed to exit conference:', error);
|
|
1647
|
+
* }
|
|
1648
|
+
* ```
|
|
1649
|
+
*/
|
|
1650
|
+
public async exitConference(): Promise<TaskResponse> {
|
|
1651
|
+
try {
|
|
1652
|
+
LoggerProxy.info(`Exiting consult conference`, {
|
|
1653
|
+
module: TASK_FILE,
|
|
1654
|
+
method: METHODS.EXIT_CONFERENCE,
|
|
1655
|
+
interactionId: this.data.interactionId,
|
|
1656
|
+
});
|
|
1325
1657
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
destinationType: CONSULT_TRANSFER_DESTINATION_TYPE.AGENT,
|
|
1330
|
-
};
|
|
1658
|
+
// Validate that interaction ID exists
|
|
1659
|
+
if (!this.data.interactionId) {
|
|
1660
|
+
throw new Error('Invalid interaction ID');
|
|
1331
1661
|
}
|
|
1332
1662
|
|
|
1333
|
-
const
|
|
1663
|
+
const response = await this.contact.exitConference({
|
|
1334
1664
|
interactionId: this.data.interactionId,
|
|
1335
|
-
data: consultTransferPayload,
|
|
1336
1665
|
});
|
|
1337
1666
|
|
|
1667
|
+
// Track success metrics (following consultTransfer pattern)
|
|
1338
1668
|
this.metricsManager.trackEvent(
|
|
1339
|
-
METRIC_EVENT_NAMES.
|
|
1669
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_END_SUCCESS,
|
|
1340
1670
|
{
|
|
1341
1671
|
taskId: this.data.interactionId,
|
|
1342
|
-
|
|
1343
|
-
destinationType: consultTransferPayload.destinationType,
|
|
1344
|
-
isConsultTransfer: true,
|
|
1345
|
-
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
|
|
1672
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1346
1673
|
},
|
|
1347
1674
|
['operational', 'behavioral', 'business']
|
|
1348
1675
|
);
|
|
1349
1676
|
|
|
1350
|
-
LoggerProxy.log(`Consult
|
|
1677
|
+
LoggerProxy.log(`Consult conference exited successfully`, {
|
|
1351
1678
|
module: TASK_FILE,
|
|
1352
|
-
method: METHODS.
|
|
1353
|
-
trackingId: result.trackingId,
|
|
1679
|
+
method: METHODS.EXIT_CONFERENCE,
|
|
1354
1680
|
interactionId: this.data.interactionId,
|
|
1355
1681
|
});
|
|
1356
1682
|
|
|
1357
|
-
return
|
|
1683
|
+
return response;
|
|
1358
1684
|
} catch (error) {
|
|
1359
|
-
const
|
|
1685
|
+
const err = generateTaskErrorObject(error, METHODS.EXIT_CONFERENCE, TASK_FILE);
|
|
1686
|
+
const taskErrorProps = {
|
|
1687
|
+
trackingId: err.data?.trackingId,
|
|
1688
|
+
errorMessage: err.data?.message,
|
|
1689
|
+
errorType: err.data?.errorType,
|
|
1690
|
+
errorData: err.data?.errorData,
|
|
1691
|
+
reasonCode: err.data?.reasonCode,
|
|
1692
|
+
};
|
|
1693
|
+
|
|
1694
|
+
// Track failure metrics (following consultTransfer pattern)
|
|
1360
1695
|
this.metricsManager.trackEvent(
|
|
1361
|
-
METRIC_EVENT_NAMES.
|
|
1696
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_END_FAILED,
|
|
1697
|
+
{
|
|
1698
|
+
taskId: this.data.interactionId,
|
|
1699
|
+
error: error.toString(),
|
|
1700
|
+
...taskErrorProps,
|
|
1701
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1702
|
+
},
|
|
1703
|
+
['operational', 'behavioral', 'business']
|
|
1704
|
+
);
|
|
1705
|
+
|
|
1706
|
+
LoggerProxy.error(`Failed to exit consult conference`, {
|
|
1707
|
+
module: TASK_FILE,
|
|
1708
|
+
method: METHODS.EXIT_CONFERENCE,
|
|
1709
|
+
interactionId: this.data.interactionId,
|
|
1710
|
+
});
|
|
1711
|
+
|
|
1712
|
+
throw err;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
/**
|
|
1717
|
+
* Transfers the current conference to another agent
|
|
1718
|
+
*
|
|
1719
|
+
* Moves the entire conference (including all participants) to a new agent,
|
|
1720
|
+
* while the current agent exits and goes to wrapup
|
|
1721
|
+
* On success, the current agent receives `task:conferenceEnded` event
|
|
1722
|
+
*
|
|
1723
|
+
* @returns Promise<TaskResponse> - Response from the conference transfer API
|
|
1724
|
+
* @throws Error if the operation fails or if no active conference exists
|
|
1725
|
+
*
|
|
1726
|
+
* @example
|
|
1727
|
+
* ```typescript
|
|
1728
|
+
* try {
|
|
1729
|
+
* await task.transferConference();
|
|
1730
|
+
* console.log('Conference transferred successfully');
|
|
1731
|
+
* } catch (error) {
|
|
1732
|
+
* console.error('Failed to transfer conference:', error);
|
|
1733
|
+
* }
|
|
1734
|
+
* ```
|
|
1735
|
+
*/
|
|
1736
|
+
public async transferConference(): Promise<TaskResponse> {
|
|
1737
|
+
try {
|
|
1738
|
+
LoggerProxy.info(`Transferring conference`, {
|
|
1739
|
+
module: TASK_FILE,
|
|
1740
|
+
method: METHODS.TRANSFER_CONFERENCE,
|
|
1741
|
+
interactionId: this.data.interactionId,
|
|
1742
|
+
});
|
|
1743
|
+
|
|
1744
|
+
// Validate that interaction ID exists
|
|
1745
|
+
if (!this.data.interactionId) {
|
|
1746
|
+
throw new Error('Invalid interaction ID');
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
const response = await this.contact.conferenceTransfer({
|
|
1750
|
+
interactionId: this.data.interactionId,
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
// Track success metrics (following consultTransfer pattern)
|
|
1754
|
+
this.metricsManager.trackEvent(
|
|
1755
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS,
|
|
1756
|
+
{
|
|
1757
|
+
taskId: this.data.interactionId,
|
|
1758
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1759
|
+
},
|
|
1760
|
+
['operational', 'behavioral', 'business']
|
|
1761
|
+
);
|
|
1762
|
+
|
|
1763
|
+
LoggerProxy.log(`Conference transferred successfully`, {
|
|
1764
|
+
module: TASK_FILE,
|
|
1765
|
+
method: METHODS.TRANSFER_CONFERENCE,
|
|
1766
|
+
interactionId: this.data.interactionId,
|
|
1767
|
+
});
|
|
1768
|
+
|
|
1769
|
+
return response;
|
|
1770
|
+
} catch (error) {
|
|
1771
|
+
const err = generateTaskErrorObject(error, METHODS.TRANSFER_CONFERENCE, TASK_FILE);
|
|
1772
|
+
const taskErrorProps = {
|
|
1773
|
+
trackingId: err.data?.trackingId,
|
|
1774
|
+
errorMessage: err.data?.message,
|
|
1775
|
+
errorType: err.data?.errorType,
|
|
1776
|
+
errorData: err.data?.errorData,
|
|
1777
|
+
reasonCode: err.data?.reasonCode,
|
|
1778
|
+
};
|
|
1779
|
+
|
|
1780
|
+
// Track failure metrics (following consultTransfer pattern)
|
|
1781
|
+
this.metricsManager.trackEvent(
|
|
1782
|
+
METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED,
|
|
1362
1783
|
{
|
|
1363
1784
|
taskId: this.data.interactionId,
|
|
1364
|
-
destination: consultTransferPayload.to,
|
|
1365
|
-
destinationType: consultTransferPayload.destinationType,
|
|
1366
|
-
isConsultTransfer: true,
|
|
1367
1785
|
error: error.toString(),
|
|
1786
|
+
...taskErrorProps,
|
|
1368
1787
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
1369
1788
|
},
|
|
1370
1789
|
['operational', 'behavioral', 'business']
|
|
1371
1790
|
);
|
|
1372
|
-
|
|
1791
|
+
|
|
1792
|
+
LoggerProxy.error(`Failed to transfer conference`, {
|
|
1793
|
+
module: TASK_FILE,
|
|
1794
|
+
method: METHODS.TRANSFER_CONFERENCE,
|
|
1795
|
+
interactionId: this.data.interactionId,
|
|
1796
|
+
});
|
|
1797
|
+
|
|
1798
|
+
throw err;
|
|
1373
1799
|
}
|
|
1374
1800
|
}
|
|
1375
1801
|
}
|