CRM

Customer Relationship Management - управление взаимоотношениями с клиентами (управление лояльностью)

CRM-система - Корпоративная информационная система, предназначенная для автоматизации стратегии CRM, в частности, для повышения уровня продаж, оптимизации деятельности отдела маркетинга, продаж и закупок и повышения лояльности (за счет роста качества обслуживания клиентов), путём сохранения информации о действующих клиентах (контрагентах) в единой базе ( + всей истории взаимоотношений с ними ), установления и улучшения бизнес-процессов и последующего анализа полученных результатов.

Asterisk + Amocrm

AmoCRM популярное облачное решение с более-менее нормальным вижетом для Asterisk.
Само-подписанный SSl сертификат годится только для тестов,
для продакшена ОБЯЗАТЕЛЬНО требуется доверенный сертификат веб сервера выписанный на ваше доменное имя.
Данное руководство дает справочную информацию о настройке и тестировании интеграции Asterisk и AmoCRM и предполагает, что вы имеете базовые знания о Linux и Asterisk.
Настройку можно разделить на 4 основных этапа:

  • Настройка Asterisk
    • /etc/asterisk/manager.conf
    • /etc/asterisk/httpd.conf
  • Конфигурация скрипта
    • amocrm.php
  • Настройка ssl сертификата веб сервера.
  • Настройка вижета в AmoCRM

Скрипт amocrm.php должен быть доступен снаружи сети. Таким образом, если сервер Asterisk находится за nat, вам потребуется открыть веб сервер на asterisk, для доступа извне. Внешний адрес за которым находится Asterisk, должен быть указан как цель для используемого доменного имени.
Сертификат может быть выписан на доменное имя третьего уровня, например: asterisk.yourdomain.com.
Доменное имя должно быть назначено серверу Asterisk.
Несмотря на обширный текст, настройка данного решения довольно проста. Большая часть материала посвящена тонкой доводке и возможно не потребуется.

Настройка AMI и AJAM

Со стороны Asterisk требуется только включить AJAM: /etc/asterisk/manager.conf

[general]
enabled = yes
port = 5038
bindaddr = 0.0.0.0
webenabled = yes
httptimeout = 60

создать пользователя AMI для AmoCRM

[amocrm]
secret = PASSWORD
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
read = cdr,reporting,originate
write = reporting,originate

и включить встроенный http сервер
Во FreePBX: FreePBX: Settings > advanced_settings

или в конфиге Asterisk: /etc/asterisk/http.conf

[general]
enabled=yes
enablestatic=yes
bindaddr=0.0.0.0
bindport=8088
prefix=asterisk

Тест AJAM интерфейса

http status

http status

asterisk*CLI> http show status
HTTP Server Status:
Prefix: /asterisk
Server: Asterisk/13.2.0
Server Enabled and Bound to 0.0.0.0:8088

Enabled URI's:
/asterisk/httpstatus => Asterisk HTTP General Status
/asterisk/amanager => HTML Manager Event Interface w/Digest authentication
/asterisk/arawman => Raw HTTP Manager Event Interface w/Digest authentication
/asterisk/manager => HTML Manager Event Interface
/asterisk/rawman => Raw HTTP Manager Event Interface
/asterisk/static/... => Asterisk HTTP Static Delivery
/asterisk/amxml => XML Manager Event Interface w/Digest authentication
/asterisk/mxml => XML Manager Event Interface
/asterisk/ws => Asterisk HTTP WebSocket

Enabled Redirects:
  None.

https://asterisk_ip:8088/asterisk/httpstatus?action=login&username=<ami_user>&secret=<ami_password>

https://asterisk_ip:8088/asterisk/rawman?action=login&username=<ami_user>&secret=<ami_password>

 Response: Success
 Message: Authentication accepted

Скрипт AmoCRM

AmoCRM получает данные от Asterisk через GET запросы к скрипту, который в свою очередь,
запрашивает данные у Астера через AJAM или AMI и SQL запросами к БД asteriskcdrdb.

Базовая конфигурация скрипта

