Интеграция на Asterisk с Битрикс24

Интеграция на Asterisk с Битрикс24
В мрежата има различни варианти за интеграция на IP-АТС Asterisk и CRM Битрикс24, но все пак решихме да напишем собствена.

Функционалността е стандартна:

  • С един клик на връзката с телефонния номер на клиента в Битрикс24, Asterisk свързва вътрешния номер на потребителя, от името на когото е направен кликът, с телефонния номер на клиента. В Битрикс24 се записва запис за обаждането и след края на разговора се извлича записът на разговора.
  • Когато Asterisk получи обаждане от външно, в интерфейса на Битрикс24 показваме картата на клиента на служителя, на когото номерът на обаждането е насочен.
    Ако такъв клиент няма, отваряме картата за създаване на нов потенциален клиент.
    Веднага след като разговора приключи, отразяваме това в картата и извличаме записа на разговора.

Под заглавието ще разкажа как да настроите всичко при вас и ще дам линк към github — да-да, вземете и ползвайте!

Общо описание

Нашата интеграция се нарича CallMe. CallMe е малко уеб приложение, написано на PHP.

Използвани технологии и услуги

  • PHP 5.6
  • PHP AMI библиотека
  • Composer
  • Nginx + php-fpm
  • supervisor
  • AMI (Asterisk Manager Interface)
  • Webhooks на Bitrix (опростена реализация на REST API)

Предварителна настройка

На сървъра с Asterisk е необходимо да се инсталира уеб сървър (при нас е nginx+php-fpm), supervisor и git.

Команда за инсталиране (CentOS):

yum install nginx php-fpm supervisor git

Преход към директорията, достъпна за уеб сървъра, сваляме приложението от 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

сървър {
	име_на_сървър www.pbx.vistep.ru pbx.vistep.ru;
	слушай *:80;
	rewrite ^  https://pbx.vistep.ru$request_uri? permanent;
}

сървър {
#        слушай *:80;
#	име_на_сървър pbx.vistep.ru;


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

    слушай 443 ssl http2;
    име_на_сървър 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;
	индекс  индек.php;
        местоположение ~ \/. {
                забрани всичко; # забрана за скрити файлове
        }

        местоположение ~* \/(?:uploads|files)\/.*.php$ {
                забрани всичко; # забрана за качени скриптове
        }

        местоположение ~* ^.+\.(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; # кеширане на статичните файлове
        }

	местоположение ~ .php {
		root /var/www/callme;
		индекс  индек.php;
		fastcgi_pass unix:/run/php/php5.6-fpm.sock;
	#	fastcgi_pass 127.0.0.1:9000;
		fastcgi_index индек.php;
		fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
		включи /etc/nginx/fastcgi_params;
		}
}

Разглеждането на конфигурацията, въпросите за сигурността, получаването на сертификата и дори избора на уеб сървър оставям извън обсега на статията — за това е написано много. Приложението няма ограничения, то работи и по 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. Той също трябва да бъде копиран, нужен е за осъществяване на изходящите обаждания.

Важно!

На сървъра на Bitrix24 трябва да бъде настроен 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, ако сме го разпознали от Bitrix24
        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});
}

};

Да започнем от самото начало: директивата globals.

Променлива URLRECORDS съхранява URL към файловете с записи на разговорите, по който Bitrix24 ще ги изтегли в картата на контакта.

Сега ни интересува макросът recording.

Тук, освен записването на разговори, ще зададем променливата 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) и, последната стъпка, изпращаме всичко до Bitrix чрез системен curl.

И още малко магия — входящо обаждане:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // задаваме CallerID, ако сме го разпознали от Bitrix24
        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 — нищо не записваме
  • tech — SIP/PJSIP/IAX/и т.н.
  • authToken — токен за удостоверяване Bitrix24, код за удостоверяване на изходящ уебхук
  • bitrixApiUrl — URL на входящия уебхук, без profile/
  • extentions — списък на външни номера
  • контекст — контекст за инициране на обаждане
  • listener_timeout — скорост на обработка на събития от Asterisk
  • asterisk — масив с настройки за свързване с Asterisk:
  • host — ip или име на хоста на Asterisk сървъра
  • scheme — схема на свързване (tcp://, tls://)
  • port — порт
  • username — потребителско име
  • secret — парола
  • connect_timeout — таймаут за свързване
  • read_timeout — таймаут за четене

примерен файл с настройки:

 <?php
return array(

        'CallMeDEBUG' => 1, \/\/ дебъг съобщения в лог: 1 - пишем, 0 - не пишем
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', \/\/ токен за удостоверяване на Bitrix
        'bitrixApiUrl' => 'https:\/\/b24-xsynia.bitrix24.ru\/rest\/1\/7eh61lh8pahw0fwt\/', \/\/ URL към API на Bitrix (входящ уебхук)
        'extentions' => array('888999'), \/\/ списък на външни номера, разделени с запетаи
        'context' => 'dial_out', \/\/ изходящ контекст за инициране на обаждане
        'asterisk' => array( \/\/ настройки за свързване с Asterisk
                    '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, който следи входящите обаждания и взаимодействия с Bitrix24 (показва карта, скрива карта и т.н.).

Файлът с настройки, който трябва да бъде създаден:

/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

Заключение

Сложно е, но съм убеден, че опитен администратор ще успее да внедри всичко и да зарадва своите потребители.

Както обещах, линк към GitHub.

Въпроси и предложения — моля в коментарите. Също така, ако е интересно как протекла разработката на тази интеграция, напишете, а в следваща статия ще се постарая да разкрия всичко по-подробно.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster