Integrazione Asterisk e Bitrix24

Integrazione Asterisk e Bitrix24
Esistono diverse opzioni per l'integrazione della centrale telefonica IP Asterisk e del CRM Bitrix24, ma abbiamo deciso di scrivere la nostra.

Funzionalità standard:

  • Cliccando sul link con il numero di telefono del cliente in Bitrix24, Asterisk collega il numero interno dell'utente che ha effettuato il clic al numero di telefono del cliente. In Bitrix24 viene registrata la chiamata e, al termine della conversazione, viene estratta la registrazione della chiamata.
  • Asterisk riceve una chiamata dall'esterno: nell'interfaccia di Bitrix24 mostriamo il profilo cliente all'impiegato al quale è giunta questa chiamata.
    Se il cliente non esiste, apriremo il profilo per creare un nuovo lead.
    Non appena la chiamata è terminata, riflettiamo questo nel profilo e estraiamo la registrazione della conversazione.

Nel prossimo paragrafo ti racconterò come impostare tutto e fornirò il link su github: sì, sì, prendilo e usalo!

Descrizione generale

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

Tecnologie e servizi utilizzati

  • PHP 5.6
  • Libreria PHP AMI
  • Composer
  • Nginx + php-fpm
  • supervisor
  • AMI (Asterisk Manager Interface)
  • Webhook di Bitrix (implementazione semplificata di REST API)

Configurazione preliminare

Sul server con Asterisk, è necessario installare il server web (nel nostro caso nginx+php-fpm), supervisor e git.

Comando per installazione (CentOS):

yum install nginx php-fpm supervisor git

Andiamo nella directory accessibile al server web, scarichiamo l'applicazione da git e impostiamo i permessi necessari sulla cartella:


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

Successivamente configureremo nginx, il nostro file di configurazione si trova in

/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; # divieto per file nascosti
        }

        location ~* \/(?:uploads|files)\/.*.php$ {
                deny all; # divieto per script caricati
        }

        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; # caching della statica
        }

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

Analizzerò la configurazione, le questioni di sicurezza, l'ottenimento del certificato e anche la scelta del server web, lasciando da parte l'articolo - ce n'è già molto scritto. L'applicazione non ha limitazioni, funziona sia in http che in https.

Abbiamo https, certificato let’s encrypt.

Se hai fatto tutto correttamente, passando per il link dovresti vedere qualcosa di simile

Integrazione Asterisk e Bitrix24

Configurazione di Bitrix24

Creeremo due webhook.

Webhook in entrata.

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

Integrazione Asterisk e Bitrix24

Compila i parametri del webhook in entrata come negli screenshot:

Integrazione Asterisk e Bitrix24

Integrazione Asterisk e Bitrix24

E fai clic su salva.

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

Integrazione Asterisk e Bitrix24

Salva il tuo URL senza la slash finale /profile/ — sarà utilizzato nell'applicazione per gestire le chiamate in entrata.

Per me è questo https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Webhook in uscita.

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

Ancora dettagli negli screenshot:

Integrazione Asterisk e Bitrix24

Integrazione Asterisk e Bitrix24

Salviamo e riceviamo il codice di autorizzazione

Integrazione Asterisk e Bitrix24

Per me è questo xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Anche questo deve essere copiato, è necessario per effettuare chiamate in uscita.

Importante!

Sul server Bitrix24 deve essere configurato un certificato ssl (puoi utilizzare letsencrypt), altrimenti l'api di Bitrix non funzionerà. Se hai la versione cloud, non preoccuparti — è già presente ssl.

Importante!

Nel campo "Indirizzo del gestore" deve essere indicato un indirizzo accessibile da Internet!

E come ultimo tocco installeremo il nostro CallMeOut come applicazione per effettuare chiamate (in modo che cliccando sul numero venga inviata una comando per l'origine della chiamata all'ATS).

Nel menu seleziona: Altro -> Telefonia -> Altro -> Impostazioni, impostiamo in "Numero per chiamata in uscita predefinito" Applicazione: CallMeOut e clicchiamo su "Salva"

Integrazione Asterisk e Bitrix24

Configurazione di asterisk

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

Inoltre ci sono alcuni accorgimenti che sarà necessario implementare tramite dialplan (nel nostro caso è extensions.ael).

Riporto l'intero file, e poi fornirò delle spiegazioni:

globals {
    WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/Cartella temporanea con WAV
    MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/Dove caricare i file mp3
    URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
    RECORDING=1; \/\/ Registrazione, 1 - attivata.
};

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()); \/\/ impostiamo il CallerID se lo conosciamo da 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 già impostato ===));  
}

}


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

};

Iniziamo dall'inizio: direttiva globals.

Variabile URLRECORDS contiene l'URL ai file delle registrazioni delle conversazioni, tramite il quale Bitrix24 li recupererà nella scheda contatto.

Successivamente, ci interessa il macro recording.

Qui, oltre alla registrazione delle conversazioni, imposteremo la variabile FullFname.

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

Essa contiene l'URL completo per un file specifico (il macro viene richiamato 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});
}

Supponiamo di chiamare il numero 89991234567, innanzitutto arriviamo qui:

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

cioè viene chiamato il macro per la registrazione della chiamata e vengono impostate le variabili necessarie.

Successivamente

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

registriamo chi ha iniziato la chiamata e registriamo l'orario d'inizio della chiamata.

E alla sua conclusione, 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});
}

disattiviamo la registrazione nella tabella CDR per questo interno (non è necessaria lì), impostiamo l'orario di termine della chiamata, calcoliamo la durata, se il risultato della chiamata non è noto — impostiamo (variabile CallMeDISPOSITION) e, come ultimo passo, inviamo tutto a Bitrix tramite curl di sistema.

E un po' di magia — chiamata in arrivo:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // impostiamo CallerID se lo sappiamo da Bitrix24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // iniziamo a contare il tempo della chiamata
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

Qui ci interessa solo una riga.

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

Essa dice all'ATS di impostare CallerID(name) uguale alla variabile CallMeCallerIDName.

La variabile CallMeCallerIDName, a sua volta, è impostata dall'applicazione CallMe (se in Bitrix24 c'è un nome completo per il numero chiamante — lo imposteremo come CallerID(name), altrimenti non faremo nulla).

Configurazione dell'applicazione

File di configurazione dell'applicazione — /var/www/pbx.vistep.ru/config.php

Descrizione dei parametri dell'applicazione:

  • CallMeDEBUG — se 1, allora verranno registrati nel file di log tutti gli eventi trattati dall'applicazione, 0 — non scriviamo nulla
  • tech — SIP/PJSIP/IAX/etc
  • authToken — token di autorizzazione Bitrix24, codice di autorizzazione del webhook in uscita
  • bitrixApiUrl — URL del webhook in entrata, senza profile/
  • extentions — elenco dei numeri esterni
  • context — contesto per l'origine della chiamata
  • listener_timeout — velocità di elaborazione degli eventi da Asterisk
  • asterisk — array con le impostazioni di connessione ad Asterisk:
  • host — ip o hostname del server Asterisk
  • scheme — schema di connessione (tcp://, tls://)
  • port — porta
  • username — nome utente
  • secret — password
  • connect_timeout — timeout di connessione
  • read_timeout — timeout di lettura

esempio di file di configurazione:

 1, // messaggi di debug nel log: 1 - scrivi, 0 - non scrivere
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //token di autorizzazione di Bitrix
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //url per l'api di Bitrix (webhook in entrata)
        'extentions' => array('888999'), // elenco dei numeri esterni, separati da virgola
        'context' => 'dial_out', // contesto in uscita per l'origine della chiamata
        'asterisk' => array( // impostazioni per la connessione ad 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, // velocità di elaborazione degli eventi da Asterisk

);

Configurazione di supervisor

Supervisor serve per avviare il processo di elaborazione degli eventi da Asterisk CallMeIn.php, che monitora le chiamate in arrivo e interagisce con Bitrix24 (visualizza la scheda, nasconde la scheda, ecc.).

File di configurazione 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

Avvio e riavvio dell'applicazione:

supervisorctl start callme
supervisorctl restart callme

visualizzazione dello stato di funzionamento dell'applicazione:

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

Conclusione

È diventato piuttosto complicato, ma sono sicuro che un amministratore esperto riuscirà a implementarlo e a rendere felici i propri utenti.

Come promesso, link su GitHub.

Domande, suggerimenti — vi prego di scriverli nei commenti. Se siete anche interessati a come è stata sviluppata questa integrazione, scrivetemi, e nel prossimo articolo cercherò di approfondire tutto in modo più dettagliato.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster