Промоделируем ситуацию: знаменитейший помощник повара по имени Хуан после прогремевшей на весь мир истории со сковородками (отсылка) решил открыть свой собственный ресторанчик.
Хуан готовит прекрасную паэлью, возможно лучшую в Андалусии. Но есть одна проблема — Хуан уважает сиесту, а поэтому с 13:00 до 17:00 совершенно не следит за персоналом ресторана.
Наша цель: помочь веселому и предприимчивому Хуану успокоить клиентов и мотивировать сотрудников, чтобы они не забывали быстро готовить и доставлять заказы.
Для этого автоматизируем процессы обработки входящих вызов от клиентов с помощью Telecom API MTT.
В данной статье мы:
-
посмотрим сценарии для управления входящим вызовом;
-
добавим голосовые сообщения;
-
внесём автоматическое информирование персонала;
-
сохраним информацию о вызовах, чтобы понять кто чаще халтурит;
-
разберем необходимые методы Telecom API;
-
получим данные из заказа в интернет-магазине на бесплатном движке PrestaShop и передадим их в Telecom API.

Оглавление:
Перед началом содержательной части статьи традиционный дисклеймер. Я не программист, поэтому мои способы решения задач в этой статье не обязательно хороши на практике. Рассматривайте все, как пример для вдохновения.
Процесс автоматизации обработки входящих вызовов
Для начала широкими мазками «опишем картину» в целом.
У Хуана есть ресторанчик, который готовит прекрасную паэлью.
У ресторанчика есть простой сайт на базе движка PrestaShop.
Все заказы так или иначе попадают в базу сайта.
Персонал:
-
Хуан — владелец и руководитель.
-
Мигель — ленивый повар.
-
Пабло — еще более ленивый курьер.
Полноценно позволить себе сиесту может только Хуан, но, когда он отдыхает, остальные не излучают энтузиазм. Поэтому в период сиесты достаточно часто поступают звонки от клиентов, которые еще не дождались своего заказа.
Каждый раз, когда такое случается, Хуан расстраивается, даже больше, чем в истории с уплывшими сковородками. Давайте же ему поможем!
Сосредоточимся на оптимизации процесса обработки звонков с претензиями клиентов.
Для начала изучим процесс «как есть»:

Для тех, кто предпочитает текстом, распишем процесс в формате сценария.
Действующие лица:
-
Хуан, клиент.
Цель
-
Поторопить ресторан с доставкой заказа.
Предусловия:
-
Пользователь сделал заказ.
-
Заказ есть в БД Prestashop ресторана.
-
Пользователь ждал дольше 50 минут.
Основной путь:
-
Клиент звонит в ресторан Хуана.
-
Хуан встает с дивана, берет трубку.
-
Хуан открывает PrestaShop.
-
Хуан смотрит какой статус у заказа.
-
Если заказ готов, Хуан поторапливает курьера.
-
Хуан извиняется перед клиентом и просит подождать еще 25 минут.
-
Хуан кладет трубку и идет обратно на диван.
-
Завершение сценария.
Альтернативный путь:
-
5а. Заказ не готов, Хуан поторапливает кухню.
-
6а. Хуан приносит свои глубочайшие извинения клиенту и просит подождать еще 50 минут.
-
Возврат к шагу 7.
Результат
-
Персонал суетится по поводу заказа, клиент успокоен.
Давайте попробуем улучшить наш «рецепт» обработки звонков, добавив в него «щепотку» автоматизации.
C помощью Telecom API мы можем:
-
добавить проигрывание голосовых сообщений (premedia) клиенту и персоналу (сообщение будем генерировать из текста);
-
добавить автоматическую переадресацию звонка повару или курьеру;
-
посмотреть статистику, чтобы понять, кто больше «филонит», пока у Хуана сиеста.
Пришло время посмотреть на оптимизированный процесс:

В этот раз процесс получился более внушительным, пришлось даже опустить некоторые детали, чтобы он вписался в верстку Хабра.
Давайте как и в прошлый раз, рассмотрим его текстовое описание:
Действующие лица:
-
Клиент, повар, курьер, telecom API, сайт.
Цель
-
Поторопить ресторан с доставкой заказа.
Предусловия:
-
Пользователь сделал заказ.
-
Заказ есть в БД Prestashop ресторана.
-
Пользователь ждал дольше 50 минут.
Основной путь:
-
Клиент звонит в ресторан Хуана.
-
Telecom API принимает вызов и делает запрос на сайт.
-
Сайт ищет номер телефона клиента среди еще невыполненных заказов.
-
Если у звонящего есть незавершенные заказы, переходим к шагу 5.
-
Хуану отправляется email о том, что был звонок клиента по незавершенному заказу.
-
Если заказ готов (статус on delivery), включить клиенту premedia, что заказ будет доставлен через 25 минут.
-
Сделать переадресацию вызова на курьера.
-
Курьер слушает premedia о недовольном заказчике.
-
Если клиент дослушал premedia, курьер извинился лично.
-
Курьер бежит доставлять заказ.
-
Сценарий завершен.
Альтернативный путь — у клиента нет незавершенных заказов:
-
4а. Переводим звонок на Хуана.
-
Переходим к шагу 11.
Альтернативный путь — заказ не готов:
-
6а. Заказ не готов (статус on kitchen), включить клиенту premedia, что заказ будет доставлен через 50 минут.
-
7a. Повар слушает premedia о недовольном заказчике.
-
8a. Если клиент дослушал premedia, повар извиняется лично.
-
9а. Повар готовит заказ.
-
10а. Повар изменяет статус заказа в PrestaShop.
-
11а. Повар передает заказ курьеру.
-
12а. возврат к шагу 10 основного сценария.
Теперь мы полностью освободили Хуана от рутины. Он может спокойно наслаждаться сиестой, лишь изредка проверяя статистику звонков и раздавая нагоняй по необходимости.
Описание необходимых методов Telecom API
Бегло взглянем на методы API, которые нам понадобятся для реализации этого кейса.
Я не буду слишком подробно описывать каждый метод, потому что всё необходимое можно найти в документации.
В одной из прошлых статей мы уже рассматривали API для создания premedia и управления входящим вызовом (правда с добавочными номерами), но, думаю, не будет лишним взглянуть еще раз с немного другого ракурса.
Для всех методов, указанных в статье, я подготовил коллекцию и окружение Postman.
Создание Premedia
Начнем с методов для создания аудио-сообщений (premedia)
Для реализации сценария нам потребуется минимум 4 сообщения, например, со следующим текстом:
-
Клиенту — «Ваш заказ передан в доставку, подождите 25 минут.”».
-
Клиенту — «Ваш заказ готовится, пожалуйста, подождите 50 минут.”».
-
Повару — «Мигель, клиент долго ждет заказ, готовь быстрей и отдай в доставку!”».
-
Курьеру — «Пабло, экий ты дармоед, скорей неси заказ клиенту!”».
В принципе API позволяет нам создавать каждый раз новое premedia с указанием данных конкретного клиента, а потом стирать его после выполнения заказа, но мы оставим это на самостоятельную проработку.
Создадим новый медиафайл с помощью метода:
URL: https://gapi.mtt.ru:6443/v1/api
Авторизация: — Basic auth.
Тип запроса: POST
Пример тела запроса:
{ "id": "1", "jsonrpc": "2.0", "method": "createCustomerPrompt", "params": { "customer_name" : "ваш логин МТТ", "prompt_name": "название медиафайла.mp3, например 25min.mp3", "prompt_type" : "text", "prompt_file_contents": "Ваш заказ передан в доставку подождите 25 минут" } }
Пример успешного ответа:
{ "jsonrpc":"2.0", "id":55585, "result": { "success":true } }
Эту операцию нам надо повторить еще три раза, чтобы получить в сумме 4 аудиосообщения.
Посмотреть, что у нас получилось, можно с помощью метода:
URL: https://gapi.mtt.ru:6443/v1/api
Авторизация: — Basic auth.
Тип запроса: POST
Пример тела запроса:
{ "id": "1", "jsonrpc": "2.0", "method": "getCustomerPrompts", "params": { "customer_name": "Ваш ID клиента" } }
Пример успешного ответа:
{ "jsonrpc": "2.0", "id": "1", "result": { "prompts_list": [ { "id": 44361, "name": "TTS_25m.mp3", "file_id": "ca15d7db7e1ecc6d95976bfa1efead92" }, { "id": 44363, "name": "TTS_50m.mp3", "file_id": "ade3e6b9ff021b8df3174f2e6b37b3df" }, { "id": 44365, "name": "TTS_Migel.mp3", "file_id": "c89020935c6157f8370730a08fadf9b9" }, { "id": 44367, "name": "TTS_Pablo.mp3", "file_id": "92b12508157acc3e69d5b3d09af786ef" } ] } }
Если вдруг вы случайно создали лишнюю запись, её можно удалить с помощью метода:
URL: https://gapi.mtt.ru:6443/v1/api
Авторизация: — Basic auth.
Тип запроса: POST
Пример тела запроса:
{ "id": "1", "jsonrpc": "2.0", "method": "getCustomerPrompts", "params": { "customer_name": "Ваш ID клиента" } }
Пример успешного ответа:
{ "jsonrpc": "2.0", "id": "1", "result": { "success": true } }
Управление входящим вызовом
Для начала добавим ссылку на скрипт, в котором будет реализована логика управления вызовом.
URL: https://api.mtt.ru/ipcr/
Авторизация: — Basic auth.
Тип запроса: POST
Пример тела запроса:
{ "id":"1", "jsonrpc":"2.0", "method": "setSipCallControlURL", "params": { "sip_id":"SIP ID клиента, например, 79998000000", "url": "{{callURL}}" } }
Пример успешного ответа:
{ "jsonrpc": "2.0", "id": "1", "result": { "success": 1 } }
Посмотреть текущие настройки можно с помощью метода:
URL: https://api.mtt.ru/ipcr/
Авторизация: — Basic auth
Тип запроса: POST
Пример тела запроса:
{ "id":"1", "jsonrpc":"2.0", "method":"getSipSettings", "params":{ "sip_id":"SIP ID клиента, например, 79998000000" } }
Пример успешного ответа:
{ "jsonrpc": "2.0", "id": "1", "result": { "GN_IP_IPCR": "http://somedomen.ru/call.php", "GN_IPCR_RESERVE": "", "i_account": 190000000 } }
Остальные методы можно изучить в документации.
История звонков
Посмотреть статистику звонков для номера своего ресторанчика Хуан сможет в любое время благодаря методу:
URL: https://webapicommon.mtt.ru/index.php
Авторизация: — Basic auth
Тип запроса: POST
Пример тела запроса:
{ "id": "1", "jsonrpc": "2.0", "method": "getCallHistory", "params": { "sip_id":"SIP ID клиента, например, 79998000000", "date_from": "25.09.2022 10:23:35", "date_to": "30.09.2022 22:23:35" } }
Пример успешного ответа:
{ "jsonrpc": "2.0", "id": "1", "result": { "incoming": [ { "cli": "7900000000", "cld": "7900000001", "customer_local_time": "2022-09-25 21:16:17", "connect_time": "2022-09-25 21:16:17", "charged_time": "60", "destination": "Входящая связь", "charged": 0, "curr": "RUB", "used_quantity": "9", "h323_conf_id": "4106D0B5 D1993112 35031CAB A0000000", "call_id": "ka4ak714k97e1a000000a6526e19f@_000163309AF07371" } ], "missed": [ { "cli": "79500000000", "cld": "79700000001", "customer_local_time": "2022-09-25 21:19:32", "destination": "Россия, моб.", "charged": 0, "curr": "RUB", "connect_time": "2022-09-25 21:19:32", "disconnect_cause": "16", "disconnect_text": "Normal call clearing", "used_quantity": "0", "h323_conf_id": "AC26B720 F5F3B474 6F23A2DF 20000000", "call_id": "57f6eae8-f673-0000-0000-86ad03c75a8b" } ], "dialed": [ { "cli": "79500000000", "cld": "79700000001", "customer_local_time": "2022-09-25 22:05:09", "connect_time": "2022-09-25 22:05:09", "charged_time": "60", "charged": 0, "destination": "Россия, моб.", "curr": "RUB", "disconnect_cause": "16", "used_quantity": "7", "h323_conf_id": "D7BBBE7C 8CA8C927 3CBB6991 F0000000", "call_id": "b007cd98-a395-0000-0000-a45579e00000" } ], "callback": [], "success": 1 } }
Так же Хуан может прослушать записи разговора в формате wav или mp3.
Ниже пример метода для mp3 (для wav параметр format нужно убрать)
Метод records
Авторизация — Basic auth
Тип запроса: GET
URL: https://rc.mtt.ru/v2/records/ID_ЗВОНКА_51B2844D_FC28243B_/urls?format=mp3
Пример успешного ответа:
[ "http://rc.mtt.ru/29132333/00/00/B3/A4/55/F3/11/E4/A2/42/00/25/90/62/ED/C4/0000B3A4_55F311E4_A2420025_9062EDC4_1_ссылка_на_скачивание_файла.mp3" ]
Если бы у Хуана была CRM, он мог бы добавлять записи разговора к информации о звонках, но в нашем случае он еще ей не обзавелся.
Интеграция с PrestaShop
Сегодня мы решим очень простую задачу: получить данные о заказах из магазина, проверить совпадение номера звонящего с кем-то из клиентов.
При необходимости сделать редирект вызова на кухню или в доставку, с включением соответствующих аудиосообщений.
Вы можете доработать кейс, например, добавив создание и удаление файла premedia так, чтобы он содержал информацию о клиенте и его заказе.
API Prestashop
Прежде, чем использовать API магазина, нам нужно сделать некоторую подготовку.
Во-первых, необходимо получить ключ доступа.
Во-вторых, в профиле пользователя сделать обязательным поле mobile_number. Можно использовать любое другое, просто не забудьте поменять код в файле call.php.
Еще для наглядности я создал новые статусы заказов, вы можете использовать существующие.

В нашей интеграции мы будем использовать только методы для работы с заказами и адресами.
Если будете использовать пример из файла call.php, установите себе на сервер (хостинг) библиотеку для работы с API.
Скрипт для интеграции Telecom API и Prestashop API
Как всегда дисклеймер. Я не программист. Код ниже я «склепал» из того, что попалось под руку. Код рабочий, но явно далек от идеала, не надо им руководствоваться как истинной в последней инстанции.
Полный листинг файла call.php я оставлю под спойлером
Развернуть код
<?php header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: access"); header("Access-Control-Allow-Methods: POST"); header("Access-Control-Allow-Credentials: true"); header('Content-Type: application/json; charset=utf-8'); # logger $params = (array) json_decode(file_get_contents('php://input'), TRUE); $fw = fopen("log.txt", "a+"); fwrite($fw, var_export($params, true)); fclose($fw); # read Telecom API request data $data = json_decode(file_get_contents("php://input")); # get caller phone number $numberA = (int)$data->params->numberA; $id = (int)$data->id; # set initial vars $shop_URL="http://mehappy-presta-g84qg.tw1.ru/"; $API_key="7HVI91EY6JX4YBSGVQJ46SJA9P6XCVSB"; $default_number = "790000000000"; $kitchen_number="790000000001"; $delivery_number="90000000002"; $client_order_id =0; $client_order_state=0; $client_mobile=0; $promt_migele="c89020935c6157f8370730a08fadf9b9"; $promt_pablo="92b12508157acc3e69d5b3d09af786ef"; $promt_25mc="ca15d7db7e1ecc6d95976bfa1efead92"; $promt_50mc="ade3e6b9ff021b8df3174f2e6b37b3df"; # if empty, media will not play. $file_to_A = ""; $file_to_B = ""; # import prestaShop library require_once('./PSWebServiceLibrary.php'); # get orders # state: 14 -kitchen , 15 - delivery try { // creating webservice access $webService = new PrestaShopWebservice($shop_URL, $API_key, false); // call to retrieve all customers $xml = $webService->get( array ( 'resource' => 'orders', 'filter[current_state]' => '[14|15]', 'display' => '[id,current_state,id_address_delivery]' ) ); } catch (PrestaShopWebserviceException $ex) { // Shows a message related to the error } $promt_pablo=""; # check if caller has on finished orders foreach ($orders as $order) { foreach ($order as $key => $value) { if ($key == 'id') { $client_order_id = $value; } elseif ($key == 'current_state') { $client_order_state = $value; } else { try { // check address to get mobile phone number $webService = new PrestaShopWebservice($shop_URL, $API_key, false); // call to retrieve all customers $xml2 = $webService->get( array ( 'resource' => 'addresses', 'id' => $value ) ); } catch (PrestaShopWebserviceException $ex) { // Shows a message related to the error echo 'Other error: <br />' . $ex->getMessage(); } $mobile_phone = $xml2->address->phone_mobile; if ($mobile_phone == $numberA){ $client_mobile=$mobile_phone; } } } # if client has unfinished orders redirect call to kitchen or delivery if ($client_mobile != 0){ $result = mail('admin@mail2.org', "Call for order $client_order_id", "Client phone $client_mobile, order state $client_order_state"); if(!$result) { # echo "Error"; } else { # echo "Success"; } if ($client_order_state == 14 ) { $redirect_number = $kitchen_number; $file_to_A = $promt_50mc; $file_to_B = $promt_migele; } else{ $redirect_number = $delivery_number; $file_to_A = $promt_25mc; $file_to_B = $promt_pablo; } break 1; } else { # set default manager number to redirect $redirect_number = $default_number; } } # create API response to Telecom API $response_call = array( "jsonrpc" => "2.0", "id" => "1", "result" => array( "redirect_type" => 1, "event_URL" => "http://mehappy-presta-g84qg.tw1.ru/call.php", "event_extended" => "Y", "client_id" => "1235", "file_to_A" => "$file_to_A", "file_to_B" => "$file_to_B", "masking" => "Y", "followme_struct" => array( 1, array( array( "I_FOLLOW_ORDER" => 1, "PERIOD" => "always", "PERIOD_DESCRIPTION" => "always", "TIMEOUT" => "90", "ACTIVE" => "Y", "NAME" => "$numberA", "REDIRECT_NUMBER" =>"$redirect_number" ) ) ) ) ); # send response to Telecom API echo json_encode($response_call, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); ?>
Давайте разберем код по логическим блокам.
header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: access"); header("Access-Control-Allow-Methods: POST"); header("Access-Control-Allow-Credentials: true"); header('Content-Type: application/json; charset=utf-8'); # logger $params = (array) json_decode(file_get_contents('php://input'), TRUE); $fw = fopen("log.txt", "a+"); fwrite($fw, var_export($params, true)); fclose($fw); # read Telecom API request data $data = json_decode(file_get_contents("php://input")); # get caller phone number $numberA = (int)$data->params->numberA; $id = (int)$data->id; # set initial vars $shop_URL="http://presta-g84qg.somedomain.ru/"; $API_key="7HVI91EY6JX4YBSGVXXXXXXXXXXXX"; $default_number = "790000000000"; $kitchen_number="790000000001"; $delivery_number="90000000002"; $client_order_id =0; $client_order_state=0; $client_mobile=0; $promt_migele="c89020935c6157f8370730a08fad1111"; $promt_pablo="92b12508157acc3e69d5b3d09af71111"; $promt_25mc="ca15d7db7e1ecc6d95976bfa1efe1111"; $promt_50mc="ade3e6b9ff021b8df3174f2e6b371111"; # if empty, media will not play. $file_to_A = ""; $file_to_B = ""; # import prestaShop library require_once('./PSWebServiceLibrary.php');
Это подготовительный блок.
В самом начале мы прописываем заголовки и пишем запросы в лог (возможно на сервере потребуется создать файл log.txt).
Далее мы прописываем все ключевые параметры.
Адрес сайта, ключ API, заглушки, медиафайлы.
На всякий случай напомню, что здесь и далее «сторона А» — звонящий, «сторона Б» — абонент, принимающий звонок.
В самом конце импортируем библиотеку PrestaShop.
# get orders # state: 14 -kitchen , 15 - delivery try { // creating webservice access $webService = new PrestaShopWebservice($shop_URL, $API_key, false); // call to retrieve all customers $xml = $webService->get( array ( 'resource' => 'orders', 'filter[current_state]' => '[14|15]', 'display' => '[id,current_state,id_address_delivery]' ) ); } catch (PrestaShopWebserviceException $ex) { // Shows a message related to the error } $promt_pablo="";
Получаем список заказов, у которых статус «В доставке» или «На кухне».
# check if caller has on finished orders foreach ($orders as $order) { foreach ($order as $key => $value) { if ($key == 'id') { $client_order_id = $value; } elseif ($key == 'current_state') { $client_order_state = $value; } else { try { // check address to get mobile phone number $webService = new PrestaShopWebservice($shop_URL, $API_key, false); // call to retrieve all customers $xml2 = $webService->get( array ( 'resource' => 'addresses', 'id' => $value ) ); } catch (PrestaShopWebserviceException $ex) { // Shows a message related to the error echo 'Other error: <br />' . $ex->getMessage(); } $mobile_phone = $xml2->address->phone_mobile; if ($mobile_phone == $numberA){ $client_mobile=$mobile_phone; } } }
Пробегаем по каждому заказу, делаем запрос на данные об адресе и проверяем номер мобильного телефона клиента.
Если телефон в адресе заказа совпадает с телефоном звонящего, то мы сохраняем данные в переменные и идем дальше.
if ($client_mobile != 0){ $result = mail('admin@mail2.org', "Call for order $client_order_id", "Client phone $client_mobile, order state $client_order_state"); if(!$result) { # echo "Error"; } else { # echo "Success"; } if ($client_order_state == 14 ) { $redirect_number = $kitchen_number; $file_to_A = $promt_50mc; $file_to_B = $promt_migele; } else{ $redirect_number = $delivery_number; $file_to_A = $promt_25mc; $file_to_B = $promt_pablo; } break 1; } else { # set default manager number to redirect $redirect_number = $default_number; } }
Если есть совпадение номера, мы сначала отправляем Хуану письмо, чтобы он знал, о возможных проблемах. Затем проверяем статус заказа и назначаем premedia и телефоны для редиректа, на кухню или в доставку соответственно.
Если совпадений не было, значит клиент новый и мы просто звоним Хуану на дефолтный номер.
# create API response to Telecom API $response_call = array( "jsonrpc" => "2.0", "id" => "1", "result" => array( "redirect_type" => 1, "event_URL" => "http://presta-g84qg.somedomain.ru/", "event_extended" => "Y", "client_id" => "1235", "file_to_A" => "$file_to_A", "file_to_B" => "$file_to_B", "masking" => "Y", "followme_struct" => array( 1, array( array( "I_FOLLOW_ORDER" => 1, "PERIOD" => "always", "PERIOD_DESCRIPTION" => "always", "TIMEOUT" => "90", "ACTIVE" => "Y", "NAME" => "$numberA", "REDIRECT_NUMBER" =>"$redirect_number" ) ) ) ) ); # send response to Telecom API echo json_encode($response_call, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
Финальный этап, формирование ответа на запрос Telecom API.
Не забудьте залить файл на сервер (хостинг). И привязать к нему Telecom API методом setSipCallControlURL.
Заключение
Подводя итоги, сегодня мы:
-
Освободили время менеджмента, улучшив процесс обработки звонков.
-
Познакомились с методами Telecom API для автоматизации работы с входящими вызовами.
-
Одним глазом глянули на PrestaShop API и подружили сайт с Telecom API.
Пожелаем Хуану удачи в ресторанном бизнесе!
Надеюсь, что и для вас статья была полезна.
Код файла call.php, коллекцию и окружение Postman я выложил на GitHub.
ссылка на оригинал статьи https://habr.com/ru/company/mtt/blog/692726/
Добавить комментарий