Последнее время в РФ все больше ужесточается законодательство в части подмены номера звонящего. Одним из последних нововведений стали крупные штрафы. И если раньше операторы связи могли смотреть ”сквозь пальцы” на факт сокрытия реального номера звонящего, то теперь вероятность блокировки подобного звонка становится значительно выше.
Для всяческих мошенников у меня нет ни капли сострадания, но что делать добросовестным предпринимателям с кейсами, в которых сокрытие номера звонящего не связано со злонамеренными действиями? Ведь подобная защита номеров актуальна даже для крупных маркетплейсов и площадок объявлений.
Например, что делать если во время звонка мы захотим показать клиенту корпоративный номер его персонального менеджера, даже если менеджер использует свой личный телефон? Ответить на этот вопрос нам поможет Telecom API от компании MTT: компания-клиент МТТ настраивает переадресацию с выделенного оператором связи номера на личный номер менеджера. При этом клиент контролирует все коммуникации, а личный номер менеджера остаётся под защитой при обратном звонке благодаря переадресации на номер компании-клиента МТТ.
Но скучно будет просто написать обзор API, поэтому мы еще сделаем свой собственный “зародыш CRM” с помощью моей любимой XWiki, щепотки кода и Telecom API. На всё это у нас уйдет буквально 10 минут.
Сегодня мы с вами:
Посмотрим как решить проблему защиты номера звонящего с помощью API callback вызова и управления входящим вызовом.
Сделаем свое расширение для open source вики-движка XWiki и интегрируем в него методы callback вызова, чтобы звонить прямо из XWiki.
При этом расширение XWiki в принципе будет способно вызвать практически любой запрос к API, поэтому даже если вас не увлекает интернет-телефония, все равно загляните под кат.
Возможно, у вас возник вопрос: “Как связаны телефония и вики движок?”.
Ответ на самом деле прост. Создатели XWiki позиционируют её не просто как “базу знаний” или вики движок, а как в некотором роде “комбайн”, в котором может быть всего понемногу от форума, до тикетборда.
Но самое главное, функции XWiki достаточно легко расширить самостоятельно. Именно этим мы с вами и займемся, сделав с помощью Telecom API из Xwiki “зародыш” CRM-системы.
Конечно, можно было бы взять специализированную open source CRM для опытов, но я просто люблю XWiki. Вы об этом точно догадались если успели прочитать мои предыдущие статьи.
Оглавление:
Callback вызов Telecom API
Общая схема процесса защиты номера
Сегодня мы не будем всё усложнять и возьмем немного надуманный, но наглядный сценарий.
Предположим, что у нас есть важный клиент и его персональный менеджер. Мы не хотим, чтобы менеджер общался с клиентом напрямую со своего личного телефонного номера, также было бы замечательно иметь запись разговора и всю историю вызовов.
Для этого мы будем проксировать звонок через Telecom API.
Наш кейс состоит из двух частей:
Позвонить клиенту:
инициируем запрос на звонок;
показываем клиенту корпоративный номер в рамках переадресации;
менеджер фактически говорит со своего личного телефона.
Клиент перезванивает обратно:
обрабатываем звонок на корпоративный номер;
выполняем переадресацию на личный номер менеджера.
Краткое описание API
В этом разделе мы бегло рассмотрим назначение методов callback вызова и минимальный набор примеров для нашего кейса.
Если вы предпочитаете вдумчивое изучение всех особенностей API, тогда обязательно загляните в документацию.
Как я уже упоминал раньше, мы будем использовать callback для того, чтобы защитить личный номер менеджера, но на самом деле функции API намного шире, ниже далеко неполный перечень возможностей API:
Быстрый вызов, одного или нескольких абонентов в последовательном, параллельном или случайном порядке.
Запись разговора.
Ограничение длительности разговора.
Получение уведомлений о состоянии вызова.
Проигрывание звуковых сообщений как из медиафайлов, так и с помощью синтезатора речи.
Делаем пробный вызов.
Сделать вызов можно двумя способами:
подготовив заранее структуру вызова;
передав все необходимые данные прямо в момент вызова.
Уверен, вам не терпится поскорее приступить к делу. Поэтому мы выберем второй - более быстрый вариант.
Для этого нам понадобится метод makeCallBackCallFollowme.
Давайте сразу рассмотрим пример вызова метода.
Авторизация: Basic auth
Метод: POST
URL: https://webapicommon.mtt.ru/index.php
Тело запроса:
{
"id": "1",
"jsonrpc": "2.0",
"method": "makeCallBackCallFollowme",
"params": {
"customer_name": "7495137XXXX",
"b_number": "7499709XXXX",
"client_caller_id": "7499709XXXX",
"caller_id" : "7965XXXXXXX",
"simpleCallBackFollowmeStruct": [
{
"order": 1,
"timeout": 40,
"redirect_number": "7965XXXXXXX",
"type": "lineral",
"name": "sales"
},
{
"order": 2,
"type": "text",
"value": "Звонок от вашего персонального менеджера",
"side": "A"
}
]
}
}
В этом примере, после отправки запроса, будет совершен вызов плеча Б (номер клиента). Клиент увидит номер, выделенный МТТ, возьмет трубку, прослушает сообщение, после чего будет осуществлена переадресация на личный номер менеджера (плечо А). Менеджер тоже увидит номер, выделенный МТТ вместо номера клиента.
Давайте разберем ключевые поля.
method - метод API, который мы вызвали (makeCallBackCallFollowme)
params - объект с параметрами вызова
customer_name - номер клиента MTT
b_number - в нашем случае номер менеджера
client_caller_id - номер который будет показан клиенту (чтобы гарантированно дозвонится, нужен номер из сети МТТ)
caller_id - номер, который будет показан менеджеру (чтобы гарантированно дозвонится, нужен номер из сети МТТ)
simpleCallBackFollowmeStruct - массив объектов с параметрами переадресации
для первого объекта:
order - порядок вызова
timeout - время ожидания дозвона с момента вызова метода
redirect_number - номер, на который звоним (номер клиента)
type - тип вызова, в нашем случае последовательный (lineral)
name - символьное имя номера для перенаправления вызова
для второго объекта
"type": "text" - текстовое сообщение, произнесенное синтезатором речи.
value - непосредственно текст для синтезатора.
side - для какого плеча предназначено сообщение, в нашем случае для плеча “А” (для клиента). Если тут подставить "B", то наше сообщение услышит менеджер вместо клиента.
Вы можВы можете при желании добавить номеров и текстовых сообщений, побаловаться порядком вызова, но мы в этой статье будем придерживаться минимальных функций для демонстрации.
Еще немного полезных методов
Все же будет неправильно, совсем обойти стороной остальные методы callback вызова Telecom API.
Данными методами мы не будем пользоваться в рамках статьи, но вы можете с помощью них расширить приложение для XWiki, которое мы напишем в следующем разделе.
Я не буду расписывать примеры и параметры методов, просто дам краткое описание.
setCallBackFollowme
Этот метод позволит нам заранее установить структуру вызова.
Очень удобно для кейсов в которых всегда повторяется одна и также логика вызова.
В таком случае тело запроса будет весьма лаконичным:
{
"id": "1",
"jsonrpc": "2.0",
"method": "makeCallBackCallFollowme",
"params": {
"customer_name" : "7495137XXXX",
"b_number" : "7499709XXXX"
}
}
getCallBackHistory
Метод позволяет получить историю звонка по его идентификатору (возвращается в ответе на запрос makeCallBackCallFollowme).
Мы можем узнать длительность вызова, время ожидания каждой из сторон, кто не взял трубку, время разговора, причины разрыва и даже стоимость звонка (это не полный список).
setCallBackPrompt и getCallBackPromptInfo
Первый метод реализует логику для загрузки медиафайлов, которые можно успешно проиграть вместо синтезированного текста. Второй метод покажет нам список доступных медиафайлов.
getCallBackFollowme
Возвращает структуру вызовов, которую вы создали ранее в setCallBackFollowme.
Полезно в том случае, если вы хотите точечно изменить существующую логику вызова с помощью средств автоматизации.
deleteCallBackFollowme
Тут все просто: метод удалит логику вызовов, которую вы создали ранее в setCallBackFollowme.
А что если нам хотят перезвонить?
В этом случае мы можем воспользоваться методами API для управления входящим вызовом, которые мы подробно разобрали в прошлой статье.
Если кратко, то мы можем пойти по совсем простому пути: установить резервный номер с помощью метода setSipReserveNumber, и тогда при звонке на номер МТТ, звонок будет переадресован менеджеру.
Но это решение на уровне “забивать гвозди микроскопом” безусловно лучше поднять небольшой сервис, указать его адрес в методе setSipCallControlURL который будет обрабатывать звонки и в зависимости от условий определять на какой номер надо перезвонить.
Пришло время применить знания на практике и превратить Xwiki в мини CRM.
Интеграция Telecom API в XWiki
Описание планируемого приложения App Within Minutes
XWiki — это действительно мульти-функциональный движок, давно вышедший за рамки простой вики системы. В принципе если команда проекта сравнительно небольшая и не очень богатая (а также совсем не привередливая), то из XWiki можно сделать полноценный корпоративный портал.
В том числе внедрить чуть-чуть функций CRM. Самый главный компонент - API для совершения звонка — мы разобрали выше, теперь пришло время разобраться с его интеграцией.
Разработчики на форуме в ситуации, когда штатных функций не хватает, часто предлагают сделать свое собственное расширение (приложение) с помощью инструмента App Within Minutes. При этом они сами не гнушаются следовать этому совету, например, бесплатная версия интеграции draw.io для XWIki сделана именно с помощью этого инструмента.
App Within Minutes - по сути представляет собой набор готовых шаблонов, которые, если не прибегать к программированию, дадут вам возможность сделать свой каталог чего-либо, например, книг, песен или кулинарных рецептов. К сожалению, большинство примеров на сайте разработчика ограничивается именно такой сферой использования. Однако, мы сегодня пойдем дальше и узнаем, как можно расширить этот концепт, добавив совсем немного программного кода.
В принципе, приложения, которые можно создать с помощью штатного инструмента, это обычные страницы XWiki, а значит никто нам не мешает подправить их для отправки POST запросов на сервис Telecom API и чуть-чуть допилить функции интерфейса. Благо Xwiki позволяет нам не только писать код на JS, но еще по желанию использовать Velocity, Groovy, Python и PHP.
Прежде чем настраивать приложение и писать код, давайте посмотрим на диаграмму прецедентов, чтобы лучше представить себе функциональность.
Примечание: разграничение между “Верховным менеджером” и админом немного условное, в данном случае мы представляем, что менеджер не умеет включать “продвинутый” режим редактора или эта возможность доступна для редактирования только админам.
Давайте разберем самый главный сценарий — вызов клиента с помощью API.
Рассмотрим описание успешного сценария, без альтернативных кейсов.
Предусловия:
У менеджера в профиле корректно заполнен телефон.
Менеджер авторизован и имеет право заходить на страницу.
В табличке есть хоть 1 корректно заполненный пользователь.
Описание процесса:
Менеджер заходит на главную страницу приложения;
Менеджер нажимает на ссылку Call
Скрипт получает номер телефона менеджера из профиля и номер телефона клиента из таблицы и вызывает JS функцию UserAction(managerPhone,clientPhone);
Функция вызывает страницу на которой размещены php скрипт для вызова Callback API и вспомогательный velocity скрипт, передавая в него номера телефонов как GET параметры;
Страница phpCall вызывает Callback API с зашитой в код макроса структурой запроса, подставляя номера телефонов с прошлого шага.
Callback сервис набирает клиента;
Клиент снимает трубку;
Клиент прослушивает сообщение;
Callback сервис набирает менеджера;
Менеджер снимает трубку.
Результат
Разговор состоялся.
Процесс создания приложения для интеграции Telecom API в XWiki
Для демонстрации процесса я буду использовать англоязычную версию XWiki 13.10.5, просто потому, что она у меня развернута локально еще с прошлой статьи. В целом от перемены языка или версии XWiki ничего кардинально не изменится. Также понадобится установить макрос для работы с PHP.
Чтобы пройти все этапы. вам нужны права администратора, продвинутый режим пользователя и отображение скрытых страниц, об этом я уже писал по ссылке выше.
Для начала создайте свое приложение в App Within Minutes.
Дайте приложению звучное название.
Перетащите поля Short text:
Добавьте подсказки
Поле для ссылки на совершение звонка мы потом добавим через редактор классов.
Третий этап можно проскочить без изменений
Отредактируйте список полей LiveTable, как на скриншоте (чуть позже мы сюда еще вернемся).
Приложение есть, но позвонить мы пока точно не сможем. Давайте это срочно исправим.
Если вы еще не включили отображение скрытых страниц пришло самое время (можно просто нажать x+x+x+h), после чего перейдите на страницу MTTCallbackCRM Class (название будет зависеть от названия вашего приложения).
Перейдите в редактор классов:
Добавьте еще одно поле call с типом computed field, это и будет наша кнопка для вызова.
В поле custom display вставьте код:
{{velocity}}
{{html wiki=true clean="false"}}
#set ($userDoc = $xwiki.getDocument($xcontext.getUser()))
#set ($userObj = $userDoc.getObject('XWiki.XWikiUsers'))
#set ($phone = $userObj.getValue('phone'))
<a href="#" onclick='UserAction(Number($phone.trim()), Number($doc.getObject("CRM callack.Code.CRM callackClass").getValue("phone")))' > Call </a>
{{/html}}
{{/velocity}}
Должно быть примерно вот так:
Также дайте одному из двух полей ShortText имя phone
Вернитесь на главную страницу и нажмите кнопку для редактирования приложения:
Пролистайте шаги без изменений, пока не доберетесь до списка полей. Добавьте новое поле call в LiveTable. Также удалите неактивное поле Short Text
и добавьте переименованное поле phone. Вы можете проделать туже операцию со вторым полем Short Text
и назвать его Name. Будем считать, что это домашнее задание.
Теперь необходимо перейти в редактор объектов
Добавьте новый класс расширения Java Script
И вставьте в него следующий код:
function UserAction(managerPhone,clientPhone) {
let params = `?managerPhoneCall=${managerPhone}&clientPhoneCall=${clientPhone}`;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
};
xhttp.open("POST", "http://localhost:8080/bin/MTTCallbackCRM/phpCall"+params, true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(JSON.stringify(params));
}
http://localhost:8080/bin/edit/MTTCallbackCRM/phpCall
- это адрес страницы на которой мы разместим скрипт вызова, пришло время её создать. У вас адрес может отличаться.
Вернитесь на главную страницу приложения, нажмите кнопку создания новой страницы, назовите её phpCall.
Выберите шаблон пустой страницы:
Перейдите в режим вставки исходного кода и вставьте следующий код (см внутри спойлера).
Код для вставки
{{velocity}}
Откройте этот блок в режиме редактора, чтобы поменять:
имя пользователя, пароль, номер для маски, тл. номер заказчика в МТТ.
## введите данные тут:
#set($username = "CallXXX - ваш юзер (даст МТТ)")
#set($password = "пароль")
#set($maskNumber = "7499ХХХ номер маски который покажут обоим абонентам")
#set($customer_name = "7495ХХХ номер телефона даст МТТ")
## Это получение параметров запроса, его мы не трогаем:
#set($managerPhone = $request.managerPhoneCall)
#set($clientPhone = $request.clientPhoneCall)
{{/velocity}}
{{php}}
<?
if ($managerPhone && $clientPhone ){
$data = [
"id" => "1",
"jsonrpc" => "2.0",
"method" => "makeCallBackCallFollowme",
"params" => [
"customer_name" => "$customer_name",
"b_number" => "$managerPhone",
"client_caller_id" => "$maskNumber",
"caller_id" => "$maskNumber",
"simpleCallBackFollowmeStruct" => [
[
"order" => 1,
"timeout" => 40,
"redirect_number" => "$clientPhone",
"type" => "lineral",
"name" => "sales"
],
[
"order" => 2,
"type" => "text",
"value" => "Звонок с сайта выдуманный магазин ру",
"side" => "A"
]
]
]
];
$postdata = json_encode($data);
$ch = curl_init(' https://webapicommon.mtt.ru/index.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata );
$html = curl_exec($ch);
curl_close($ch);
echo $html;
}
?>
{{/php}}
Само собой вам надо подставить свои данные.
Я не стал заморачиваться с управлением паролями и прочим, просто запихнул их в код. Вы можете доработать этот момент.
Не забудьте сохранить страницу.
Осталось только завести пробную запись. Вам понадобится 2 номера телефона, к которым у вас есть доступ.
Для начала запишем номер телефона в свой профиль.
Затем создадим запись в приложении.
Нажимаем на ссылку (кнопку) Call и восхищаемся магии CallBack API.
Заключение
Сегодня мы с вами не только разобрали API с помощью которого можно защищать номера абонентов, вести логи, собирать статистику звонков и так далее, но и нашли способ как интегрировать его в Xwiki.
Я очень надеюсь, что примеры из статьи будут вам полезны и может быть даже избавят от появления преждевременных седых волос.
Коллекцию для вызова метода и xar архив с приложением можно скачать с GitHub.
Большое спасибо всем, кто прочитал до конца, буду рад конструктивной обратной связи.