Integracja Asterisk i Bitrix24

Integracja Asterisk i Bitrix24
Istnieją różne opcje integracji IP-PBX Asterisk i CRM Bitrix24 w sieci, ale mimo to zdecydowaliśmy się napisać własną.

Pod względem funkcjonalności wszystko jest standardowe:

  • Klikając w link z numerem telefonu klienta w Bitrix24, Asterisk łączy numer wewnętrzny użytkownika, w imieniu którego dokonano kliknięcia, z numerem telefonu klienta. W Bitrix24 nagrywany jest zapis rozmowy, a po zakończeniu połączenia pobierane jest nagranie rozmowy.
  • Asterisk odbiera połączenie z zewnątrz - w interfejsie Bitrix24 pokazujemy kartę klienta pracownikowi, na numer, na który przyszło to połączenie.
    Jeżeli nie ma takiego klienta, otworzymy kartę do utworzenia nowego leada.
    Gdy tylko połączenie zostanie zakończone, odzwierciedlamy to na karcie i wyświetlamy nagranie rozmowy.

Poniżej opowiem Wam jak wszystko skonfigurować i podam link do githuba - tak, tak, weźcie i używajcie!

Ogólny opis

Naszą integrację nazwaliśmy CallMe. CallMe to niewielka aplikacja internetowa napisana w języku PHP.

Stosowane technologie i usługi

  • PHP 5.6
  • Biblioteka PHP AMI
  • Komponować
  • Nginx + php-fpm
  • nadzorca
  • AMI (interfejs menedżera gwiazdek)
  • Webhooki Bitrix (uproszczona implementacja API REST)

Wstępne ustawienie

Na serwerze z gwiazdką musisz zainstalować serwer WWW (u nas jest to nginx+php-fpm), nadzorcę i git.

Polecenie instalacji (CentOS):

yum install nginx php-fpm supervisor git

Przechodzimy do katalogu dostępnego dla serwera WWW, ściągamy aplikację z Gita i ustawiamy niezbędne uprawnienia do folderu:


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

Następnie skonfigurujmy nginx, w którym znajduje się nasza konfiguracja

/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;
		}
}

Analizę konfiguracji, kwestie bezpieczeństwa, uzyskanie certyfikatu, a nawet wybór serwera WWW pozostawię poza zakresem artykułu - wiele na ten temat napisano. Aplikacja nie ma żadnych ograniczeń, działa zarówno poprzez protokół http, jak i https.

Używamy https, szyfrujmy certyfikat.

Jeśli wszystko zrobiłeś poprawnie, to po kliknięciu linku powinieneś zobaczyć coś takiego

Integracja Asterisk i Bitrix24

Konfigurowanie Bitrix24

Stwórzmy dwa webhooki.

Przychodzący webhook.

Pod kontem administratora (o identyfikatorze 1) podążaj ścieżką: Aplikacje -> Webhooks -> Dodaj webhook -> Przychodzący webhook

Integracja Asterisk i Bitrix24

Wypełnij parametry przychodzącego webhooka jak na zrzutach ekranu:

Integracja Asterisk i Bitrix24

Integracja Asterisk i Bitrix24

I kliknij Zapisz.

Po zapisaniu Bitrix24 poda adres URL przychodzącego webhooka, na przykład:

Integracja Asterisk i Bitrix24

Zapisz swoją wersję adresu URL bez końcowego /profilu/ - będzie on używany w aplikacji do obsługi połączeń przychodzących.

Mam to https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Wychodzący webhook.

Aplikacje -> Webhook -> Dodaj webhook -> Wychodzący webhook

Szczegóły ponownie na zrzutach ekranu:

Integracja Asterisk i Bitrix24

Integracja Asterisk i Bitrix24

Zapisz i odbierz kod autoryzacyjny

Integracja Asterisk i Bitrix24

Mam to xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Musisz go także skopiować dla siebie; potrzebujesz go do wykonywania połączeń wychodzących.

Ważne!

Na serwerze Bitrix24 należy skonfigurować certyfikat SSL (możesz użyć letsencrypt), w przeciwnym razie api Bitrix nie będzie działać. Jeśli masz wersję w chmurze, nie martw się – ma ona już protokół SSL.

Ważne!

Pole „Adres procesora” musi zawierać adres dostępny z Internetu!

Na koniec zainstalujmy CallMeOut jako aplikację do wykonywania połączeń (aby po kliknięciu numeru w centrali PBX polecenie rozpoczęcia połączenia wyleciało).

W menu wybierz: Więcej -> Telefonia -> Więcej -> Ustawienia, ustaw w „Domyślny numer połączenia wychodzącego” Aplikacja: CallMeOut i kliknij „Zapisz”

Integracja Asterisk i Bitrix24

Ustawianie gwiazdki

Aby interakcja między Asterisk i Bitrix24 przebiegła pomyślnie, musimy dodać wywołanie użytkownika AMI do pliku 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

Następnie jest kilka sztuczek, które trzeba będzie wdrożyć za pomocą dialplanu (dla nas jest to plik Extensions.ael).

Podam cały plik, a następnie dam wyjaśnienie:

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});
}

};

Zacznijmy od początku: dyrektywa globals.

Zmienna REKORDY URL przechowuje adres URL plików nagrań rozmów, zgodnie z którymi Bitrix24 pobierze je na kartę kontaktu.

Następnie interesuje nas makro-makro nagranie.

Tutaj oprócz nagrywania rozmów ustawimy zmienną Pełna nazwa.

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

Przechowuje pełny adres URL konkretnego pliku (makro jest wywoływane wszędzie).

Przeanalizujmy połączenie wychodzące:

_. => {
	&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});
}

Powiedzmy, że dzwonimy pod numer 89991234567, przede wszystkim trafiamy tutaj:

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

te. Wywoływane jest makro nagrywania rozmowy i ustawiane są niezbędne zmienne.

Dalej

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

Rejestrujemy, kto zainicjował połączenie i rejestrujemy godzinę rozpoczęcia połączenia.

A po jego zakończeniu, w szczególnym kontekście 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});
}

wyłącz wpis do tabeli CDR dla tego numeru wewnętrznego (nie jest tam potrzebny), ustaw godzinę zakończenia połączenia, oblicz czas trwania połączenia, jeśli wynik połączenia nie jest znany - ustaw (zmienną CallMeDISPOSITION) i w ostatnim kroku wyślij wszystko do Bitrix za pośrednictwem systemowego curl.

I jeszcze trochę magii – połączenie przychodzące:

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();
        }

Tutaj interesuje nas tylko jedna linia.

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

Mówi centrali PBX, aby ją zainstalowała ID rozmówcy (nazwa) równy zmiennej Nazwa CallMeCallerIDName.

Z kolei sama zmienna CallMeCallerIDName ustawiana jest przez aplikację CallMe (jeśli Bitrix24 ma pełną nazwę numeru osoby dzwoniącej, ustaw ją jako ID rozmówcy (nazwa), nie – nic nie zrobimy).

Konfigurowanie aplikacji

Plik ustawień aplikacji - /var/www/pbx.vistep.ru/config.php

Opis parametrów aplikacji:

  • Zadzwoń do mnieDEBUG — jeśli 1, to wszystkie zdarzenia przetworzone przez aplikację zostaną zapisane do pliku logu, 0 — nic nie zapiszemy
  • tech -SIP/PJSIP/IAX/itp
  • token autoryzacji — Token autoryzacyjny Bitrix24, wychodzący kod autoryzacyjny webhooka
  • bitrixApiUrl — Adres URL przychodzącego webhooka, bez profilu/
  • rozszerzenia — lista numerów zewnętrznych
  • kontekst — kontekst inicjowania połączenia
  • limit czasu_słuchacza — szybkość przetwarzania zdarzeń od gwiazdki
  • gwiazdka — tablica z ustawieniami podłączenia do gwiazdki:
  • gospodarz — adres IP lub nazwa hosta serwera z gwiazdką
  • schemat — schemat połączeń (tcp://, tls://)
  • Port - Port
  • nazwa użytkownika - Nazwa użytkownika
  • tajemnica - hasło
  • limit_czasu połączenia - czas połączenia minął
  • limit czasu odczytu - przeczytaj limit czasu

przykładowy plik ustawień:

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

);

Konfiguracja nadzorcy

Supervisor służy do uruchamiania procesu obsługi zdarzeń z Asterisk CallMeIn.php, który monitoruje połączenia przychodzące i współdziała z Bitrix24 (pokaż kartę, ukryj kartę itp.).

Plik ustawień do utworzenia:

/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

Uruchom i uruchom ponownie aplikację:

supervisorctl start callme
supervisorctl restart callme

Przeglądanie stanu działania aplikacji:

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

wniosek

Okazało się to dość skomplikowane, ale jestem pewien, że doświadczony administrator będzie w stanie to wdrożyć i zadowolić swoich użytkowników.

Jak obiecano, link do githuba.

Pytania, sugestie – prosimy o pozostawienie ich w komentarzach. Także jeśli ciekawi Cię jak przebiegał rozwój tej integracji napisz, a w kolejnym artykule postaram się ujawnić wszystko bardziej szczegółowo.

Źródło: www.habr.com

Dodaj komentarz