При звонках в колл-центр компаний часто приходится сталкиваться с большим временем ожидания на линии, многие из нас слушали надоедливую мелодию в течение десятков минут хотя бы раз в жизни. Самое интересное заключается в том, что это совершенно невыгодно компании в колл-центр которой вы звоните, особенно если вы звоните на номер 8-800. К счастью, уже давно придуман способ, позволяющий решить данную проблему — это callback или обратный вызов. Суть этого способа очень простая: позвонившему предлагают отключиться от колл-центра при этом его номер так и остается в очереди на обслуживание и как только его очередь подойдет, то ему автоматически наберут и соединят с оператором, на которого распределился его звонок. Таким образом убиваем сразу несколько зайцев: не занимаются линии колл-центра, не тратятся дорогостоящие минуты 8-800, а клиенты не испытывают лишнего раздражения в ожидании ответа. Вендоры колл-центрового ПО хотят за такую функцию весьма приличных денег, а мы под катом расскажем как данный функционал достаточно просто и быстро реализуется с помощью платформы VoxImplant.Так как мы уже писали про организацию колл-центра с помощью VoxImplant, то повторять эту часть в данной статье не будем, а сосредоточимся на изменениях, которые необходимо сделать в сценариях для реализации коллбэк-функции. Сразу замечу, что данная функциональность доступна только для сценариев, в которых подключается модуль ACD для работы с очередями. Сценарий, отвечающий за обработку входящих звонков с учетом нашей коллбэк-функции будет выглядеть следующим образом:
// Подключаем модуль ACD require(Modules.ACD); var request, // <-- тут будем хранить экземпляр ACDRequest originalCall, // <-- входящий звонок callerid, statusInterval, callback = false; // <-- флаг для коллбэк-режима // Вешаем обработчик входящего вызова VoxEngine.addEventListener(AppEvents.CallAlerting, handleInboundCall); // Обрабатываем входящий вызов function handleInboundCall(e) { originalCall = e.call; callerid = e.callerid; // Вешаем обработчики originalCall.addEventListener(CallEvents.Connected, handleCallConnected); originalCall.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); originalCall.addEventListener(CallEvents.Failed, cleanup); originalCall.addEventListener(CallEvents.Disconnected, cleanup); // Отвечаем на звонок originalCall.answer(); } // Завершаем сессию function cleanup(e) { if (request) { // Если звонок в очереди - удаляем request.cancel(); request = null; } // Закончить сессию if (!callback) VoxEngine.terminate(); } // Играем музыку после окончания проигрывания голоса или музыки function handlePlaybackFinished(e) { e.call.startPlayback("http://cdn.voximplant.com/toto.mp3"); } // Обработчик нажатий на кнопки function handleToneReceived(e) { if (e.tone == "#") { callback = true; originalCall.hangup(); // <-- несмотря на отсутствие звонков сессия не завершится } } // Звонок соединен function handleCallConnected(e) { // Включаем обработку нажатий на кнопки телефона originalCall.handleTones(true); originalCall.addEventListener(CallEvents.ToneReceived, handleToneReceived); // Отправляем звонок в очередь 'MainQueue', которую мы создали в панели управления request = VoxEngine.enqueueACDRequest("MainQueue", callerid); // Получаем статус после того как звонок поставлен в очередь request.addEventListener(ACDEvents.Queued, function (acdevent) { request.getStatus(); }); // Сообщаем звонящему о примерном времени ожидания и месте в очереди request.addEventListener(ACDEvents.Waiting, function (acdevent) { var minutesLeft = acdevent.ewt + 1; var minutesWord = " минуты."; if ((minutesLeft > 10 && minutesLeft < 20) || (minutesLeft % 10 > 4 || minutesLeft % 10 == 0)) { minutesWord = " минут."; } else if (minutesLeft % 10 == 1) { minutesWord = " минуту."; } originalCall.say("Вы находитесь в очереди под номером " + acdevent.position + ". Оператор ответит Вам менее чем через " + (acdevent.ewt + 1) + minutesWord + " Вы также можете нажать решетку и мы сами перезвоним вам как только оператор будет готов обслужить ваш вызов.", Language.RU_RUSSIAN_FEMALE); }); // Отправляем звонок оператору request.addEventListener(ACDEvents.OperatorReached, function (acdevent) { if (callback) { // В случае если клиент выбрал коллбэк, то после распределения вызова на оператора сообщаем оператору, что нужно дождаться соединения с клиентом acdevent.operatorCall.say("Пожалуйста, дождитесь соединения с клиентом.", Language.RU_RUSSIAN_FEMALE); acdevent.operatorCall.addEventListener(CallEvents.Disconnected, VoxEngine.terminate); acdevent.operatorCall.addEventListener(CallEvents.PlaybackFinished, function (callevent) { // Делаем коллбэк. В качестве caller id указываем номер, подтвержденный через верхнее меню панели управления Voximplant. const callerId = "+1234567890" originalCall = VoxEngine.callPSTN(callerid, callerId); originalCall.addEventListener(CallEvents.Connected, function (callevent) { VoxEngine.sendMediaBetween(acdevent.operatorCall, originalCall); clearInterval(statusInterval); }); originalCall.addEventListener(CallEvents.Failed, cleanup); originalCall.addEventListener(CallEvents.Disconnected, cleanup); }); } else { VoxEngine.sendMediaBetween(acdevent.operatorCall, originalCall); acdevent.operatorCall.addEventListener(CallEvents.Disconnected, VoxEngine.terminate); clearInterval(statusInterval); } }); // Нет доступных операторов - ни один оператор не обслуживает очередь request.addEventListener(ACDEvents.Offline, function (acdevent) { originalCall.say("К сожалению, сейчас нет доступных операторов. Пожалуйста, попробуйте позвонить позднее.", Language.RU_RUSSIAN_FEMALE); originalCall.addEventListener(CallEvents.PlaybackFinished, function (e) { VoxEngine.terminate(); }); }); // Получаем и сообщаем статус каждые 30 секунд statusInterval = setInterval(request.getStatus, 30000); }
Вот собственно и все. Немного подправив сценарий из предыдущего туториала про ACD мы получили очередь с коллбэком. Базовый сценарий, который мы меняли, доступен на github.com/voximplant/acd, также как и простейший веб-фон для операторов.
Работа с очередью через HTTP API
Предыдущий пример был сделан для случая когда сначала есть входящий звонок, в реальной жизни могут встречаться случаи, когда клиент сразу заказывает на сайте коллбэк и нам нужно его разместить в очереди на обработку. В целом, очередь — это абстрактная сущность, туда на обработку можно кидать не только звонки, но и, например, emailы, сообщения и т.д. В такой ситуации сценарий надо запускать через метод StartScenarios HTTP API, а сам сценарий немного трансформируется:
var displayName, callback = true; // Обработка заупуска сессии через StartScenarios VoxEngine.addEventListener(AppEvents.Started, function(e) { var data = VoxEngine.customData(); // Будем в script_custom_data передавать имя клиента и его номер в виде номер:имя data = data.split(":"); callerid = data[0]; displayName = data[1]; Logger.write("Put "+displayName+" with number "+callerid+" in a queue"); // Ставим запрос в очередь 'MainQueue' request = VoxEngine.enqueueACDRequest("MainQueue", callerid); // ... дальше все то же самое, что и в предыдущем сценарии });
P.S. А что если...
Нас иногда спрашивают: «а что если мы хотим использовать SIP-телефоны вместо веб-телефонов, сделанных с помощью VoxImplant Web SDK в нашем колл-центре?»
Отвечаем: «как ни странно, это возможно, но подробнее об этом мы расскажем в отдельной статье».
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Понравился ли вам данный материал?
65.71%Да69
22.86%Не очень24
11.43%Нет12
Проголосовали 105 пользователей. Воздержались 38 пользователей.

