Intégration d'Asterisk et Bitrix24

Intégration d'Asterisk et Bitrix24
Le réseau a différentes options pour intégrer IP-PBX Asterisk et CRM Bitrix24, mais nous avons néanmoins décidé d'écrire la nôtre.

Fonctionnellement, tout est standard :

  • En cliquant sur le lien avec le numéro de téléphone du client dans Bitrix24, Asterisk associe le numéro interne de l'utilisateur pour le compte duquel ce clic a été effectué au numéro de téléphone du client. Dans Bitrix24, un enregistrement de l'appel est enregistré et à la fin de l'appel, l'enregistrement de la conversation est extrait.
  • Un appel arrive à Asterisk de l'extérieur - dans l'interface Bitrix24, nous montrons la carte client à l'employé au numéro duquel cet appel est arrivé.
    S'il n'y a pas de client de ce type, ouvrez la carte pour créer un nouveau prospect.
    Dès que l'appel est terminé, nous le reflétons sur la carte et affichons l'enregistrement de la conversation.

Sous la coupe, je vais vous dire comment tout configurer pour vous-même et donner un lien vers github - oui, oui, prenez-le et utilisez-le !

Description générale

Nous avons appelé notre intégration CallMe. CallMe est une petite application web écrite en PHP.

Technologies et services utilisés

  • PHP 5.6
  • Bibliothèque AMI PHP
  • Compositeur
  • nginx + php fpm
  • superviseur
  • AMI (interface du gestionnaire d'astérisque)
  • Webhooks Bitrix (implémentation simplifiée de l'API REST)

préréglage

Sur le serveur avec Asterisk, vous devez installer un serveur web (nous avons nginx + php-fpm), un superviseur et git.

Commande d'installation (CentOS) :

yum install nginx php-fpm supervisor git

Nous transmettons le répertoire disponible au serveur Web, extrayons l'application du git et définissons les droits nécessaires sur le dossier :


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

Ensuite, configurez nginx, notre configuration se trouve dans

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

Je laisserai l'analyse de la configuration, les problèmes de sécurité, l'obtention d'un certificat et même le choix d'un serveur Web en dehors du cadre de l'article - beaucoup a été écrit à ce sujet. L'application n'a aucune restriction, elle fonctionne à la fois sur http et https.

Nous avons https, chiffrons le certificat.

Si vous avez tout fait correctement, alors en cliquant sur le lien, vous devriez voir quelque chose comme ça

Intégration d'Asterisk et Bitrix24

Configuration de Bitrix24

Créons deux webhooks.

Webhook entrant.

Sous le compte administrateur (avec l'id 1) suivez le chemin : Applications -> Webhooks -> Ajouter un webhook -> Incoming webhook

Intégration d'Asterisk et Bitrix24

Renseignez les paramètres du webhook entrant comme dans les captures d'écran :

Intégration d'Asterisk et Bitrix24

Intégration d'Asterisk et Bitrix24

Et cliquez sur enregistrer.

Après l'enregistrement, Bitrix24 fournira l'URL du webhook entrant, par exemple :

Intégration d'Asterisk et Bitrix24

Enregistrez votre version de l'URL sans la fin /profil/ - elle sera utilisée dans l'application pour traiter les appels entrants.

je l'ai https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Webhook sortant.

Applications -> Webhooks -> Ajouter un Webhook -> Webhook sortant

Les détails sont sur les captures d'écran :

Intégration d'Asterisk et Bitrix24

Intégration d'Asterisk et Bitrix24

Enregistrez et obtenez le code d'autorisation

Intégration d'Asterisk et Bitrix24

je l'ai xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Vous devez également le copier sur vous-même, il est nécessaire pour passer des appels sortants.

Important!

Un certificat ssl doit être configuré sur le serveur Bitrix24 (vous pouvez utiliser letsencrypt), sinon l'api BitrixXNUMX ne fonctionnera pas. Si vous avez une version cloud, ne vous inquiétez pas - SSL est déjà là.

Important!

Dans le champ « Adresse du sous-traitant », une adresse accessible depuis Internet doit être indiquée !

Et avec la touche finale, installons notre CallMeOut comme une application pour passer des appels (de sorte qu'en cliquant sur le numéro sur le PBX, une commande volera pour lancer l'appel).

Dans le menu, sélectionnez : Plus -> Téléphonie -> Plus -> Paramètres, renseignez le "Numéro pour les appels sortants par défaut" Application : CallMeOut et cliquez sur "Enregistrer"

Intégration d'Asterisk et Bitrix24

configuration astérisque

Pour une interaction réussie entre Asterisk et Bitrix24, nous devons ajouter l'utilisateur callme AMI à 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

Ensuite, il y a quelques astuces qui devront être implémentées en utilisant le dialplan (nous avons extensions.ael).

Je citerai tout le dossier, puis je donnerai des explications :

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

};

Commençons par le début : directive globals.

Variable ENREGISTREMENTS URL stocke l'URL des fichiers d'enregistrement de conversation, selon laquelle Bitrix24 les extraira dans la carte de contact.

Ensuite, nous nous intéressons à la macro macro l'enregistrement.

Ici, en plus d'enregistrer les conversations, nous allons définir la variable NomFcomplet.

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

Il stocke l'URL complète d'un fichier spécifique (la macro est appelée partout).

Analysons l'appel sortant :

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

Disons que nous appelons 89991234567, la première chose que nous obtenons ici :

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

ceux. la macro d'enregistrement d'appel est appelée et les variables nécessaires sont définies.

Suivant

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

nous enregistrons qui a lancé l'appel et enregistrons l'heure de début de l'appel.

Et à son achèvement, dans un contexte particulier 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});
}

désactivez l'entrée dans la table CDR pour cette extension (elle n'est pas nécessaire là-bas), définissez l'heure de fin de l'appel, calculez la durée, si le résultat de l'appel n'est pas connu - définissez (variable Appelez-moi DISPOSITION) et, dernière étape, tout envoyer à Bitrix via le système curl.

Et un peu plus de magie - un appel entrant :

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

Ici, nous ne nous intéressons qu'à une seule ligne.

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

Elle dit installer PBX ID de l'appelant (nom) variable CallMeCallerIDName.

La variable CallMeCallerIDName elle-même, à son tour, est définie par l'application CallMe (si Bitrix24 a un nom complet pour le numéro de l'appelant, nous le définirons comme ID de l'appelant (nom), non - nous ne ferons rien).

Configuration de l'application

Fichier de paramètres d'application - /var/www/pbx.vistep.ru/config.php

Description des paramètres d'application :

  • Appelez-moiDEBUG - si 1, alors tous les événements traités par l'application seront écrits dans le fichier journal, 0 - nous n'écrivons rien
  • technologie SIP/PJSIP/IAX/etc.
  • jeton d'authentification — Jeton d'autorisation Bitrix24, code d'autorisation de webhook sortant
  • bitrixApiUrl — URL du webhook entrant, sans profil/
  • des extensions — liste des numéros externes
  • contexte — contexte pour le départ d'appel
  • écouteur_timeout - vitesse de traitement des événements à partir d'un astérisque
  • astérisque - un tableau avec les paramètres de connexion à l'astérisque :
  • hôte - ip ou nom d'hôte du serveur asterisk
  • programme — schéma de connexion (tcp://, tls://)
  • port - port
  • Nom d'utilisateur - Nom d'utilisateur
  • secret - mot de passe
  • connexion_timeout - délai de connection dépassé
  • read_timeout - délai de lecture

exemple de fichier de paramètres :

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

);

Configuration du superviseur

Le superviseur est utilisé pour lancer le processus de gestionnaire d'événements Asterisk CallMeIn.php, qui surveille les appels entrants et interagit avec Bitrix24 (afficher la carte, masquer la carte, etc.).

Fichier de paramètres à créer :

/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

Démarrage et redémarrage de l'application :

supervisorctl start callme
supervisorctl restart callme

voir le statut de l'application :

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

Conclusion

Cela s'est avéré assez difficile, mais je suis sûr qu'un administrateur expérimenté pourra mettre en œuvre et plaire à ses utilisateurs.

Comme promis, lien vers github.

Questions, suggestions - s'il vous plaît dans les commentaires. De plus, si vous êtes intéressé par le déroulement du développement de cette intégration, écrivez, et dans le prochain article, j'essaierai de tout révéler plus en détail.

Source: habr.com

Ajouter un commentaire