Сначала вам потребуется задать параметры доступа к базе данных asteriskcdrdb,
префикс AJAM, а также путь к директории записей.

  • AC_HOST - ip/hostname сервера AMI/AJAM (localhost)
  • AC_PORT - порт сервера AMI/AJAM (если AMI то пусто, если AJAM то 8088)
  • AC_PREFIX - префикс заданный в http.conf астериска (например: prefix=asterisk)
  • AC_DB_UNAME - пользователь БД asteriskcdrdb
  • AC_DB_UPASS - пароль БД asteriskcdrdb (можно посмотреть в файлах cdr_mysql.conf или res_odbc.conf
  • AC_RECORD_PATH путь к записям разговоров

Рассмотрим обще-употребимый пример получения записей из FreePBX.
Записи по умолчанию расположены в директории: /var/spool/asterisk/monitor/Год/Месяц/День
Создадим в веб директории в которой расположен скрипт мягкую ссылку на директорию записей Asterisk:

 ln -s /var/spool/asterisk/monitor monitor

Чтобы затруднить доступ к директории запретите листениг в файле .htaccess

  Options -Indexes 

В этом случае ссылка в скрипте amocrm будет выглядеть так:

https://ваше_доменное_имя/веб_директория_скрипта/monitor/%Y/%m/%d/#

Приведенные ниже рассуждения и примеры о получении записей относятся к версии php скрипта из этой статьи. Возможно, у вас есть более актуальная версия, но общие положения должны быть верны.
На этапе первоначальной установки и конфигурации можно пропустить.

Для отображения записей в AmoCRM, возможно, потребуется модифицировать SQL запросы в скрипте:

Получение имени файла из базы данных asteriskcdrdb производится по запросу:

GET ../amocrm.php?GETFILE=1505491053.1619

где 1505491053.1619 UNIQUEID вызова.
Скрипт amocrm в свою очередь пытается получить имя файла из колонки recordingfile БД asteriskcdrdb и таблицы cdr следующим запросом:

SELECT calldate,recordingfile FROM cdr WHERE uniqueid= :uid

где uid это UNIQUEID из GET запроса.

Но по этому запросу БД может выдать несколько строк с совпадающим UNIQUEID и только в одной будет задано recordingfile Например, в случае, если запись включена в настройках екстеншена, а вызов поступает сначала в группу или очередь, а только потом на екстеншен. Ситуация описана для FreePBX.

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

+---------------------+-------------------------------------------------------------+
| calldate            | recordingfile                                               |
+---------------------+-------------------------------------------------------------+
| 2017-09-15 18:57:33 |                                                             |
| 2017-09-15 18:57:33 |                                                             |
| 2017-09-15 18:58:00 | external-02-666-20170915-185733-1505491053.1619.wav     |
+---------------------+-------------------------------------------------------------+

В этом случае надо либо включить запись в настройках группы или очереди,
или, например, модифицировать зарос следующим образом, чтобы получать только одну, последнюю запись из БД.

SELECT calldate,recordingfile FROM cdr WHERE uniqueid= :uid order by calldate DESC limit 1

или
сохраним UNIQUEID в переменную $recfile:

 $recfile = $_GET['GETFILE']; 

а искать будем не по колонке uniqueid, а по recordingfile:

 SELECT calldate, recordingfile FROM cdr WHERE recordingfile like '%$recfile%';

Данные CDR в БД AmoCRM передаются по запросу (каждые 40 минут):

GET .. /amocrm.php?_login=<AMI_LOGIN>&_secret=<AMI_PASSWORD>&_action=cdr&date_from=<дата_от>&date_to=<и_до>

По которому, в свою очередь, скрипт делает выборку из БД следующего вида:

SELECT calldate,src,dst,duration,billsec,uniqueid,recordingfile FROM cdr WHERE disposition=\'ANSWERED\' AND billsec>=:minsec AND calldate> :from AND calldate< :to

По данной выборке в БД AmoCRM будут попадать все вызовы включая местные.
Если вы хотите избавиться, например, от внутренних вызовов, то можно модифицировать запрос следующим образом. В приведенном примере отфильтрованы вызовы с номеров 100-199.
добавив следующее условие AND src NOT RLIKE "^1xx"

SELECT calldate, src,dst,duration,billsec,uniqueid,recordingfile FROM cdr WHERE disposition=\'ANSWERED\'
AND src NOT RLIKE "^1xx" AND billsec>=:minsec AND calldate> :from AND calldate< :to

И так далее по образу и подобию, по вашим условиям.


Скрипт AmoCRM

Расположите скрипт в веб директории сервера asterisk.
В приведенных ниже примерах скрипт расположен в корне - /var/www/html/amocrm.php,
но лучше разместить его в директории с неявным именем.
Например:

  • /var/www/html/amo/amocrm.php - плохо
  • /var/www/html/09q2393ig5gj48u39203r2rR/amosramoboombarum.php - хорошо

amocrm.php

amocrm.php

<?php
/*
        amoCRM to  asterisk integration.
        mailto: info@asterisk-pbx.ru
        Date:   21.09.2017  
                         _____ _____  __  __
                        / ____|  __ \|  \/  |
   __ _ _ __ ___   ___ | |    | |__) | \  / |
  / _` | '_ ` _ \ / _ \| |    |  _  /| |\/| |
 | (_| | | | | | | (_) | |____| | \ \| |  | |_
  \__,_|_| |_| |_|\___/ \_____|_|  \_\_|  |_(_)
 
 
 
 */
ini_set('display_errors',0);
define('AC_HOST','localhost');
define('AC_PORT',8088);
define('AC_PREFIX','/aster/');
define('AC_TLS',false);
define('AC_DB_CS','mysql:host=localhost;port=3306;dbname=asteriskcdrdb');
define('AC_DB_UNAME','db_user');
define('AC_DB_UPASS','db_password');
define('AC_TIMEOUT',0.75);
define('AC_RECORD_PATH','https://hostname/amo_dir/monitor/%Y/%m/%d/#');
define('AC_TIME_DELTA',3); // hours. Ex. GMT+4 = 4
 
 
$db_cs=AC_DB_CS;
$db_u=!strlen(AC_DB_UNAME)?NULL:AC_DB_UNAME;
$db_p=!strlen(AC_DB_UPASS)?NULL:AC_DB_UPASS;
date_default_timezone_set('UTC');
 
 
if (AC_PORT<1) die('Please, configure settings first!'); // die if not
if (defined('AC_RECORD_PATH') AND !empty($_GET['GETFILE'])){
        //get file. Do not check auth. (uniqueid is rather unique)
        $p=AC_RECORD_PATH;
        if (empty($p)) die('Error while getting file from asterisk (no path)');
        try {
                $dbh = new PDO($db_cs, $db_u, $db_p);
                $sth = $dbh->prepare('SELECT calldate,recordingfile FROM cdr WHERE uniqueid= :uid order by calldate DESC limit 1');
                $sth->bindValue(':uid',strval($_GET['GETFILE']));
                $sth->execute();
                $r = $sth->fetch(PDO::FETCH_ASSOC);
                if ($r===false OR empty($r['recordingfile'])) die('Error while getting file from asterisk (no filename in select)');
                $date=strtotime($r['calldate']);
                $replace=array();
                $replace['#']=$r['recordingfile'];
                $dates=array('d','m','Y','y');
                foreach ($dates as $d) $replace['%'.$d]=date($d,$date); // not a good idea!
                $p=str_replace(array_keys($replace),array_values($replace),$p);
                if (empty($_GET['noredirect'])) header('Location: '.$p);
                die($p);
        } catch (PDOException $e) {
                die('Error while getting file from asterisk');
        }
}
 
 
// filter parameters from _GET
foreach (array('login','secret','action') as $k){
        if (empty($_GET['_'.$k])) die('NO_PARAMS');
        $$k=strval($_GET['_'.$k]);
}
// trying to check accacess
$loginArr=array(
        'Action'=>'Login',
        'username'=>$login,
        'secret'=>$secret,
//      'Events'=>'off',
);
$resp=asterisk_req($loginArr,true);
// problems? exiting
if ($resp[0]['response']!=='Success') answer(array('status'=>'error','data'=>$resp[0]));
 
//auth OK. Lets perform actions
if ($action==='status'){ // list channels status
        $params=array( 'action'=>'status');
        $resp=asterisk_req($params);
        // report error of any
        if ($resp[0]['response']!=='Success') answer(array('status'=>'error','data'=>$resp[0]));
        // first an last chunks are useless
        unset($resp[end(array_keys($resp))],$resp[0]);
        // renumber keys for JSON
        $resp=array_values($resp);
        // report OK
        answer(array('status'=>'ok','action'=>$action,'data'=>$resp));
 
}elseif ($action==='call'){ // originate a call
        $params=array(
                'action'=>'Originate',
                'channel'=>'Local/'.$_GET['from'].'@from-internal',
                'Exten'=>strval($_GET['to']),
                'Context'=>'from-internal',
                'priority'=>'1',
                'Callerid'=>'"'.strval($_GET['as']).'" <'.intval($_GET['from']).'>',
                'Async'=>'Yes',
                // Not Implemented:
                //'Callernumber'=>'150',
                //'CallerIDName'=>'155',
        );
        $resp=asterisk_req($params,true);
        if ($resp[0]['response']!=='Success') answer(array('status'=>'error','data'=>$resp[0]));
        answer(array('status'=>'ok','action'=>$action,'data'=>$resp[0]));
 
} elseif ($action==='test_cdr'){ // test if DB connection params are OK.
        if (!class_exists('PDO')) answer(array('status'=>'error','data'=>'PDO_NOT_INSTALLED')); // we use PDO for accessing mySQL pgSQL sqlite within same algorythm
        try {
                $dbh = new PDO($db_cs, $db_u, $db_p);
        } catch (PDOException $e) {
                answer(array('status'=>'error','data'=>$e->getMessage()));
        }
        answer(array('status'=>'ok','data'=>'connection ok'));
} elseif ($action==='cdr'){ // fetch call history
        try {
                $dbh = new PDO($db_cs, $db_u, $db_p);
 
                foreach (array('date_from','date_to') as $k){
                        $v=doubleval( (!empty($_GET[$k]))?intval($_GET[$k]):0 );
                        if ($v<0) $v=time()-$v;
                        $$k=$v;
                }
                if ($date_from<time()-10*24*3600) $date_from=time()-7*24*3600; //retr. not more than 10d before
                $date_from=($date_from?$date_from+AC_TIME_DELTA*3600:0); //default 01-01-1970
                $date_to  =($date_to  ?$date_to  +AC_TIME_DELTA*3600:time()+AC_TIME_DELTA*3600);//default now()
                $sth = $dbh->prepare('SELECT calldate, src,dst,duration,billsec,uniqueid,recordingfile FROM cdr WHERE disposition=\'ANSWERED\' AND billsec>=:minsec AND calldate> :from AND calldate< :to');
                // BETWEEN is illegal on some bcknds
                header("X-REAL_DATE:" . gmdate('Y-m-d H:i:s',$date_from).'@'. gmdate('Y-m-d H:i:s',$date_to));
                $sth->bindValue(':from', date('Y-m-d H:i:s',$date_from) );
                $sth->bindValue(':to',   date('Y-m-d H:i:s',$date_to));
                $sth->bindValue(':minsec',!empty($_GET['minsec'])?$_GET['minsec']:5,PDO::PARAM_INT);
                $sth->execute();
                //$sth->debugDumpParams();      var_dump($sth->errorInfo());
                $r = $sth->fetchAll(PDO::FETCH_ASSOC);
                foreach ($r as $k=>$v) $r[$k]['calldate']=date('Y-m-d H:i:s',strtotime($v['calldate'])-AC_TIME_DELTA*3600);
                answer(array('status'=>'ok','data'=>$r),true);
        } catch (PDOException $e) {
                answer(array('status'=>'error','data'=>$e->getMessage()),true);
        }
} elseif ($action==='pop'){// fill test data. Maybe you will need it. Just comment line below.
        die();
        $dbh = new PDO($db_cs, $db_u, $db_p);
        for ($i=0;$i<(int)$_GET['n'];$i++){
                $array=array(
                        date('Y-m-d H:i:s',time()-rand(100,7*24*3600)),
                        'Auto <150>', 150,'791612345678','n/a','n/a','n/a','n/a','n/a',999, rand(7,999), 'ANSWERED',3,'',uniqid(),'','',''
                );
                $str=array();
                foreach ($array as  $v) $str[]="'{$v}'";
                $str=implode(', ',$str);
                $dbh->query("INSERT INTO cdr VALUES ({$str});");
        }
}
 
/** MakeRequest to asterisk interfacees
 * @param $params -- array of req. params
 * @return array -- response
 */
function asterisk_req($params,$quick=false){
        // lets decide if use AJAM or AMI
        return !defined('AC_PREFIX')?ami_req($params,$quick):ajam_req($params);
}
 
/**
 * Shudown function. Gently close the socket
 */
function asterisk_socket_shutdown(){ami_req(NULL);}
 
/*** Make request with AMI
 * @param $params -- array of req. params
 * @param bool $quick -- if we need more than action result
 * @return array result of req
 */
function ami_req($params,$quick=false){
        static $connection;
        if ($params===NULL and $connection!==NULL) {
                // close connection
                fclose($connection);
                return;
        }
        if ($connection===NULL){
                $en=$es='';
                $connection = fsockopen(AC_HOST, AC_PORT, $en, $es, 3);
                // trying to connect. Return an error on fail
                if ($connection) register_shutdown_function('asterisk_socket_shutdown');
                else {$connection=NULL; return array(0=>array('response'=>'error','message'=>'socket_err:'.$en.'/'.$es));}
        }
        // building req.
        $str=array();
        foreach($params as $k=>$v) $str[]="{$k}: {$v}";
        $str[]='';
        $str=implode("\r\n",$str);
        // writing
        fwrite($connection,$str."\r\n");
        // Setting stream timeout
        $seconds=ceil(AC_TIMEOUT);
        $ms=round((AC_TIMEOUT-$seconds)*1000000);
        stream_set_timeout($connection,$seconds,$ms);
        // reading respomse and parsing it
        $str= ami_read($connection,$quick);
        $r=rawman_parse($str);
        //var_dump($r,$str);
        return $r;
}
/*** Reads data from coinnection
 * @param $connection -- active connection
 * @param bool $quick -- should we wait for timeout or return an answer after getting command status
 * @return string RAW response
 */
function ami_read($connection,$quick=false){
        $str='';
        do {
                $line = fgets($connection, 4096);
                $str .= $line;
                $info = stream_get_meta_data($connection);
                if ($quick and $line== "\r\n") break;
        }while ($info['timed_out'] == false );
        return $str;
}
 
/*** Echo`s data
 * @param $array answer data
 * @param bool $no_callback shold we output as JSON or use callback function
 */
function answer($array,$no_callback=false){
        header('Content-type: text/javascript;');
        if (!$no_callback)  echo "asterisk_cb(".json_encode($array).');';
        else echo json_encode($array);
        die();
}
 
/** Parse RAW response
 * @param $lines RAW response
 * @return array parsed response
 */
function rawman_parse($lines){
        $lines=explode("\n",$lines);
        $messages=array();
        $message=array();
 
        foreach ($lines as $l){
                $l=trim($l);
                if (empty($l) and count($message)>0){ $messages[]= $message;  $message=array(); continue;}
                if (empty($l))  continue;
                if (strpos($l,':')===false)  continue;
                list($k,$v)=explode(':',$l);
                $k=strtolower(trim($k));
                $v=trim($v);
                if (!isset( $message[$k]))  $message[$k]=$v;
                elseif (!is_array( $message[$k]))  $message[$k]=array( $message[$k],$v);
                else  $message[$k][]=$v;
        }
        if (count($message)>0) $messages[]= $message;
        return $messages;
}
 
 
/** Make request via AJAM
 * @param $params req. params
 * @return array parsed resp.
 */
function ajam_req($params){
        static $cookie;
        // EveryRequest Ajam sends back a cookir, needed for auth handling
        if ($cookie===NULL) $cookie='';
        // make req. and store cookie
        list($body,$cookie)= rq(AC_PREFIX.'rawman?'.http_build_query($params),$cookie);
        // parse an answer
        return rawman_parse($body);
}
 
/** make http req. to uri with cookie, parse resp and fetch a new cookie
 * @param $url
 * @param string $cookie
 * @return array  ($body,$newcookie)
 */
function rq($url,$cookie=''){
        // get RAW data
        $r=_rq($url,$cookie);
        // divide in 2 parts
        list($headersRaw,$body)=explode("\r\n\r\n",$r,2);
        // parse headers
        $headersRaw=explode("\r\n",$headersRaw);
        $headers=array();
        foreach ($headersRaw as $h){
                if (strpos($h,':')===false) continue;
                list($hname,$hv)=explode(":",$h,2);
                $headers[strtolower(trim($hname))]=trim($hv);
        }
        // fetch cookie
        if (!empty($headers['set-cookie'])){
                $listcookies=explode(';',$headers['set-cookie']);
                foreach ($listcookies as $c){
                        list($k,$v)=explode('=',trim($c),2);
                        if ($k=='mansession_id') $cookie=$v;
                }
        }
 
        return array($body,$cookie);
}
 
/**  mare a request to URI and return RAW resp or false on fail
 * @param $url
 * @param $cookie
 * @return bool|string
 */
function _rq($url,$cookie){
        $errno=$errstr="";
        $fp = fsockopen(AC_HOST, AC_PORT, $errno, $errstr, 3);
        if (!$fp) return false;
        $out = "GET {$url} HTTP/1.1\r\n";
        $out .= "Host: ".AC_HOST."\r\n";
        if (!empty($cookie)) $out.="Cookie: mansession_id={$cookie}\r\n";
        $out .= "Connection: Close\r\n\r\n";
        fwrite($fp, $out);
        $r='';
        while (!feof($fp)) $r.=fgets($fp);
        fclose($fp);
        return $r;
}

Скрипт обрабатывает следующие запросы:

В зависимости от типа запросов они инициируется либо с IP-адреса сервера AmoCRM, либо с IP пользователя, работающего в AmoCRM.

  • status - core show channels (c ip пользователя)
  • test_cdr - Проверка соединения c БД asteriskcdrdb
  • cdr - Выборка из БД asteriskcdrdb.cdr (c ip сервера)
  • GETFILE - Получение файла записи разговора. (c ip пользователя)
  • call - Инициирует originate. (c ip пользователя)

Команда call позволяет инициировать соединение двух екстеншенов. Это функция потенциально опасна и требует дополнительных мер защиты. Например запретить обращение к веб серверу всем кроме AmoCRM и IP адресов с которых работают пользователи AmoCRM (что может быть проблематично, если пользователи работают из разных мест). Актуальный адрес с которого идут запросы AmoCRM на осень 2017 года: 88.212.249.27
Если вам не требуется данный функционал, просто запретите его использование в конфигурации пользователя amocrm в /etc/asterisk/manager.conf удалив опцию originate:

[amocrm]
secret = PASSWORD
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
read = cdr,reporting
write = reporting

Поверка работы скрипта:

status

https://host/amocrm.php?_login=<ami_user>&_secret=<ami_password>&_action=status

 asterisk_cb({"status":"ok","action":"status","data":[]});

test_cdr

https://host/amocrm.php?_login=<ami_user>&_secret=<ami_password>&_action=test_cdr

 asterisk_cb({"status":"ok","data":"connection ok"});

cdr

https://host/amocrm.php?_login=<ami_user>&_secret=<ami_password>&_action=cdr

cdr

cdr

{"calldate":"2015-03-11 12:38:16","src":"2274","dst":"3900","duration":"95","billsec":"87","uniqueid":"1426077496.1805","recordingfile":""},{"calldate":"2015-03-11 
12:39:24","src":"3710","dst":"9xxxxxxxxx","duration":"74","billsec":"59","uniqueid":"1426077564.1817","recordingfile":""},{"calldate":"2015-03-11 
12:41:56","src":"2776","dst":"3848","duration":"8","billsec":"8","uniqueid":"1426077716.1907","recordingfile":""},{"calldate":"2015-03-11 
12:42:28","src":"2274","dst":"4321","duration":"7","billsec":"7","uniqueid":"1426077748.1923","recordingfile":""},{"calldate":"2015-03-11 
12:42:59","src":"3892","dst":"2274","duration":"115","billsec":"113","uniqueid":"1426077779.1949","recordingfile":""},{"calldate":"2015-03-11 
12:43:29","src":"4108","dst":"2207","duration":"71","billsec":"69","uniqueid":"1426077809.1957","recordingfile":""},{"calldate":"2015-03-11 
12:45:06","src":"2776","dst":"3848","duration":"23","billsec":"16","uniqueid":"1426077906.2023","recordingfile":""},{"calldate":"2015-03-11 
12:46:12","src":"2373","dst":"3914","duration":"239","billsec":"235","uniqueid":"1426077972.2055","recordingfile":""},{"calldate":"2015-03-11 

call

 amocrm.php?_login=<ami_login>&_secret=<ami_password>&_action=call&from=<TEL>&to=<TEL>

За обработку запроса call отвечает ниже приведенный код скрипта.
Возможно вам понадобится изменить имя исходящего контекста с from-internal,
на нужное вам.

}elseif ($action==='call'){ // originate a call
        $params=array(
                'action'=>'Originate',
                'channel'=>'Local/'.$_GET['from'].'@from-internal',
                'Exten'=>strval($_GET['to']),
                'Context'=>'from-internal',
                'priority'=>'1',
                'Callerid'=>'"'.strval($_GET['as']).'" <'.intval($_GET['from']).'>',
                'Async'=>'Yes',
        );

Посмотреть запросы можно в логе ssl_access_log веб сервера:

 tail -f /var/log/httpd/ssl_access_log

Настройка сертификата

Рассмотрим установку популярного сертификата от Comodo на веб сервер apache в CentOS 7. Скачайте и распакуйте архив с сертификатами на сервер

 AddTrustExternalCARoot.crt
 your_domain_com.crt
 COMODORSAAddTrustCA.crt
 COMODORSADomainValidationSecureServerCA.crt

Создайте директорию для сертификатов:

 mkdir /etc/pki/tls/cert

Создайте файл ключа

  touch /etc/pki/tls/cert/your_domain_com.key   

И скопируйте в него ключ.

Объедините файлы crt.

 cat your_domain_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > /etc/pki/tls/cert/ssl-bundle.crt

Включите ssl и укажите путь к созданным файлам /etc/httpd/conf.d/ssl.conf:

  SSLEngine on
  SSLCertificateKeyFile /etc/pki/tls/cert/your_domain_com.key
  SSLCertificateFile /etc/pki/tls/cert/ssl-bundle.crt

Задайте серверу доменное имя /etc/sysconfig/network

 HOSTNAME=your.domain.com

Добавьте имя в /etc/hosts:

 внешний_IP  your.domain.com hostname

Выполните команду hostname из командной строки

 hostname your.domain.com

Сделайте рестарт httpd и network

AmoCRM вижет

Дополнительно

При помощи модуля CallerID Lookup вы может подставлять имена клиентов из AmoCRM в CALLERID(name) asterisk.

FreePBX: admin > CallerID Lookup Sources

  • Host = yourhost.amocrm.ru
  • Port = 443
  • Username = ami_login
  • Password = ami_pass
  • Path = /private/acceptors/asterisk_new/
  • Query = number=[NUMBER]&USER_LOGIN=AMO_USER_LOGIN&USER_HASH=<HASH>

FreePBX: Connectivity > Inbound Routes
Подключите созданный CallerID Lookup в нужном входящем маршруте:

Нажмите, чтобы отобразить

Нажмите, чтобы скрыть

[root@asterisk ~]# cat /etc/asterisk/extensions_additional.conf | grep cidlookup
[cidlookup]
exten => cidlookup_1,1,Set(CURLOPT(httptimeout)=7)
exten => cidlookup_1,n,Set(CALLERID(name)=${CURL(https://api.opencnam.com/v2/phone/${CALLERID(num)}?format=pbx&ref=freepbx)})
exten => cidlookup_1,n,Set(current_hour=${STRFTIME(,,%Y-%m-%d %H)})
exten => cidlookup_1,n,Set(last_query_hour=${DB(cidlookup/opencnam_last_query_hour)})
exten => cidlookup_1,n,Set(total_hourly_queries=${DB(cidlookup/opencnam_total_hourly_queries)})
exten => cidlookup_1,n,ExecIf($["${last_query_hour}" != "${current_hour}"]?Set(DB(cidlookup/opencnam_total_hourly_queries)=0))
exten => cidlookup_1,n,ExecIf($["${total_hourly_queries}" = ""]?Set(DB(cidlookup/opencnam_total_hourly_queries)=0))
exten => cidlookup_1,n,Set(DB(cidlookup/opencnam_total_hourly_queries)=${MATH(${DB(cidlookup/opencnam_total_hourly_queries)}+1,i)})
exten => cidlookup_1,n,ExecIf($[${DB(cidlookup/opencnam_total_hourly_queries)} >= 60]?System(${ASTVARLIBDIR}/bin/opencnam-alert.php))
exten => cidlookup_1,n,Set(DB(cidlookup/opencnam_last_query_hour)=${current_hour})
exten => cidlookup_1,n,Return()
exten => cidlookup_2,1,GotoIf($[${DB_EXISTS(cidname/${CALLERID(num)})} = 1]?cidlookup,cidlookup_return,1)
exten => cidlookup_2,n,Set(CURLOPT(httptimeout)=7)
exten => cidlookup_2,n,Set(CALLERID(name)=${CURL(https://<ami_user>:<ami_password>@<amo_account>.amocrm.ru:443/private/acceptors/asterisk_new/?number=${CALLERID(num)}&USER_LOGIN=amo_user@mail.tld&USER_HASH=xxxxxxxxxxxxxxxxxxxxxxxxxxx)})
exten => cidlookup_2,n,Set(DB(cidname/${CALLERID(num)})=${CALLERID(name)})
exten => cidlookup_2,n,Return()
exten => cidlookup_return,1,ExecIf($["${DB(cidname/${CALLERID(num)})}" != ""]?Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})}))
exten => cidlookup_return,n,Return()
;--== end of [cidlookup] ==--;
exten => _X.,n,Gosub(cidlookup,cidlookup_2,1())
[root@asterisk ~]# cat /etc/asterisk/extensions_override_freepbx.conf | grep cidlookup
[cidlookup]
include => cidlookup_custom
exten => cidlookup_2,1,Set(CALLERID(name)=${SHELL(wget -O - --quiet https://<amo_account>.amocrm.ru/private/acceptors/asterisk_new/?number=${CALLERID(num)}\&USER_LOGIN=amo_user@mail.tld\&USER_HASH=xxxxxxxxxxxxxxxxxxxxxxxxxx)})
exten => cidlookup_2,n,Return()
exten => cidlookup_return,1,ExecIf($["${DB(cidname/${CALLERID(num)})}" !=""]?Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})}))
exten => cidlookup_return,n,Return()

ссылки по теме: Описание функций ~~socialite~~

2016/11/26

asterCRM

Программное обеспечение для создания Call Center на базе Asterisk. Предоставляет функции - всплывающего окна с информацией о звонящем из базы данных; интеллектуального набора; Click-to-call; Статус абонента; Запись разговоров; Группы операторов, супервайзеров, администраторов.

смотри также: Установка AsterCRM Call Center
http://astercc.org

Приложения

2016/11/26

VTiger 6 CRM

  • vTiger CRM — система управления взаимоотношениями с клиентами (CRM) с открытым кодом (Open Source).
  • vTiger CRM построен на LAMP (Linux, Apache, MySQL, PHP).
  • Новый коннектор для связи с Asterisk написан на Java и работает значительно стабильнее, чем в версии 5.4
  • Реализована интеграция с Asterisk версии 1.8 (Asterisk Manager Interface 1.1).
  • На официальном сайте заявлена также возможность интеграции с Plivo и Twilio.

Всплывающие окно входящего вызова (call popups)

При входящем вызове, когда вызов поступает на телефон привязанный к аккаунту агента VTiger,
всплывает окно сообщающее о вызове и предлагающее создать полноценный Контакт или Обращение.

vtiger pbxmanager incoming call

Детализированный отчет о звонках

Ведется полный отчет о совершенных вызовах и запись телефонных переговоров.
Доступна функция Click-To-Call. Если кликнуть на сохраненный номер в отчете о звонках или Контакте, Организации и т.д.,
VTiger вызовет сначала внутренний номер агента, привязанный к аккаунту VTiger,
а когда агент поднимет трубку произведет набор внешнего номера.

vtiger cdr

Подробная информация о вызове.

vtiger pbxmanager detail call

Сохраненный контакт.

Каждую запись в Vtiger легко найти и отредактировать.
Благодаря продуманной структуре вся связанная с клиентом информация, также будет под рукой.
Чтобы вы ни искали - Обращения, Контакты, Организации или Контрагентов, вы увидите связанные с ними сообщения емайл, сделки и заметки.

vtiger contact

Взаимодействуйте с вашими клиентами, где бы вы ни были.

Мобильные приложения на IPhone, iPad и Android реализуют множество функций:

  • Просмотр, редактирование и создание CRM записей.
  • Доступ оффлайн к информации.
  • Автоматическое добавление мобильных вызовов в Контакты (Android)
  • Настройка мобильных оповещений и задач.
  • Импорт Контактов из сфотографированных визитных карточек.

iphone ipad android

Расширения

vtiger

Скачать VTiger 6.x

VTiger Asterisk Connector

https://www.vtiger.com/crm-integrations-extensions/

Asterisk + VTigerCRM 6.1

  • vTiger CRM — система управления взаимоотношениями с клиентами (CRM) с открытым кодом (Open Source).
  • vTiger CRM построен на LAMP (Linux, Apache, MySQL, PHP).
  • Новый коннектор для связи с Asterisk написан на Java и работает значительно стабильнее, чем в версии 5.4
  • Реализована интеграция с Asterisk версии 1.8 (Asterisk Manager Interface 1.1).

Предварительные требования для установки

1. Asterisk 1.8 (возможно Asterisk 11)

2. Java 1.7

 yum install java-1.7.0-openjdk.i686

Скачайте Asterisk Connector

 wget https://www.vtiger.com/products/apps/VtigerAsteriskConnector/VtigerAsteriskConnector-1.3.zip

Распакуйте в удобной для вас директории.

 unzip VtigerAsteriskConnector-1.3.zip

В данном примере /usr/local

Отредактируйте файл VtigerAsteriskConnector/conf/VtigerAsteriskConnector.properties

/*
 * Copyright (C) www.vtiger.com. All rights reserved.
 * @license Proprietary
 */

// Location where the application server will be running.
ServerIP   = 127.0.0.1
ServerPort = 50777

// Call Recordings storage path
StorageDir = /usr/local/VtigerAsteriskConnector/bin/rec

// Enable(true) or Disable(false) call recordings
Recording = true

// Location where the applications database files will be stored.
AsteriskAppDBPath = /var/spool/asterisk/system

// Asterisk Server Details
AsteriskServerPublicIP = 192.168.0.1
AsteriskServerIP   = 127.0.0.1
AsteriskServerPort = 5038
AsteriskUsername   = vtiger
AsteriskPassword   = vtiger_password

// Vtiger CRM URL
VtigerURL = http://127.0.0.1/vtigercrm/
VtigerSecretKey = 12345

//Enable(true) or Disable(false) Asterisk Events and Database Logs in Connector
AsteriskLog = true
DatabaseLog = true
Asterisk
ServerIP IP адрес на котором Asterisk Vtiger Connector будет работать.
ServerPort Порт на котором Asterisk Vtiger Connector будет работать .
StorageDir Путь к директории записи разговоров на сервере Asterisk.
Recording True/False - запись разговоров
AsteriskAppDBPath Путь для сохранения файла базы данных Vtiger Asterisk Connector на вашем сервере.
Asterisk Server Details
AsteriskServerPublicIP Внешний IP адрес сервера Asterisk.
AsteriskServerIP IP адрес сервера Asterisk
AsteriskServerPort Порт Asterisk Manager Interface (AMI).
AsteriskUsername Имя пользователя manager.conf на сервере Asterisk.
AsteriskPassword Пароль пользователя manager.conf на сервере Asterisk.
Vtiger
VtigerURL Vtiger Asterisk App URL.
VtigerSecretKey Vtiger Secret Key.

<fs large>CRM Settings > Integration > PBX Manager</fs>

<fs large>User > My Preference - More Information</fs>

Запуск VTiger Asterisk Connector

 cd /usr/local/VtigerAsteriskConnector/bin
[root@localhost bin]# ls -la
total 24
drwxrwxr-x 2 root root 4096 Dec  5 14:25 .
drwxrwxr-x 8 root root 4096 Dec  5 14:25 ..
-rwxrwxr-x 1 root root  339 Dec  5 14:25 agi.sh
-rwxrwxr-x 1 root root  228 Dec  5 14:25 start.sh
-rwxrwxr-x 1 root root  115 Dec  5 14:25 stop.sh
-rwxrwxr-x 1 root root  377 Dec  5 14:25 webapp.sh

запустим коннектор командой:

 ./start.sh

Автозагрузка скрипта в CentOS

  echo sh /usr/local/VtigerAsteriskConnector/bin/start.sh  >> /etc/rc.local

Если коннектор запущен, директория отобразится в браузере, по порту приложения (в примере 50777):

# ps aux | grep Vtiger
root      3117  0.0  0.1   5052  1220 pts/1    S    16:52   0:00 /bin/sh /usr/local/VtigerAsteriskConnector/bin/webapp.sh
root      3118  0.0  0.1   5052  1204 pts/1    S    16:52   0:00 /bin/sh /usr/local/VtigerAsteriskConnector/bin/agi.sh
root      3183  0.0  0.0   4352   728 pts/1    S+   16:52   0:00 grep Vtiger
[vtiger_out]
exten => _X.,1,Agi(agi://127.0.0.1/incoming.agi)


[fake_random_callerid_812]
exten => 1122334,1,Set(CALLERID(num)=812${RAND(2111111,9999999)})
exten => 1122334,n,Set(CALLERID(name)=CALLERID(num))
exten => 1122334,n,Agi(agi://127.0.0.1/incoming.agi)

модель событий AMI

модель событий AMI

НеправильноПравильно
Event: Newchannel
Privilege: call,all
Channel: SIP/1001-00000002
ChannelState: 0
ChannelStateDesc: Down
CallerIDNum: 1001
CallerIDName:
AccountCode:
Exten: 1000
Context: vtiger_out
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: SIPURI
Value: sip:1001@123.123.123.1:5091
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: SIPDOMAIN
Value: 124.124.124.1
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: SIPCALLID
Value: YjdmNTBiNTg5YjY3YTg5YTYwNTI3ZTc0OTVlOTgyZTA.
Uniqueid: 1423640748.2

Event: Newstate
Privilege: call,all
Channel: SIP/1001-00000002
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: 1001
CallerIDName:
ConnectedLineNum:
ConnectedLineName:
Uniqueid: 1423640748.2

Event: Newexten
Privilege: dialplan,all
Channel: SIP/1001-00000002
Context: vtiger_out
Extension: 1000
Priority: 1
Application: AGI
AppData: agi://127.0.0.1/incoming.agi
Uniqueid: 1423640748.2

Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1001-00000002
CommandId: 1568281865
Command: ANSWER

Event: Newstate
Privilege: call,all
Channel: SIP/1001-00000002
ChannelState: 6
ChannelStateDesc: Up
CallerIDNum: 1001
CallerIDName:
ConnectedLineNum:
ConnectedLineName:
Uniqueid: 1423640748.2

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1001-00000002
CommandId: 1568281865
Command: ANSWER
ResultCode: 200
Result: Success

Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1001-00000002
CommandId: 863625742
Command: EXEC "Monitor" "wav,/usr/local/
VtigerAsteriskConnector/bin/rec/0263ef66ecd84937b52052d654705393,m"

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: __MONITORED
Value: true
Uniqueid: 1423640748.2

Event: MonitorStart
Privilege: call,all
Channel: SIP/1001-00000002
Uniqueid: 1423640748.2

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1001-00000002
CommandId: 863625742
Command: EXEC "Monitor" "wav,/usr/local/
VtigerAsteriskConnector/bin/rec/0263ef66ecd84937b52052d654705393,m"
ResultCode: 200
Result: Success
====ERROR========
Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1001-00000002
CommandId: 2048191671
Command: EXEC "Dial" "SIP/, 60"

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: DIALSTATUS
Value:
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: DIALEDPEERNUMBER
Value:
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: DIALEDPEERNAME
Value:
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: ANSWEREDTIME
Value:
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: DIALEDTIME
Value:
Uniqueid: 1423640748.2
====ERROR=======
Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: DIALSTATUS
Value: INVALIDARGS
Uniqueid: 1423640748.2

Event: Dial
Privilege: call,all
SubEvent: End
Channel: SIP/1001-00000002
UniqueID: 1423640748.2
DialStatus: INVALIDARGS

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1001-00000002
CommandId: 2048191671
Command: EXEC "Dial" "SIP/, 60"
ResultCode: 200
Result: Unknown Result

Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1001-00000002
CommandId: 908355524
Command: SET VARIABLE "AJ_AGISTATUS" "SUCCESS"

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: AJ_AGISTATUS
Value: SUCCESS
Uniqueid: 1423640748.2

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1001-00000002
CommandId: 908355524
Command: SET VARIABLE "AJ_AGISTATUS" "SUCCESS"
ResultCode: 200
Result: Success

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: AGISTATUS
Value: SUCCESS
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: RTPAUDIOQOS
Value: ssrc=1499164886;themssrc=3683911828;lp=0;
rxjitter=0.000000;rxcount=136;txjitter=0.000590;txcount=0;rlp=0;rtt=0.000000
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: RTPAUDIOQOSJITTER
Value: minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0.000000;
stdevrxjitter=0.000000;reported_minjitter=0.000000;reported_maxjitter=0.000000;
reported_avgjitter=0.000000;reported_stdevjitter=0.000000;
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: RTPAUDIOQOSLOSS
Value: minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.000000;
stdevrxlost=0.000000;reported_minlost=0.000000;reported_maxlost=0.000000;
reported_avglost=0.000000;reported_stdevlost=0.000000;
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: RTPAUDIOQOSRTT
Value: minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrtt=0.000000;
Uniqueid: 1423640748.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1001-00000002
Variable: RTPAUDIOQOS
Value: ssrc=1499164886;themssrc=3683911828;lp=0;rxjitter=0.000000;rxcount=136;
txjitter=0.000590;txcount=0;rlp=0;rtt=0.000000
Uniqueid: 1423640748.2

Event: Hangup
Privilege: call,all
Channel: SIP/1001-00000002
Uniqueid: 1423640748.2
CallerIDNum: 1001
CallerIDName: <unknown>
ConnectedLineNum: <unknown>
ConnectedLineName: <unknown>
Cause: 0
Cause-txt: Unknown
Event: MonitorStop
Privilege: call,all
Channel: SIP/1001-00000002
Uniqueid: 1423640748.2
Event: Newchannel
Privilege: call,all
Channel: SIP/1111-00000000
ChannelState: 0
ChannelStateDesc: Down
CallerIDNum: 1111
CallerIDName: 1111
AccountCode:
Exten: 1122
Context: vtiger_out
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: SIPURI
Value: sip:1111@192.168.0.194:50518
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: SIPDOMAIN
Value: 192.168.0.67
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: SIPCALLID
Value: be1981dba7a041f28b1c0706f4a4929d
Uniqueid: 1423642071.0

Event: Newstate
Privilege: call,all
Channel: SIP/1111-00000000
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: 1111
CallerIDName: 1111
ConnectedLineNum:
ConnectedLineName:
Uniqueid: 1423642071.0

Event: Newexten
Privilege: dialplan,all
Channel: SIP/1111-00000000
Context: vtiger_out
Extension: 1122
Priority: 1
Application: AGI
AppData: agi://127.0.0.1/incoming.agi
Uniqueid: 1423642071.0

Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1111-00000000
CommandId: 1427834315
Command: ANSWER

Event: Newstate
Privilege: call,all
Channel: SIP/1111-00000000
ChannelState: 6
ChannelStateDesc: Up
CallerIDNum: 1111
CallerIDName: 1111
ConnectedLineNum:
ConnectedLineName:
Uniqueid: 1423642071.0
=====================cut RTCPReceved
Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1111-00000000
CommandId: 1427834315
Command: ANSWER
ResultCode: 200
Result: Success
==================Cut RTCPReceived
Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1111-00000000
CommandId: 226466943
Command: EXEC "Monitor" "wav,/usr/src/
VtigerAsteriskConnector/bin/rec/b884ad2e696e479b99a6884ed2afd882,m"

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: __MONITORED
Value: true
Uniqueid: 1423642071.0

Event: MonitorStart
Privilege: call,all
Channel: SIP/1111-00000000
Uniqueid: 1423642071.0

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1111-00000000
CommandId: 226466943
Command: EXEC "Monitor" "wav,/usr/src/VtigerAsteriskConnector/bin/rec/b884ad2e696e479b99a6884ed2afd882,m"
ResultCode: 200
Result: Success

Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1111-00000000
CommandId: 1957166649
Command: EXEC "Dial" "SIP/1122, 60"

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALSTATUS
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDPEERNUMBER
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDPEERNAME
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: ANSWEREDTIME
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDTIME
Value:
Uniqueid: 1423642071.0

Event: Newchannel
Privilege: call,all
Channel: SIP/1122-00000001
ChannelState: 0
ChannelStateDesc: Down
CallerIDNum: 1122
CallerIDName: 1122
AccountCode:
Exten:
Context: vtiger_out
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: SIPCALLID
Value: 31745c432fb52d7b3dbac8443aca170f@192.168.0.67:5060
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: DIALEDPEERNUMBER
Value: 1122
Uniqueid: 1423642078.1

Event: Dial
Privilege: call,all
SubEvent: Begin
Channel: SIP/1111-00000000
Destination: SIP/1122-00000001
CallerIDNum: 1111
CallerIDName: 1111
ConnectedLineNum: <unknown>
ConnectedLineName: <unknown>
UniqueID: 1423642071.0
DestUniqueID: 1423642078.1
Dialstring: 1122

Event: Newstate
Privilege: call,all
Channel: SIP/1122-00000001
ChannelState: 5
ChannelStateDesc: Ringing
CallerIDNum: 1122
CallerIDName: 1122
ConnectedLineNum: 1111
ConnectedLineName: 1111
Uniqueid: 1423642078.1
======Cut RTCPReceived
Event: Newstate
Privilege: call,all
Channel: SIP/1122-00000001
ChannelState: 6
ChannelStateDesc: Up
CallerIDNum: 1122
CallerIDName: 1122
ConnectedLineNum: 1111
ConnectedLineName: 1111
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALSTATUS
Value: ANSWER
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDPEERNAME
Value: SIP/1122-00000001
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDPEERNUMBER
Value: 1122
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: BRIDGEPEER
Value: SIP/1122-00000001
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: BRIDGEPEER
Value: SIP/1111-00000000
Uniqueid: 1423642078.1

Event: NewAccountCode
Privilege: call,all
Channel: SIP/1122-00000001
Uniqueid: 1423642078.1
AccountCode:
OldAccountCode:

Event: Bridge
Privilege: call,all
Bridgestate: Link
Bridgetype: core
Channel1: SIP/1111-00000000
Channel2: SIP/1122-00000001
Uniqueid1: 1423642071.0
Uniqueid2: 1423642078.1
CallerID1: 1111
CallerID2: 1122

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: BRIDGEPEER
Value: SIP/1122-00000001
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: BRIDGEPVTCALLID
Value: 31745c432fb52d7b3dbac8443aca170f@192.168.0.67:5060
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: BRIDGEPEER
Value: SIP/1111-00000000
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: BRIDGEPVTCALLID
Value: be1981dba7a041f28b1c0706f4a4929d
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: BRIDGEPEER
Value: SIP/1122-00000001
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: BRIDGEPVTCALLID
Value: 31745c432fb52d7b3dbac8443aca170f@192.168.0.67:5060
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: BRIDGEPEER
Value: SIP/1111-00000000
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: BRIDGEPVTCALLID
Value: be1981dba7a041f28b1c0706f4a4929d
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOS
Value: ssrc=94312286;themssrc=1304172298;lp=0;rxjitter=0.000000;rxcount=67;txjitter=0.001008;txcount=68;rlp=0;rtt=0.000000
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSBRIDGED
Value: ssrc=94312286;themssrc=1304172298;lp=0;rxjitter=0.000000;rxcount=67;txjitter=0.001008;txcount=68;rlp=0;rtt=0.000000
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSJITTER
Value: minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0.000000;stdevrxjitter=0.000000;reported_minjitter=0.000000;reported_maxjitter=0.000000;reported_avgjitter=0.000000;reported_stdevjitter=0.000000;
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSJITTERBRIDGED
Value: minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0.000000;stdevrxjitter=0.000000;reported_minjitter=0.000000;reported_maxjitter=0.000000;reported_avgjitter=0.000000;reported_stdevjitter=0.000000;
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSLOSS
Value: minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.000000;stdevrxlost=0.000000;reported_minlost=0.000000;reported_maxlost=0.000000;reported_avglost=0.000000;reported_stdevlost=0.000000;
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSLOSSBRIDGED
Value: minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.000000;stdevrxlost=0.000000;reported_minlost=0.000000;reported_maxlost=0.000000;reported_avglost=0.000000;reported_stdevlost=0.000000;
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSRTT
Value: minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrtt=0.000000;
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSRTTBRIDGED
Value: minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrtt=0.000000;
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOS
Value: ssrc=875571376;themssrc=1648457076;lp=0;rxjitter=0.000000;rxcount=599;txjitter=0.000755;txcount=252;rlp=0;rtt=0.002000
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSBRIDGED
Value: ssrc=875571376;themssrc=1648457076;lp=0;rxjitter=0.000000;rxcount=599;txjitter=0.000755;txcount=252;rlp=0;rtt=0.002000
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSJITTER
Value: minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0.000000;stdevrxjitter=0.000000;reported_minjitter=0.000000;reported_maxjitter=0.000000;reported_avgjitter=0.000000;reported_stdevjitter=0.000000;
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSJITTERBRIDGED
Value: minrxjitter=0.000000;maxrxjitter=0.000000;avgrxjitter=0.000000;stdevrxjitter=0.000000;reported_minjitter=0.000000;reported_maxjitter=0.000000;reported_avgjitter=0.000000;reported_stdevjitter=0.000000;
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSLOSS
Value: minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.000000;stdevrxlost=0.000000;reported_minlost=0.000000;reported_maxlost=0.000000;reported_avglost=0.000000;reported_stdevlost=0.000000;
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSLOSSBRIDGED
Value: minrxlost=0.000000;maxrxlost=0.000000;avgrxlost=0.000000;stdevrxlost=0.000000;reported_minlost=0.000000;reported_maxlost=0.000000;reported_avglost=0.000000;reported_stdevlost=0.000000;
Uniqueid: 1423642078.1

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: RTPAUDIOQOSRTT
Value: minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrtt=0.000000;
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000001
Variable: RTPAUDIOQOSRTTBRIDGED
Value: minrtt=0.000000;maxrtt=0.000000;avgrtt=0.000000;stdevrtt=0.000000;
Uniqueid: 1423642078.1

Event: Unlink
Privilege: call,all
Channel1: SIP/1111-00000000
Channel2: SIP/1122-00000001
Uniqueid1: 1423642071.0
Uniqueid2: 1423642078.1
CallerID1: 1111
CallerID2: 1122

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: ANSWEREDTIME
Value: 2
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDTIME
Value: 13
Uniqueid: 1423642071.0

Event: Hangup
Privilege: call,all
Channel: SIP/1122-00000001
Uniqueid: 1423642078.1
CallerIDNum: 1122
CallerIDName: 1122
ConnectedLineNum: 1111
ConnectedLineName: 1111
Cause: 16
Cause-txt: Normal Clearing

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALSTATUS
Value: ANSWER
Uniqueid: 1423642071.0

Event: Dial
Privilege: call,all
SubEvent: End
Channel: SIP/1111-00000000
UniqueID: 1423642071.0
DialStatus: ANSWER

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1111-00000000
CommandId: 1957166649
Command: EXEC "Dial" "SIP/1122, 60"
ResultCode: 200
Result: Unknown Result

Event: AGIExec
Privilege: agi,all
SubEvent: Start
Channel: SIP/1111-00000000
CommandId: 734805183
Command: SET VARIABLE "AJ_AGISTATUS" "SUCCESS"

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: AJ_AGISTATUS
Value: SUCCESS
Uniqueid: 1423642071.0

Event: AGIExec
Privilege: agi,all
SubEvent: End
Channel: SIP/1111-00000000
CommandId: 734805183
Command: SET VARIABLE "AJ_AGISTATUS" "SUCCESS"
ResultCode: 200
Result: Success

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: AGISTATUS
Value: SUCCESS
Uniqueid: 1423642071.0

Event: Newexten
Privilege: dialplan,all
Channel: SIP/1111-00000000
Context: vtiger_out
Extension: 1122
Priority: 2
Application: Dial
AppData: SIP/1122,,
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALSTATUS
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDPEERNUMBER
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDPEERNAME
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: ANSWEREDTIME
Value:
Uniqueid: 1423642071.0

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1111-00000000
Variable: DIALEDTIME
Value:
Uniqueid: 1423642071.0

Event: Newchannel
Privilege: call,all
Channel: SIP/1122-00000002
ChannelState: 0
ChannelStateDesc: Down
CallerIDNum: 1122
CallerIDName: 1122
AccountCode:
Exten:
Context: vtiger_out
Uniqueid: 1423642084.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000002
Variable: SIPCALLID
Value: 2f13f54435ef3f35611bc985424eb28e@192.168.0.67:5060
Uniqueid: 1423642084.2

Event: VarSet
Privilege: dialplan,all
Channel: SIP/1122-00000002
Variable: DIALEDPEERNUMBER
Value: 1122
Uniqueid: 1423642084.2

Event: Dial
Privilege: call,all
SubEvent: Begin
Channel: SIP/1111-00000000
Destination: SIP/1122-00000002
CallerIDNum: 1111
CallerIDName: 1111
ConnectedLineNum: 1122
ConnectedLineName: 1122
UniqueID: 1423642071.0
DestUniqueID: 1423642084.2
Dialstring: 1122

Event: Newstate
Privilege: call,all
Channel: SIP/1122-00000002
ChannelState: 5
ChannelStateDesc: Ringing
CallerIDNum: 1122
CallerIDName: 1122
ConnectedLineNum: 1111
ConnectedLineName: 1111
Uniqueid: 1423642084.2
Connected to Asterisk 1.8.32.2 currently running on localhost (pid = 1190)
Verbosity is at least 4
  == Using SIP RTP CoS mark 5
    -- Executing [1000@vtiger_out:1] AGI("SIP/1001-00000003", "agi://127.0.0.1/incoming.agi") in new stack
  == Manager 'vtg' logged on from 127.0.0.1
    -- AGI Script Executing Application: (Monitor) Options: (wav,/usr/local/VtigerAsteriskConnector/bin/rec/8854393f7ea1489585e1c360c54d1974,m)
    -- AGI Script Executing Application: (Dial) Options: (SIP/, 60)
[Feb 11 11:00:19] WARNING[2236]: app_dial.c:2253 dial_exec_full: Dial argument takes format (technology/[device:]number1)
  == Manager 'vtg' logged off from 127.0.0.1
    -- <SIP/1001-00000003>AGI Script agi://127.0.0.1/incoming.agi completed, returning 0
    -- Auto fallthrough, channel 'SIP/1001-00000003' status is 'INVALIDARGS'
Executing [1122@vtiger_out:1] AGI("SIP/1111-00000003", "agi://127.0.0.1/incoming.agi") in new stack
  == Manager 'admin' logged on from 127.0.0.1
    -- AGI Script Executing Application: (Monitor) Options: (wav,/usr/src/VtigerAsteriskConnector/bin/rec/6b71af0405344e07a497527f4c6a723d,m)
    -- AGI Script Executing Application: (Dial) Options: (SIP/1122, 60)
  == Using SIP RTP CoS mark 5
    -- Called SIP/1122
    -- SIP/1122-00000004 is ringing
    -- SIP/1122-00000004 answered SIP/1111-00000003
  == Manager 'admin' logged off from 127.0.0.1
    -- <SIP/1111-00000003>AGI Script agi://127.0.0.1/incoming.agi completed, returning 0
    -- Executing [1122@vtiger_out:2] Dial("SIP/1111-00000003", "SIP/1122,,") in new stack
  == Using SIP RTP CoS mark 5
    -- Called SIP/1122
    -- SIP/1122-00000005 is ringing

Приложения

~~socialite~~

2016/11/26

Установка AsterCRM Call Center

Настроим Asterisk, Freeswitch, Call Center

  • orphans/crm.txt
  • Последние изменения: 2015/03/24