IVR

Лет 7 тому назад, я уже писал на тему обработки входящего звонка от клиента, с поиском внутреннего номера сотрудника, который последним звонил на номер клиента. Теперь пришло время написать похожую статью, как такое реализовать в webitel, тем более, что начиная с версии 3.8.2 (UPD: как оказалось, нужна версия старше 3.8.2) у нас в маршрутизации появилось отдельное приложение для запросов в базу elasticsearch, где и хранится вся информация о звонках. Давайте рассмотрим пример, как научить webitel соединять клиентов с последним звонившим.

Предположим, что у нас уже имеется любая существующая схема с IVR и другими полезностями. Мы хотим добавить в начале проверку по номеру телефона, звонящего к нам в офис, кто из сотрудников последним звонил на данный номер. Дополнительно мы еще добавим ограничение в «за последние 30 минут». Все это мы можем сделать с помощью запроса в cdr:

Довольно долго мы откладывали реализацию графического конструктора для настройки маршрутизации вызовов. Лично я всегда считал, что наша платформа для разработчиков, которые будут знать, что такое JSON и править код проще, чем перетягивать кубики. Но, пользователи требуют кубики.

И вот они, кубики:

VoiceMailПродолжаю рассказ о новых функциях Terrasoft Webitel 1.3. В этой заметке речь пойдет о голосовой почте.

В новой версии работать с голосовой почтой так же удобно, как и с обычными Email. Все сообщения хранятся в новом разделе и доступны пользователям Terrasoft Webitel. Каждый может видеть сообщения адресованные только ему, а администратор системы — все:

Vmail_Grid

Из интерфейса Вы можете сохранить голосовое сообщения на локальный диск (скачать себе), либо прослушать из системы:

VMail_Save

Как и в почте, доступно меню с пометками:

VMail_Mark

Удаление сообщений происходит через «Корзину», с которой Вы можете восстановить либо полностью удалить:

Vmail_Restore

Если SIP-телефон поддерживает MWI, то он Вас проинформирует о новом сообщении:

VMail_on_Yealink

Вы так же можете позвонить на IVR-меню управления голосовой почтой (по-умолчанию, номер 400) и прослушать либо удалить сообщение с помощью DTMF.

Ну и конечно, если в настройках пользователя Вы указали свой Email, то ждите сообщение в формате MP3 и там:

VMail2EMail

А Вы уже используете голосовую почту?

До официального релиза Webitel 1.3 осталось еще не много, а я уже сейчас хочу начать рассказывать о всех тех новых фишках, что мы в него добавили. Первая на очереди небольшая функция «Маршрут звонка».

Нас часто спрашивали: а как узнать где уже был звонок? Либо: а можно оператору сразу в карточке показать, что абонент был в IVR, потом поговорил с другим оператором, потом его переключили опять на IVR, а с него он попал на другого оператора?

Теперь это все возможно! В карточке звонка оператора доступна новая вкладка «Маршрут», а в разделе [Статистика] — кнопка, нажав на которую, Вы увидите историю прохождения звонка:

Roadmap

На снимке экрана видно, как абонент позвонил на пользователя, который переключил абонента на IVR-меню, после он попал на входящую очередь КЦ, где его обслужил оператор КЦ.

Как Вы думаете: насколько будет полезной эта функция?

FreeSWITCHЯ уже описывал, как в Oktell организовать сценарий Callback для сотрудников (звонок за счет офисной АТС). Теперь рассмотрим как такое же реализовать с помощью FreeSWITCH.

Для этой функции я выделил отдельный городской SIP-номер (благо, у меня их 10 шт.). Пускай Вас не смущает, что придется звонить с мобильного на городской, мы сделаем все возможное отправим в trunk SIP 183 Session Progress Message, что бы сотрудник не потерял и копейки. Вот таким будет наш диалплан:

    <extension name="380322320000">
    <condition field="destination_number" expression="^(380322320000)$">
            <action application="pre_answer"/>
            <action application="read" data="3 12 'tone_stream://%(10000,0,350,440)' digits 20000 #"/>
            <action application="set" data="api_hangup_hook=jsrun callback.js ${caller_id_number} ${digits}"/>
            <action application="hangup" data="CALL_REJECTED"/>
    </condition>
    </extension>

Поступил звонок, отправили Session Progress и гудок. Ждем ввода номера, после чего завершаем соединение. А вот уже после завершения запускаем JavaScript callback.js, где на вход отправляем номер звонящего и набранные цифры. Вот код скрипта callback.js:

    if ( ['0636150000','0939230000'].indexOf(argv[0]) != '-1' ) {
    console_log("info","Callback to " + argv[0] + "\n");
    session = new Session("{ignore_early_media=true}sofia/gateway/gsm/" + argv[0]);
    while (session.ready()) {
            session.execute("execute_extension", argv[1]+ " XML default");
            }
    }

Здесь все просто: проверяем номер ли нашего сотрудника, дозваниваемся ему и соединяем с набранным ранее абонентом.

Задача следующая: поступает вызов на один наш особый номер (только на этот номер) от абонента группе наших сотрудников. Сотрудник отвечает, общается с абонентом и абонент кладет трубку. Теперь начинается самое интересное, тот кто из группы поговорил с абонентом, надо коммутировать на руководителя отдела. Конечно, сотрудник может и сам потом перезвонить руководителю — но нет, его надо туда перевести 🙂 Вот как это можно решить на FreeSWITCH (99051000114579 — наш особый номер, 2000 — это номер группы, а 1000 — это номер руководителя отдела):

<extension name="in_extensions">
   <condition field="destination_number" expression="^(99051000114579)$">
       <action application="export" data="exec_after_bridge_app=transfer" />
       <action application="export" data="exec_after_bridge_arg=1000 XML features" />
       <action application="bridge" data="2000 XML default" />
    </condition>
</extension> 

Если Вы используете Oktell IP PBX без модуля КЦ и Вы не умеете разрабатывать плагины, а необходимо быстро решить вопрос: При входящем звонке отобразить историю всех звонков по номеру с комментариями. Как это сделать? Пойдем через веб-страничку 🙂

Для начало разработаем SQL запрос, что бы увидеть все входящие, исходящие и пропущенные звонки по номеру:

SELECT [s].[TimeAnswer] as [TimeAnswer]
   ,CONVERT(varchar(max), Cast (Cast ( [s].TimeStop - [s].TimeAnswer as float ) * 1440 as decimal(15,2))) as [TimeLong]
   ,'входящий' AS [D]
   ,CONVERT(varchar(max), [s].[Astr]) as [Abonent] 
   ,CONVERT(varchar(max), [s].[Bstr]) as [Oper] 
   ,l.LineCode as [LineCode]
   ,CONVERT(varchar(max), [c].[Comment])  AS [Comment]
   FROM [oktell].[dbo].[A_Stat_Comments] [c]
   right outer join [oktell].[dbo].[A_Stat_Connections_1x1] [s] on [s].[Id] = c.[id]
   join [oktell].[dbo].A_ServerExtLines [l] on [s].ALineId = [l].id
WHERE ([s].[AOutNumber] like '$c' AND [s].[Bstr] not like 'IVR') 

UNION

SELECT [s].[TimeAnswer] as [TimeAnswer]
   ,CONVERT(varchar(max), Cast (Cast ( [s].TimeStop - [s].TimeAnswer as float ) * 1440 as decimal(15,2))) as [TimeLong]
   ,'исходящий' AS [D]
   ,CONVERT(varchar(max), [s].[Bstr]) as [Abonent] 
   ,CONVERT(varchar(max), [s].[Astr]) as [Oper] 
   ,l.LineCode as [LineCode]
   ,CONVERT(varchar(max), [c].[Comment])  AS [Comment]
   FROM [oktell].[dbo].[A_Stat_Comments] [c]
   right outer join [oktell].[dbo].[A_Stat_Connections_1x1] [s] on [s].[Id] = c.[id]
   join [oktell].[dbo].A_ServerExtLines [l] on [s].BLineId = [l].id
WHERE [s].[BOutNumber] like '$c' AND [s].[Astr] not like 'IVR'

UNION

SELECT [s].[TimeAnswer] as [TimeAnswer]
   ,CONVERT(varchar(max), Cast (Cast ( [s].TimeStop - [s].TimeAnswer as float ) * 1440 as decimal(15,2))) as [TimeLong]
   ,'пропущенный' AS [D]
   ,CONVERT(varchar(max), [s].[Astr]) as [Abonent] 
   ,CONVERT(varchar(max), [s].[Bstr]) as [Oper] 
   ,l.LineCode as [LineCode]
   ,CONVERT(varchar(max), [c].[Comment])  AS [Comment]
   FROM [oktell].[dbo].[A_Stat_Comments] [c]
   right outer join [oktell].[dbo].[A_Stat_Connections_1x1] [s] on [s].[Id] = c.[id]
   join [oktell].[dbo].A_ServerExtLines [l] on [s].ALineId = [l].id
WHERE [s].[AOutNumber] like '$c' AND [s].[Bstr] like 'IVR' AND [s].[ReasonStop] = '3'

ORDER BY [TimeAnswer] DESC

Часто возникает необходимость оценить работу оператора после завершения разговора. Начиная с версии Oktell от 01.09.2011 — это стало просто в реализации. Все что Вам нужно, создать IVR сценарий с нужно логикой, как вот этот:

И назначить в настройках:

Все! Теперь после завершения разговора с сотрудником, Вы сможете услышать фразу: «Благодарим Вас за звонок» 🙂

Если Вы используете Oktell и Terrasoft, то Вы привыкли, что во время входящего звонка подымается карточка Звонка, где определяется Контакт и Контрагент по CallerID.
Сегодня, один из наших менеджеров предложил: «Было бы вообще супер, если информации об абоненте еще и на дисплее SIP-телефона отображалась!»
А почему бы и нет? — подумал я 😉

Для начала, создаем служебный сценарий, назовем его «Опрос Terrasoft»:

Самое интересное здесь — SQL-запрос в базу с Terrasoft:

SELECT [A].[Name] AS [Name]
, [A].[OfficialAccountName] AS [FullName]
FROM [Terrasoft_XRM+SD332].[dbo].[tbl_AccountCommunication] [AC]
JOIN [Terrasoft_XRM+SD332].[dbo].[tbl_Account] [A] ON [A].[ID] = [AC].[AccountID]
WHERE [AC].[Digits] LIKE '%'+@phone
UNION ALL
SELECT [C].[Name] AS [Name]
,[CA].[OfficialAccountName] AS [FullName]
FROM [Terrasoft_XRM+SD332].[dbo].[tbl_ContactCommunication] [CC]
JOIN [Terrasoft_XRM+SD332].[dbo].[tbl_Contact] [C] ON [C].[ID] = [CC].[ContactID]
JOIN [Terrasoft_XRM+SD332].[dbo].[tbl_Account] [CA] ON [C].[ID] = [CA].[PrimaryContactID]
WHERE [CC].[Digits] LIKE '%'+@phone

В общих настройках выбираем этот сценарий в пункте «Служебный сценарий получения данных из справочника РосФирм» 😉

Теперь на IP-телефонах можно увидеть:

А у кого нет Terrasoft, а только рабочее место Сотрудника:

Стоит задача на Oktell IP PBX ограничить длительность внешних разговоров для всех сотрудников до 10 мин. Решил задачу так:

1. Создаем служебный сценарий который проверяет активность на каждой из внешних SIP-линий и если превышено 10 мин. — разрывает соединение:

2. Прописываем служебный сценарий на периодический запуск каждых 20 сек.

Задача решена 🙂