Intégration d'Asterisk et Bitrix24.

Intégration d'Asterisk et Bitrix24.
Il existe différentes options pour intégrer IP-ATS Asterisk et CRM Bitrix24, mais nous avons finalement décidé d'écrire la nÎtre.

Les fonctionnalités sont standard :

  • En cliquant sur le lien avec le numĂ©ro de tĂ©lĂ©phone du client dans Bitrix24, Asterisk connecte le numĂ©ro interne de l'utilisateur au nom duquel ce clic a Ă©tĂ© effectuĂ©, avec le numĂ©ro de tĂ©lĂ©phone du client. Une note de l'appel est enregistrĂ©e dans Bitrix24 et, Ă  la fin de l'appel, l'enregistrement de la conversation est rĂ©cupĂ©rĂ©.
  • Un appel arrive sur Asterisk - dans l'interface de Bitrix24, nous montrons la fiche du client Ă  l'employĂ© Ă  qui cet appel est destinĂ©.
    S'il n'y a pas de client, nous ouvrirons la fiche pour créer un nouveau lead.
    DÚs que l'appel est terminé, nous le reflétons dans la fiche et récupérons l'enregistrement de la conversation.

Je vous expliquerai comment tout configurer chez vous et je fournirai un lien vers github - oui, oui, prenez-le et utilisez-le !

Description générale

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

Technologies et services utilisés

  • PHP 5.6
  • BibliothĂšque PHP AMI
  • Composer
  • Nginx + php-fpm
  • supervisor
  • AMI (Asterisk Manager Interface)
  • Webhooks Bitrix (implĂ©mentation simplifiĂ©e de l'API REST)

Configuration préalable

Sur le serveur avec Asterisk, il est nécessaire d'installer un serveur web (nous avons nginx+php-fpm), supervisor et git.

Commande d'installation (CentOS) :

yum install nginx php-fpm supervisor git

Accédez au répertoire accessible au serveur web, tirez l'application de git et définissez les droits appropriés sur le dossier :


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

Ensuite, configurons nginx, notre fichier de configuration est situé dans

/etc/nginx/conf.d/pbx.vistep.ru.conf

serveur {
	server_name www.pbx.vistep.ru pbx.vistep.ru;
	listen *:80;
	rewrite ^  https://pbx.vistep.ru$request_uri? permanent;
}

serveur {
#        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; # interdiction pour les fichiers cachés
        }

        location ~* \/(?:uploads|files)\/.*.php$ {
                deny all; # interdiction pour les scripts chargés
        }

        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; # mise en cache de la statique
        }

	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 vais laisser l'analyse de la configuration, les questions de sĂ©curitĂ©, l'obtention du certificat et mĂȘme le choix du serveur web en dehors de cet article — beaucoup en ont dĂ©jĂ  parlĂ©. L'application n'a pas de restrictions, elle fonctionne Ă  la fois en http et en https.

Nous avons un https, certificat let's encrypt.

Si vous avez tout fait correctement, vous devriez voir quelque chose comme cela en cliquant sur le lien.

Intégration d'Asterisk et Bitrix24.

Configuration de Bitrix24

Nous allons créer deux webhooks.

Webhook entrant.

Sous le compte administrateur (avec l'id 1), allez dans : Applications -> Webhooks -> Ajouter un webhook -> Webhook entrant

Intégration d'Asterisk et Bitrix24.

Remplissez les paramÚtres du webhook entrant comme sur les captures d'écran :

Intégration d'Asterisk et Bitrix24.

Intégration d'Asterisk et Bitrix24.

Et cliquez sur enregistrer.

AprÚs avoir enregistré, Bitrix24 vous fournira l'URL du webhook entrant, par exemple :

Intégration d'Asterisk et Bitrix24.

Conservez votre version de l'URL sans le \/profile\/ Ă  la fin — elle sera utilisĂ©e dans l'application pour travailler avec les appels entrants.

Pour moi, cela est https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Webhook sortant.

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

Les détails à nouveau 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.

Pour moi, cela est xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Il doit Ă©galement ĂȘtre copiĂ©, il est nĂ©cessaire pour passer des appels sortants.

Attention !

Un certificat SSL doit ĂȘtre configurĂ© sur le serveur Bitrix24 (vous pouvez utiliser letsencrypt), sinon l'API de Bitrix ne fonctionnera pas. Si vous avez la version cloud, pas de souci — SSL est dĂ©jĂ  configurĂ©.

Attention !

Dans le champ « Adresse du gestionnaire », vous devez indiquer une adresse accessible depuis Internet !

Enfin, nous allons installer notre CallMeOut en tant qu'application de passation d'appels (pour que lors d'un clic sur le numéro, une commande soit envoyée à la PBX pour l'initiation de l'appel).

Dans le menu, sélectionnez : Autres -> Téléphonie -> Autres -> ParamÚtres, définissez dans « Numéro pour l'appel sortant par défaut » l'application : CallMeOut et cliquez sur « Enregistrer »

Intégration d'Asterisk et Bitrix24.

Configuration d'Asterisk

Pour assurer une interaction réussie entre Asterisk et Bitrix24, nous devons ajouter l'utilisateur AMI callme dans 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 que nous devrons implémenter via le dialplan (dans notre cas, c'est extensions.ael).

Je présente le fichier complet, et ensuite je fournirai des explications :

globals {
    WAV=\/var\/www\/pbx.vistep.fr\/callme\/records\/wav; \/\/Dossier temporaire pour les fichiers WAV
    MP3=\/var\/www\/pbx.vistep.fr\/callme\/records\/mp3; \/\/Emplacement pour décharger les fichiers mp3
    URLRECORDS=https:\/\/pbx.vistep.fr\/callme\/records\/mp3;
    RECORDING=1; \/\/ Enregistrement, 1 - activé.
};

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()); \/\/ Mettre Ă  jour l'identification de l'appelant si nous l'avons obtenue de 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 déjà été fixé ===));  
}

}


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.fr\/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 : la directive globals.

Variable URLRECORDS contient l'URL des fichiers d'enregistrement des appels, que Bitrix24 utilisera pour les intégrer à la fiche de contact.

Ensuite, intéressons-nous au macro recording.

Ici, en plus de l'enregistrement des appels, nous allons définir la variable FullFname.

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

Elle contient l'URL complÚte vers un fichier spécifique (le macro est appelé 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});
}

Supposons que nous appelions le 89991234567, nous commençons ici :

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

c'est-à-dire qu'il appelle la macro d'enregistrement de l'appel et définit les variables nécessaires.

Ensuite

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

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

Et à sa fin, dans un contexte spécial 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});
}

nous dĂ©sactivons l'enregistrement dans la table CDR pour cet extension (pas besoin ici), nous fixons l'heure de fin d'appel, calculons la durĂ©e, si le rĂ©sultat de l'appel n'est pas connu — nous dĂ©finissons (la variable CallMeDISPOSITION) et, en dernier recours, nous envoyons tout Ă  Bitrix via cURL.

Et un peu de magie — l'appel entrant :

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // nous définissons le CallerID si nous l'avons appris de Bitrix24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // nous commençons le chronomÚtre de l'appel
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)});
        Hangup();
        }

Ici, une seule ligne nous intéresse.

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

Elle dit à l'ATS de définir CallerID(name) comme la variable CallMeCallerIDName.

La variable CallMeCallerIDName, Ă  son tour, est dĂ©finie par l'application CallMe (s'il y a un nom pour le numĂ©ro appelĂ© dans Bitrix24 — nous le fixerons comme CallerID(name), sinon — nous ne ferons rien).

Configuration de l'application

Le fichier de configuration de l'application — /var/www/pbx.vistep.ru/config.php

Description des paramĂštres de l'application :

  • CallMeDEBUG — si 1, alors tous les Ă©vĂ©nements traitĂ©s par l'application seront Ă©crits dans le fichier log, 0 — nous ne notons rien
  • tech — SIP/PJSIP/IAX/etc
  • authToken — jeton d'autorisation Bitrix24, code d'autorisation du webhook sortant
  • bitrixApiUrl — URL du webhook entrant, sans profile/
  • extensions — liste des numĂ©ros externes
  • context — contexte pour l'origine de l'appel
  • listener_timeout — vitesse de traitement des Ă©vĂ©nements d'Asterisk
  • asterisk — tableau avec les paramĂštres de connexion Ă  Asterisk :
  • host — ip ou nom d'hĂŽte du serveur Asterisk
  • scheme — schĂ©ma de connexion (tcp://, tls://)
  • port — port
  • username — nom d'utilisateur
  • secret — mot de passe
  • connect_timeout — dĂ©lai d'attente de connexion
  • read_timeout — dĂ©lai d'attente de lecture

exemple de fichier de configuration :

 1, // débogage des messages dans le journal : 1 - écriture, 0 - non-écriture
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', // jeton d'autorisation de Bitrix
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', // URL de l'API Bitrix (webhook entrant)
        'extensions' => array('888999'), // liste des numéros externes, séparés par des virgules
        'context' => 'dial_out', // contexte sortant pour l'origine de l'appel
        'asterisk' => array( // paramĂštres de connexion Ă  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, // vitesse de traitement des événements d'Asterisk

);

Configuration du superviseur

Supervisor sert à exécuter le processus de gestion des événements CallMeIn.php d'Asterisk, qui surveille les appels entrants et interagit avec Bitrix24 (afficher la fiche, cacher la fiche, etc.).

Fichier de configuration à 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

vérification de l'état de l'application :

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

Conclusion

C'était assez compliqué, mais je suis sûr qu'un administrateur expérimenté pourra l'implémenter et ravir ses utilisateurs.

Comme promis, lien vers GitHub.

Questions, suggestions — veuillez laisser des commentaires. Si vous ĂȘtes Ă©galement intĂ©ressĂ© par le dĂ©veloppement de cette intĂ©gration, faites-le moi savoir, et dans un prochain article, j'essaierai de tout expliquer plus en dĂ©tail.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster