Интеграция OTRS и Asterisk
Модератор: ykolesnikov
-
- OTRS Новобранец
- Сообщения: 48
- Зарегистрирован: 01 ноя 2010, 14:47
- Откуда: Воронеж
- Контактная информация:
Интеграция OTRS и Asterisk
Наконец, реализовали возможность совершать звонки из OTRS так же, как у нас это уже давно реализовано в Dokuwiki.
Работает это все следующим образом: при просмотре заявки агентом он может в один клик набрать мобильный, рабочий или домашний номер клиента. Звонок сначала приходит на внутренний номер агента, указанный в его профиле, а после того, как агент снимает трубку идет дозвон до клиента. Можно добавить компании клиента поле "Рабочий Телефон" и тогда для всех клиентов принадлежащих компании будет отображаться этот номер.
Чтобы указать внутренний номер агентам, можно использовать динамические поля агента (добавить поле extension). Изначально, мы использовали для этого поле "Комментарий".
Как добавлять поля клиентов написано тут: http://doc.otrs.org/3.0/ru/html/custome ... backend-db
Аналогично добавляются поля и для компаний.
"Звонилка" состоит из следующих частей:
1. JavaScript в шаблоне AgentTicketZoom.dtl
Javascript находит на странице телефон, разбирает поле с телефонами (по запятым) и каждый номер оборачивает в ссылку на вызов ajax-запроса "для позвонить". Если в номере содержится +, то всё, что после него, считается "добавочным" и ajax-агенту не передаётся. Чтобы поле отлавливалось скриптом, оно должно содержать $Text{"Phone"} (локализация слова "Phone"), например "Мобильный Телефон", "Рабочий Телефон" и т.д. Этого можно добиться, используя кастомную локализацию.
2. PHP-скрипт phony.php на сервере OTRS
AJAX-запрос вызывает скрипт phony.php, находящийся на сервере OTRS. Данный скрипт обязательно должен быть на том же домене, что и otrs. Он читает данные из файла сессии агента и передает их на сервер телефонии скрипту connect.php
3. PHP-скрипт connect.php на сервере asterisk
Скрипт connect.php, который находится на сервере asterisk "дает команду" совершить звонок. Он формирует так называемый call-файл и помещает его в специальный каталог asterisk-а, откуда тот его незамедлительно считывает и выполняет. Скрипт обязательно должен быть хорошо защищен от злоумышленников!
ToDo: надо бы добавить javascript также в шаблоны AgentTicketEmail и AgentTicketPhone
Работает это все следующим образом: при просмотре заявки агентом он может в один клик набрать мобильный, рабочий или домашний номер клиента. Звонок сначала приходит на внутренний номер агента, указанный в его профиле, а после того, как агент снимает трубку идет дозвон до клиента. Можно добавить компании клиента поле "Рабочий Телефон" и тогда для всех клиентов принадлежащих компании будет отображаться этот номер.
Чтобы указать внутренний номер агентам, можно использовать динамические поля агента (добавить поле extension). Изначально, мы использовали для этого поле "Комментарий".
Как добавлять поля клиентов написано тут: http://doc.otrs.org/3.0/ru/html/custome ... backend-db
Аналогично добавляются поля и для компаний.
"Звонилка" состоит из следующих частей:
1. JavaScript в шаблоне AgentTicketZoom.dtl
Javascript находит на странице телефон, разбирает поле с телефонами (по запятым) и каждый номер оборачивает в ссылку на вызов ajax-запроса "для позвонить". Если в номере содержится +, то всё, что после него, считается "добавочным" и ajax-агенту не передаётся. Чтобы поле отлавливалось скриптом, оно должно содержать $Text{"Phone"} (локализация слова "Phone"), например "Мобильный Телефон", "Рабочий Телефон" и т.д. Этого можно добиться, используя кастомную локализацию.
2. PHP-скрипт phony.php на сервере OTRS
AJAX-запрос вызывает скрипт phony.php, находящийся на сервере OTRS. Данный скрипт обязательно должен быть на том же домене, что и otrs. Он читает данные из файла сессии агента и передает их на сервер телефонии скрипту connect.php
3. PHP-скрипт connect.php на сервере asterisk
Скрипт connect.php, который находится на сервере asterisk "дает команду" совершить звонок. Он формирует так называемый call-файл и помещает его в специальный каталог asterisk-а, откуда тот его незамедлительно считывает и выполняет. Скрипт обязательно должен быть хорошо защищен от злоумышленников!
ToDo: надо бы добавить javascript также в шаблоны AgentTicketEmail и AgentTicketPhone
Последний раз редактировалось alex 09 июн 2012, 09:49, всего редактировалось 5 раз.
OTRS::ITSM 5.0.5
-
- OTRS Новобранец
- Сообщения: 48
- Зарегистрирован: 01 ноя 2010, 14:47
- Откуда: Воронеж
- Контактная информация:
Re: Интеграция OTRS и Asterisk
Javascript в шаблоне AgentTicketZoom.dtl:
Код: Выделить всё
--- AgentTicketZoom.dtl.orig 2012-06-07 22:48:01.000000000 +0400
+++ AgentTicketZoom.dtl 2012-06-08 11:21:35.000000000 +0400
@@ -786,6 +773,48 @@
Core.Agent.TicketZoom.Init({ ArticleTableHeight: parseInt('$Env{"UserTicketZoomArticleTableHeight"}', 10)});
Core.Config.Set('Ticket::Frontend::HTMLArticleHeightDefault', parseInt("$Config{"Ticket::Frontend::HTMLArticleHeightDefault"}" || 0, 10));
Core.Config.Set('Ticket::Frontend::HTMLArticleHeightMax', parseInt("$Config{"Ticket::Frontend::HTMLArticleHeightMax"}" || 0, 10));
+
+ window.callPhony = function(phone) {
+ $.post("/phony.php", { phone: phone } );
+ };
+
+ function addPhony(jqelem) {
+ var phones = $(jqelem).attr("title").split(",");
+
+ jqelem.empty();
+ jqelem.removeAttr("title");
+
+ var first = true;
+ for (var i = 0; i < phones.length; i ++) {
+ var phoneNumber = phones[i].trim().split("+");
+
+ if (phoneNumber.length == 2)
+ var addPart = phoneNumber[1];
+ phoneNumber = phoneNumber[0];
+
+ var a = document.createElement("a");
+ a.href = "javascript:callPhony('" + phoneNumber + "')";
+ a.title = phoneNumber;
+ var text = document.createTextNode(phoneNumber);
+ a.appendChild(text);
+
+ if (!first)
+ jqelem.append(", ");
+ first = false;
+ jqelem.append(a);
+ if (addPart)
+ jqelem.append("+" + addPart);
+ }
+ }
+
+ $(document).ready(function(){
+ $("div.Content fieldset.TableLike.FixedLabelSmall label")
+ .each(function(index) {
+ if ($(this).text().search("$Text{"Phone"}") >= 0)
+ addPhony($(this).next("p.Value"));
+ });
+ });
//]]></script>
<!-- dtl:js_on_document_complete -->
<!-- dtl:block:TicketZoomInit -->
OTRS::ITSM 5.0.5
-
- OTRS Новобранец
- Сообщения: 48
- Зарегистрирован: 01 ноя 2010, 14:47
- Откуда: Воронеж
- Контактная информация:
Re: Интеграция OTRS и Asterisk
phony.php
Код: Выделить всё
<?php
$config = array(
'agenturl' => "http://amp.__________.ru/phony/connect.php",
// Данные для http-basic аутентификации к скрипту connect.php
'agentuser' => "agentuser",
'agentpass' => "agentpass",
// Путь к каталогу, где лежат сессии. PHP-скрипт должен иметь права на чтение файлов из него!
'sessionpath' => "/opt/otrs-3.1.5/var/sessions/"
);
// === library ===
function call($caller, $callee) {
global $config;
$agent = $config['agenturl'];
$user = $config['agentuser'];
$pass = $config['agentpass'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $agent."?from=$caller&to=$callee");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$pass);
$ret = curl_exec($ch);
curl_close($ch);
}
function parseSession($sessionId) {
global $config;
$sessionFile = $config['sessionpath'] . $sessionId;
if (!is_readable($sessionFile))
return false;
$sessionData = file($sessionFile, FILE_IGNORE_NEW_LINES);
$sessionParsed = array();
foreach ($sessionData as $record) {
list($name, $value) = explode(":", $record);
$value = base64_decode($value);
if (preg_match("!([^\[]+)\[([^\]]+)\]!", $name, $matches)) {
$name = $matches[1];
$subname = $matches[2];
if (!is_array($sessionParsed[$name]))
$sessionParsed[$name] = array();
$sessionParsed[$name][$subname] = $value;
} else {
$sessionParsed[$name] = $value;
}
}
return $sessionParsed;
}
function determineOTRSAgentPhone($sessionId) {
$session = parseSession($sessionId);
if (!$session)
return false;
return $session['UserDynamicField_extension'];
}
// === entry point ===
$sessionId = $_COOKIE["Session"];
if (!preg_match("![\da-f]{34}!", $sessionId)) {
header("HTTP/1.1 400 Bad Request");
die("Wrong usage");
}
$agentPhone = determineOTRSAgentPhone($sessionId);
if (!$agentPhone) {
header("HTTP/1.1 400 Bad Request");
die("Wrong usage");
}
$phone = $_POST["phone"];
$phone = preg_replace("![^\d]+!", "", $phone);
call($agentPhone, $phone);
?>
Последний раз редактировалось alex 08 июн 2012, 16:08, всего редактировалось 1 раз.
OTRS::ITSM 5.0.5
-
- OTRS Новобранец
- Сообщения: 48
- Зарегистрирован: 01 ноя 2010, 14:47
- Откуда: Воронеж
- Контактная информация:
Re: Интеграция OTRS и Asterisk
Скрипт connect.php:
Обязательно, защищайте этот скрипт всеми способами!
Код: Выделить всё
<?php
header("Content-Type: text/plain; charset=utf-8");
$rndfile = uniqid().'.call';
$tmp = '/tmp';
$dst = '/var/spool/asterisk/outgoing';
file_put_contents("$tmp/$rndfile",
'Channel: Local/'.$_GET["from"].'@from-internal'. "\n".
'CallerID: Phony <' . $_GET["to"] . '>'. "\n".
'MaxRetries: 5'."\n".
'RetryTime: 3'."\n".
'Context: from-internal'."\n".
'Extension: '.$_GET["to"]
);
rename("$tmp/$rndfile", "$dst/$rndfile");
?>
OTRS::ITSM 5.0.5
-
- OTRS Новобранец
- Сообщения: 3
- Зарегистрирован: 18 окт 2012, 17:11
Re: Интеграция OTRS и Asterisk
Пожалуйста как можно поподробнее по Javascript AgentTicketZoom.dtl
Не совсем понятно по этому скрипту. что в нем нужно изменять ? что добавлять? не просто же выделить и вставить в файл AgentTicketZoom.dtl.
Cпасибо!.
Не совсем понятно по этому скрипту. что в нем нужно изменять ? что добавлять? не просто же выделить и вставить в файл AgentTicketZoom.dtl.
Cпасибо!.
-
- OTRS Новобранец
- Сообщения: 48
- Зарегистрирован: 01 ноя 2010, 14:47
- Откуда: Воронеж
- Контактная информация:
Re: Интеграция OTRS и Asterisk
Нужно найти в этом файле строчку и вставить после нее то, что отмечено плюсами (плюсы, естественно, нужно убрать).
Код: Выделить всё
Core.Config.Set('Ticket::Frontend::HTMLArticleHeightMax', parseInt("$Config{"Ticket::Frontend::HTMLArticleHeightMax"}" || 0, 10));
OTRS::ITSM 5.0.5
Re: Интеграция OTRS и Asterisk
2 alex:
Все работает, спасибо за отличную идею реализации.
Правда Extension (из поля "Комментарий") я передаю прямо через JS (без парсинга сессии).
У меня вопрос: как же все-таки добавить динамические поля для агента? (чтобы сделать по красоте поле Extension, а не комментарий).
Весь инет перерыл - не могу найти.
Последняя инстанция - файл User.pm, но че-то как-то совсем не хочется его править.
Все работает, спасибо за отличную идею реализации.
Правда Extension (из поля "Комментарий") я передаю прямо через JS (без парсинга сессии).
У меня вопрос: как же все-таки добавить динамические поля для агента? (чтобы сделать по красоте поле Extension, а не комментарий).
Весь инет перерыл - не могу найти.
Последняя инстанция - файл User.pm, но че-то как-то совсем не хочется его править.
Re: Интеграция OTRS и Asterisk
Кто подскажет куда конкретно класть, в какую папку и прочее phony.php connect.php и что куда прикручивать.
Как то вся процедура поверхностно написана. можно конкретики в каждом действии что делать.
Как то вся процедура поверхностно написана. можно конкретики в каждом действии что делать.
-
- OTRS Новобранец
- Сообщения: 48
- Зарегистрирован: 01 ноя 2010, 14:47
- Откуда: Воронеж
- Контактная информация:
Re: Интеграция OTRS и Asterisk
Добавил скриншот, вроде бы это все, что нужно сделать, но точно уже не помню.BOYARIN писал(а):2 alex:
Все работает, спасибо за отличную идею реализации.
Правда Extension (из поля "Комментарий") я передаю прямо через JS (без парсинга сессии).
У меня вопрос: как же все-таки добавить динамические поля для агента? (чтобы сделать по красоте поле Extension, а не комментарий).
Весь инет перерыл - не могу найти.
Последняя инстанция - файл User.pm, но че-то как-то совсем не хочется его править.
- Вложения
-
- agent_dynamic_field.jpeg (132.99 КБ) 31016 просмотров
OTRS::ITSM 5.0.5
Re: Интеграция OTRS и Asterisk
[/quote]alex писал(а):Javascript в шаблоне AgentTicketZoom.dtl:Код: Выделить всё
--- AgentTicketZoom.dtl.orig 2012-06-07 22:48:01.000000000 +0400 +++ AgentTicketZoom.dtl 2012-06-08 11:21:35.000000000 +0400 @@ -786,6 +773,48 @@ Core.Agent.TicketZoom.Init({ ArticleTableHeight: parseInt('$Env{"UserTicketZoomArticleTableHeight"}', 10)}); Core.Config.Set('Ticket::Frontend::HTMLArticleHeightDefault', parseInt("$Config{"Ticket::Frontend::HTMLArticleHeightDefault"}" || 0, 10)); Core.Config.Set('Ticket::Frontend::HTMLArticleHeightMax', parseInt("$Config{"Ticket::Frontend::HTMLArticleHeightMax"}" || 0, 10)); + + window.callPhony = function(phone) { + $.post("/phony.php", { phone: phone } ); + }; + + function addPhony(jqelem) { + var phones = $(jqelem).attr("title").split(","); + + jqelem.empty(); + jqelem.removeAttr("title"); + + var first = true; + for (var i = 0; i < phones.length; i ++) { + var phoneNumber = phones[i].trim().split("+"); + + if (phoneNumber.length == 2) + var addPart = phoneNumber[1]; + phoneNumber = phoneNumber[0]; + + var a = document.createElement("a"); + a.href = "javascript:callPhony('" + phoneNumber + "')"; + a.title = phoneNumber; + var text = document.createTextNode(phoneNumber); + a.appendChild(text); + + if (!first) + jqelem.append(", "); + first = false; + jqelem.append(a); + if (addPart) + jqelem.append("+" + addPart); + } + } + + $(document).ready(function(){ + $("div.Content fieldset.TableLike.FixedLabelSmall label") + .each(function(index) { + if ($(this).text().search("$Text{"Phone"}") >= 0) + addPhony($(this).next("p.Value")); + }); + }); //]]></script> <!-- dtl:js_on_document_complete --> <!-- dtl:block:TicketZoomInit -->
Код уже устарел? на OTRS 3.3.8 не взлетает(((