Інтеграція Asterisk та Бітрікс24

Інтеграція Asterisk та Бітрікс24
У мережі є різні варіанти інтеграції IP-АТС Asterisk і CRM Бітрікс24, але ми все-таки вирішили написати свою.

За функціоналом все стандартно:

  • Натиснувши на посилання з номером телефону клієнта в Бітрікс24, Asterisk з'єднує внутрішній номер користувача, від імені якого цей клік здійснено, з номером телефону клієнта. У Бітрікс24 фіксується запис про дзвінок і після закінчення виклику підтягується запис розмови.
  • На Asterisk надходить дзвінок ззовні - в інтерфейсі Бітрікс24 показуємо картку клієнта тому співробітнику, на номер якого цей дзвінок прилетів.
    Якщо такого клієнта немає, відкриємо картку створення нового ліда.
    Як тільки дзвінок завершено, відображаємо це у картці та підтягуємо запис розмови.

Під катом розповім як все налаштувати у себе і дам лінк на github - так-так, забирайте та користуйтеся!

Загальний опис

Свою інтеграцію ми назвали CallMe. CallMe - це невеликий веб-додаток, написаний на PHP.

Використовувані технології та сервіси

  • PHP 5.6
  • PHP AMI-бібліотека
  • Композитор
  • Nginx + php-fpm
  • supervisor
  • AMI (Asterisk Manager Interface)
  • Вебхукі Bitrix (спрощена реалізація REST API)

Попереднє налаштування

На сервері з Asterisk необхідно встановити web-сервер (у нас це nginx+php-fpm), supervisor та git.

Команда для встановлення (CentOS):

yum install nginx php-fpm supervisor git

Переходимо директорію, доступну веб-серверу, тягнемо з гіта додаток та виставляємо потрібні права на папку:


cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/

Далі налаштуємо nginx, наш конфіг розмістився в

/etc/nginx/conf.d/pbx.vistep.ru.conf

server {
	server_name www.pbx.vistep.ru pbx.vistep.ru;
	listen *:80;
	rewrite ^  https://pbx.vistep.ru$request_uri? permanent;
}

server {
#        listen *:80;
#	server_name pbx.vistep.ru;


	access_log /var/log/nginx/pbx.vistep.ru.access.log main;
        error_log /var/log/nginx/pbx.vistep.ru.error.log;

    listen 443 ssl http2;
    server_name pbx.vistep.ru;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.ru/privkey.pem;
    ssl_dhparam /etc/nginx/certs/dhparam.pem;
    ssl_session_timeout 24h;
    ssl_session_cache shared:SSL:2m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2;
    ssl_prefer_server_ciphers on;
    add_header Strict-Transport-Security "max-age=31536000;";
    add_header Content-Security-Policy-Report-Only "default-src https:; script-src https: 'unsafe-eval' 'unsafe-inline'; style-src https: 'unsafe-inline'; img-src https: data:; font-src https: data:; report-uri /csp-report";
	
	root /var/www/callme;
	index  index.php;
        location ~ /. {
                deny all; # запрет для скрытых файлов
        }

        location ~* /(?:uploads|files)/.*.php$ {
                deny all; # запрет для загруженных скриптов
        }

        location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                access_log off;
                log_not_found off;
                expires max; # кеширование статики
        }

	location ~ .php {
		root /var/www/callme;
		index  index.php;
		fastcgi_pass unix:/run/php/php5.6-fpm.sock;
	#	fastcgi_pass 127.0.0.1:9000;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
		include /etc/nginx/fastcgi_params;
		}
}

Розбір конфігу, питання безпеки, отримання сертифікату і навіть вибір web-сервера я залишу за рамками статті – про це написано багато. Програма не має обмежень, вона працює і по http і по https.

У нас є https, сертифікат let's encrypt.

Якщо ви все зробили правильно, то, перейшовши за посиланням, повинні побачити щось подібне

Інтеграція Asterisk та Бітрікс24

Налаштування Бітрікс24

Створимо два вебхуки.

Вхідний вебхук.

Під обліковим записом адміністратора (з id 1) йдемо шляхом: Програми -> Вебхукі -> Додати вебхук -> Вхідний вебхук

Інтеграція Asterisk та Бітрікс24

Заповнюємо параметри вхідного вебхука як на скрінах:

Інтеграція Asterisk та Бітрікс24

Інтеграція Asterisk та Бітрікс24

І тиснемо зберегти.

Після збереження Бітрікс24 надасть URL вхідного вебхука, наприклад:

Інтеграція Asterisk та Бітрікс24

Збережіть собі ваш варіант URL без завершального /profile/ - він буде використовуватися в програмі для роботи з вхідними дзвінками.

У мене це https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Вихідний вебхук.

Програми -> Вебхукі -> Додати вебхук -> Вихідний вебхук

Подробиці знову на скрінах:

Інтеграція Asterisk та Бітрікс24

Інтеграція Asterisk та Бітрікс24

Зберігаємо та отримуємо код авторизації

Інтеграція Asterisk та Бітрікс24

У мене це xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Його теж потрібно скопіювати собі, він потрібний для здійснення вихідних дзвінків.

Важливо!

На сервері Бітрікс24 має бути налаштований ssl-сертифікат (можна використовувати letsencrypt), інакше api бітриксу не працюватиме. Якщо у вас хмарна версія, можете не хвилюватись – там вже є ssl.

Важливо!

У полі «Адреса обробника» має бути вказана доступна з мережі Інтернет адреса!

І останнім штрихом встановимо наш CallMeOut як додаток для здійснення дзвінків (щоб по кліку на номер на АТС відлітала команда для оригінації дзвінка).

У меню вибираємо: Ще -> Телефонія -> Ще -> Налаштування, ставимо в "Номер для вихідного дзвінка за замовчуванням" Додаток: CallMeOut і тиснемо "Зберегти"

Інтеграція Asterisk та Бітрікс24

Налаштування asterisk

Для успішної взаємодії Asterisk та Bitrix24 нам потрібно додати AMI-користувача callme у manager.conf:

[callme]
secret = JD3clEB8_f23r-3ry84gJ
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
permit= 10.100.111.249/255.255.255.255
permit = 192.168.254.0/255.255.255.0
read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
write = system,call,agent,log,verbose,user,config,command,reporting,originate

Далі є кілька хитрощів, які потрібно впровадити за допомогою dialplan (у нас це extensions.ael).

Наводжу весь файл, а потім дам пояснення:

globals {
    WAV=/var/www/pbx.vistep.ru/callme/records/wav; //Временный каталог с WAV
    MP3=/var/www/pbx.vistep.ru/callme/records/mp3; //Куда выгружать mp3 файлы
    URLRECORDS=https://pbx.vistep.ru/callme/records/mp3;
    RECORDING=1; // Запись, 1 - включена.
};

macro recording(calling,called) {
        if ("${RECORDING}" = "1"){
              Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called});
	      Set(datedir=${STRFTIME(${EPOCH},,%Y/%m/%d)});
	      System(mkdir -p ${MP3}/${datedir});
	      System(mkdir -p ${WAV}/${datedir});
              Set(monopt=nice -n 19 /usr/bin/lame -b 32  --silent "${WAV}/${datedir}/${fname}.wav"  "${MP3}/${datedir}/${fname}.mp3" && rm -f "${WAV}/${fname}.wav" && chmod o+r "${MP3}/${datedir}/${fname}.mp3");
	      Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3);
              Set(CDR(filename)=${fname}.mp3);
	      Set(CDR(recordingfile)=${fname}.wav);
              Set(CDR(realdst)=${called});
              MixMonitor(${WAV}/${datedir}/${fname}.wav,b,${monopt});

       };
};


context incoming {
888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // выставляем CallerID если узнали его у Битрикс24
        Set(CallStart=${STRFTIME(epoch,,%s)});  
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

h => {
    Set(CDR_PROP(disable)=true); 
    Set(CallStop=${STRFTIME(epoch,,%s)}); 
    Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)}); 
    ExecIF(${ISNULL(${CallMeDISPOSITION})}?Set(CallMeDISPOSITION=${CDR(disposition)}):NoOP(=== CallMeDISPOSITION already was set ===));  
}

}


context default {

_X. => {
        Hangup();
        }
};


context dial_out {

_[1237]XX => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
        Dial(SIP/${EXTEN},,tTr);
        Hangup();
        }

_11XXX => {
	&recording(${CALLERID(number)},${EXTEN});
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Set(__CallIntNum=${CALLERID(num)});
        Dial(SIP/${EXTEN:2}@toOurAster,,t);
        Hangup();
        }

_. => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Dial(SIP/${EXTEN}@toOurAster,,t);
	Hangup();
        }

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

};

Почнемо із самого початку: директива глобали.

Мінлива URLRECORDS зберігає в собі URL-адресу до файлів записів розмов, за яким Bitrix24 їх підтягуватиме в картку контакту.

Далі нам цікавий макрос макрос запис.

Тут, окрім запису розмов, ми встановимо змінну FullFname.

Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3);

Вона зберігає повну URL-адресу до конкретного файлу (макрос викликається скрізь).

Розберемо вихідний дзвінок:

_. => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Dial(SIP/${EXTEN}@toOurAster,,t);
	Hangup();
        }

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

Допустимо ми телефонуємо на 89991234567, перш за все потрапляємо сюди:

&recording(${CALLERID(number)},${EXTEN});

тобто. викликається макрос запису розмови та проставляються необхідні змінні.

Далі

        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});

записуємо хто ініціював дзвінок та фіксуємо час старту дзвінка.

І після його завершення, у спеціальному контексті h

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

відключаємо запис до таблиці CDR для цього екстеншена (не потрібно воно там), виставляємо час завершення дзвінка, обчислюємо тривалість, якщо результат дзвінка не відомий - ставимо (змінна CallMeDISPOSITION) і, останнім кроком, шолом всі бітриксу через системний curl.

І ще трохи магії - вхідний дзвінок:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // выставляем CallerID если узнали его у Битрикс24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // начинаем отсчет времени звонка
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

Тут нас цікавить лише один рядок.

ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());

Вона каже АТС встановити CallerID(name) рівним змінною CallMeCallerIDName.

Сама змінна CallMeCallerIDName, у свою чергу, встановлюється додатком CallMe (якщо в Bitrix24 є ПІБ для номера, що зателефонував — встановимо як CallerID(name)ні – нічого не будемо робити).

Налаштування програми

Файл налаштувань програми - /var/www/pbx.vistep.ru/config.php

Опис параметрів програми:

  • CallMeDEBUG - Якщо 1, то в лог файл будуть писатися всі події, що обробляються додатком, 0 - нічого не пишемо
  • технології - SIP/PJSIP/IAX/etc
  • authToken - токен авторизації бітрікс24, код авторизації вихідного вебхука
  • bitrixApiUrl — URL вхідного вебхука, без profile/
  • extentions - Список зовнішніх номерів
  • контекст контекст для оригінації дзвінка
  • listener_timeout - швидкість обробки подій від asterisk
  • зірочка - масив з налаштуваннями підключення до астериску:
  • господар - IP або hostname сервера астериск
  • схема - Схема підключення (tcp://, tls://)
  • порт - порт
  • ім'я користувача - Ім'я користувача
  • secret - пароль
  • час очікування підключення - Таймають підключення
  • read_timeout - Таймають читання

приклад файлу налаштувань:

 <?php
return array(

        'CallMeDEBUG' => 1, // дебаг сообщения в логе: 1 - пишем, 0 - не пишем
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //токен авторизации битрикса
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //url к api битрикса (входящий вебхук)
        'extentions' => array('888999'), // список внешних номеров, через запятую
        'context' => 'dial_out', //исходящий контекст для оригинации звонка
        'asterisk' => array( // настройки для подключения к астериску
                    'host' => '10.100.111.249',
                    'scheme' => 'tcp://',
                    'port' => 5038,
                    'username' => 'callme',
                    'secret' => 'JD3clEB8_f23r-3ry84gJ',
                    'connect_timeout' => 10000,
                    'read_timeout' => 10000
                ),
        'listener_timeout' => 300, //скорость обработки событий от asterisk

);

Налаштування supervisor

Supervisor служить для запуску процесу-обробника подій від Asterisk CallMeIn.php, який відстежує вхідні дзвінки та взаємодіє з Бітрікс24 (показати картку, приховати картку тощо).

Файл налаштувань, який потрібно створити:

/etc/supervisord.d/callme.conf

[program:callme]
command=/usr/bin/php CallMeIn.php
directory=/var/www/pbx.vistep.ru
autostart=true
autorestart=true
startretries=5
stderr_logfile=/var/www/pbx.vistep.ru/logs/daemon.log
stdout_logfile=/var/www/pbx.vistep.ru/logs/daemon.log

Запуск та рестарт програми:

supervisorctl start callme
supervisorctl restart callme

перегляд статусу роботи програми:

supervisorctl status callme
callme                           RUNNING   pid 11729, uptime 17 days, 16:58:07

Висновок

Вийшло досить складно, але впевнений - досвідчений адміністратор зуміє впровадити у себе та порадувати своїх користувачів.

Як обіцяв, лінк на гітхаб.

Запитання, побажання — прошу у коментарі. Також якщо цікаво, як йшла розробка цієї інтеграції, напишіть, а в черговій статті я постараюся розкрити дедалі детальніше.

Джерело: habr.com

Додати коментар або відгук