Интеграция OTRS и Asterisk

Только для готовых решений! Пожалуйста, не используйте для вопросов и обсуждений!

Модератор: ykolesnikov

Ответить
alex
OTRS Новобранец
Сообщения: 48
Зарегистрирован: 01 ноя 2010, 14:47
Откуда: Воронеж
Контактная информация:

Интеграция OTRS и Asterisk

Сообщение alex » 08 июн 2012, 15:45

Наконец, реализовали возможность совершать звонки из 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
Последний раз редактировалось alex 09 июн 2012, 09:49, всего редактировалось 5 раз.
OTRS::ITSM 5.0.5

alex
OTRS Новобранец
Сообщения: 48
Зарегистрирован: 01 ноя 2010, 14:47
Откуда: Воронеж
Контактная информация:

Re: Интеграция OTRS и Asterisk

Сообщение alex » 08 июн 2012, 15:48

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

alex
OTRS Новобранец
Сообщения: 48
Зарегистрирован: 01 ноя 2010, 14:47
Откуда: Воронеж
Контактная информация:

Re: Интеграция OTRS и Asterisk

Сообщение alex » 08 июн 2012, 15:53

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

alex
OTRS Новобранец
Сообщения: 48
Зарегистрирован: 01 ноя 2010, 14:47
Откуда: Воронеж
Контактная информация:

Re: Интеграция OTRS и Asterisk

Сообщение alex » 08 июн 2012, 15:57

Скрипт 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

adrenaline69
OTRS Новобранец
Сообщения: 3
Зарегистрирован: 18 окт 2012, 17:11

Re: Интеграция OTRS и Asterisk

Сообщение adrenaline69 » 03 дек 2012, 15:26

Пожалуйста как можно поподробнее по Javascript AgentTicketZoom.dtl
Не совсем понятно по этому скрипту. что в нем нужно изменять ? что добавлять? не просто же выделить и вставить в файл AgentTicketZoom.dtl.
Cпасибо!.

alex
OTRS Новобранец
Сообщения: 48
Зарегистрирован: 01 ноя 2010, 14:47
Откуда: Воронеж
Контактная информация:

Re: Интеграция OTRS и Asterisk

Сообщение alex » 08 дек 2012, 10:36

Нужно найти в этом файле строчку

Код: Выделить всё

Core.Config.Set('Ticket::Frontend::HTMLArticleHeightMax', parseInt("$Config{"Ticket::Frontend::HTMLArticleHeightMax"}" || 0, 10));
и вставить после нее то, что отмечено плюсами (плюсы, естественно, нужно убрать).
OTRS::ITSM 5.0.5

BOYARIN
OTRS Новобранец
Сообщения: 1
Зарегистрирован: 24 сен 2013, 13:23

Re: Интеграция OTRS и Asterisk

Сообщение BOYARIN » 24 сен 2013, 13:29

2 alex:

Все работает, спасибо за отличную идею реализации.
Правда Extension (из поля "Комментарий") я передаю прямо через JS (без парсинга сессии).

У меня вопрос: как же все-таки добавить динамические поля для агента? (чтобы сделать по красоте поле Extension, а не комментарий).
Весь инет перерыл - не могу найти.

Последняя инстанция - файл User.pm, но че-то как-то совсем не хочется его править.

skeleton
OTRS Новобранец
Сообщения: 2
Зарегистрирован: 12 авг 2013, 01:30

Re: Интеграция OTRS и Asterisk

Сообщение skeleton » 25 сен 2013, 08:59

Кто подскажет куда конкретно класть, в какую папку и прочее phony.php connect.php и что куда прикручивать.
Как то вся процедура поверхностно написана. можно конкретики в каждом действии что делать.

alex
OTRS Новобранец
Сообщения: 48
Зарегистрирован: 01 ноя 2010, 14:47
Откуда: Воронеж
Контактная информация:

Re: Интеграция OTRS и Asterisk

Сообщение alex » 14 окт 2013, 14:46

BOYARIN писал(а):2 alex:

Все работает, спасибо за отличную идею реализации.
Правда Extension (из поля "Комментарий") я передаю прямо через JS (без парсинга сессии).

У меня вопрос: как же все-таки добавить динамические поля для агента? (чтобы сделать по красоте поле Extension, а не комментарий).
Весь инет перерыл - не могу найти.

Последняя инстанция - файл User.pm, но че-то как-то совсем не хочется его править.
Добавил скриншот, вроде бы это все, что нужно сделать, но точно уже не помню.
Вложения
agent_dynamic_field.jpeg
agent_dynamic_field.jpeg (132.99 КБ) 17078 просмотров
OTRS::ITSM 5.0.5

belko54
OTRS Новобранец
Сообщения: 7
Зарегистрирован: 03 май 2012, 11:41

Re: Интеграция OTRS и Asterisk

Сообщение belko54 » 12 окт 2016, 09:13

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 -->
[/quote]
Код уже устарел? на OTRS 3.3.8 не взлетает(((

Ответить