Integrazione di Asterisk e Bitrix24

Integrazione di Asterisk e Bitrix24
Esistono diverse opzioni per integrare l'IP-PBX Asterisk e il CRM Bitrix24 nella rete, ma abbiamo comunque deciso di scriverne una nostra.

In termini di funzionalità, tutto è standard:

  • Facendo clic su un collegamento con il numero di telefono di un cliente in Bitrix24, Asterisk collega il numero interno dell'utente per conto del quale è stato effettuato il clic con il numero di telefono del cliente. In Bitrix24 viene registrata una registrazione della chiamata e alla fine della chiamata viene richiamata una registrazione della conversazione.
  • Asterisk riceve una chiamata dall'esterno: nell'interfaccia Bitrix24 mostriamo la carta cliente al dipendente al cui numero è arrivata questa chiamata.
    Se non esiste tale cliente, apriremo la scheda per creare un nuovo lead.
    Non appena la chiamata è completata, lo riflettiamo sulla carta e visualizziamo una registrazione della conversazione.

Sotto il taglio ti dirò come impostare tutto da solo e ti darò un link a github - sì, sì, prendilo e usalo!

descrizione generale

Abbiamo chiamato la nostra integrazione CallMe. CallMe è una piccola applicazione web scritta in PHP.

Tecnologie e servizi utilizzati

  • PHP 5.6
  • Libreria AMI PHP
  • Compositore
  • Nginx+php-fpm
  • supervisore
  • AMI (Interfaccia Gestione Asterisco)
  • Webhook Bitrix (implementazione API REST semplificata)

preimpostazione

Su un server con Asterisk è necessario installare un web server (per noi è nginx+php-fpm), supervisore e git.

Comando di installazione (CentOS):

yum install nginx php-fpm supervisor git

Andiamo nella directory accessibile al server web, estraiamo l'applicazione da Git e impostiamo i diritti necessari sulla cartella:


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

Successivamente, configuriamo nginx, in cui si trova la nostra configurazione

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

Lascerò l'analisi della configurazione, i problemi di sicurezza, l'ottenimento di un certificato e persino la scelta di un server Web al di fuori dello scopo dell'articolo: è stato scritto molto al riguardo. L'applicazione non ha restrizioni, funziona sia su http che su https.

Usiamo https, crittografiamo il certificato.

Se hai fatto tutto correttamente, facendo clic sul collegamento dovresti vedere qualcosa di simile

Integrazione di Asterisk e Bitrix24

Configurazione di Bitrix24

Creiamo due webhook.

Webhook in entrata.

Sotto l'account amministratore (con ID 1), segui il percorso: Applicazioni -> Webhook -> Aggiungi webhook -> Webhook in entrata

Integrazione di Asterisk e Bitrix24

Compila i parametri del webhook in entrata come negli screenshot:

Integrazione di Asterisk e Bitrix24

Integrazione di Asterisk e Bitrix24

E fai clic su Salva.

Dopo il salvataggio, Bitrix24 fornirà l'URL del webhook in entrata, ad esempio:

Integrazione di Asterisk e Bitrix24

Salva la tua versione dell'URL senza il /profilo/ finale: verrà utilizzato nell'applicazione per gestire le chiamate in arrivo.

ho questo https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Webhook in uscita.

Applicazioni -> Webhook -> Aggiungi webhook -> Webhook in uscita

I dettagli sono di nuovo negli screenshot:

Integrazione di Asterisk e Bitrix24

Integrazione di Asterisk e Bitrix24

Salva e ricevi il codice di autorizzazione

Integrazione di Asterisk e Bitrix24

ho questo xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Devi copiarlo anche per te stesso; ti serve per effettuare chiamate in uscita.

Importante!

Un certificato SSL deve essere configurato sul server Bitrix24 (puoi usare letsencrypt), altrimenti l'API Bitrix non funzionerà. Se hai una versione cloud, non preoccuparti: ha già SSL.

Importante!

Il campo “Indirizzo processore” deve contenere un indirizzo accessibile da Internet!

E come tocco finale, installiamo il nostro CallMeOut come un'applicazione per effettuare chiamate (in modo che quando clicchi sul numero del centralino, il comando per avviare la chiamata volerà via).

Nel menu selezionare: Altro -> Telefonia -> Altro -> Impostazioni, impostato in “Numero chiamate in uscita predefinito” Applicazione: CallMeOut e fare clic su “Salva”

Integrazione di Asterisk e Bitrix24

Impostazione dell'asterisco

Per un'interazione di successo tra Asterisk e Bitrix24, dobbiamo aggiungere l'utente AMI callme a 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

Successivamente, ci sono diversi trucchi che dovranno essere implementati tramite dialplan (per noi questo è extensions.ael).

Fornirò l'intero file e poi darò una spiegazione:

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

};

Partiamo dall'inizio: la direttiva globals.

Переменная URLRECORDS memorizza l'URL dei file di registrazione della conversazione, in base ai quali Bitrix24 li inserirà nella scheda del contatto.

Successivamente siamo interessati alla macro macro registrazione.

Qui, oltre a registrare le conversazioni, imposteremo la variabile NomeF completo.

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

Memorizza l'URL completo in un file specifico (la macro viene chiamata ovunque).

Analizziamo la chiamata in uscita:

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

Diciamo che chiamiamo il 89991234567, prima di tutto arriviamo qui:

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

quelli. Viene richiamata la macro di registrazione della conversazione e vengono impostate le variabili necessarie.

Avanti

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

Registriamo chi ha avviato la chiamata e registriamo l'ora di inizio della chiamata.

E al suo completamento, in un contesto speciale 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});
}

disabilitare l'ingresso nella tabella CDR per questo interno (non è necessario lì), impostare l'ora di fine della chiamata, calcolare la durata, se il risultato della chiamata non è noto - impostare (variabile CallMeDISPOSIZIONE) e, ultimo passaggio, invia tutto a Bitrix tramite il sistema curl.

E un po' più di magia: una chiamata in arrivo:

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

Qui siamo interessati solo ad una riga.

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

Dice al PBX di eseguire l'installazione ID chiamante(nome) uguale a variabile CallMeCallerIDNome.

La stessa variabile CallMeCallerIDName, a sua volta, è impostata dall'applicazione CallMe (se Bitrix24 ha un nome completo per il numero del chiamante, impostalo come ID chiamante(nome), no, non faremo nulla).

Configurazione dell'applicazione

File delle impostazioni dell'applicazione - /var/www/pbx.vistep.ru/config.php

Descrizione dei parametri dell'applicazione:

  • CallMeDEBUG — se 1, tutti gli eventi elaborati dall'applicazione verranno scritti nel file di registro, 0 — non scriviamo nulla
  • Tech -SIP/PJSIP/IAX/ecc
  • authToken — Token di autorizzazione Bitrix24, codice di autorizzazione del webhook in uscita
  • bitrixApiUrl — URL del webhook in entrata, senza profilo/
  • estensioni — elenco dei numeri esterni
  • contesto — contesto per avviare una chiamata
  • listener_timeout — velocità di elaborazione degli eventi dall'asterisco
  • asterisco — un array con le impostazioni per la connessione all'asterisco:
  • host — IP o nome host del server con asterisco
  • schema — schema di collegamento (tcp://, tls://)
  • porto - porto
  • nome utente - Nome utente
  • segreto - parola d'ordine
  • timeout_connessione - connesione finita
  • read_timeout - leggere il timeout

file di impostazioni di esempio:

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

);

Configurazione del supervisore

Supervisor viene utilizzato per avviare il processo di gestione degli eventi da Asterisk CallMeIn.php, che monitora le chiamate in entrata e interagisce con Bitrix24 (mostra carta, nascondi carta, ecc.).

File di impostazioni da creare:

/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

Avvia e riavvia l'applicazione:

supervisorctl start callme
supervisorctl restart callme

Visualizzazione dello stato operativo dell'applicazione:

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

conclusione

Si è rivelato piuttosto complicato, ma sono sicuro che un amministratore esperto sarà in grado di implementarlo e soddisfare i suoi utenti.

Come promesso, collegamento a github.

Domande, suggerimenti: lasciateli nei commenti. Inoltre, se sei interessato a come è andato lo sviluppo di questa integrazione, scrivi, e nel prossimo articolo cercherò di svelarti tutto più nel dettaglio.

Fonte: habr.com

Aggiungi un commento