Інтэграцыя 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
  • руководитель
  • 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://)
  • порт - порт
  • імя карыстальніка - Імя карыстальніка
  • таямніца - пароль
  • тайм-аўт падлучэння - таймаўт падключэння
  • час чакання_чытання - таймаўт чытання

прыклад файла настроек:

 <?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

Дадаць каментар