
Im Internet gibt es verschiedene Integrationsmöglichkeiten für die IP-Telefonanlage Asterisk und das CRM Bitrix24, aber wir haben uns dennoch entschieden, unsere eigene Lösung zu schreiben.
Die Funktionalität ist ganz standardmäßig:
- Mit einem Klick auf den Link mit der Telefonnummer des Kunden in Bitrix24 verbindet Asterisk die interne Nummer des Benutzers, der auf den Link geklickt hat, mit der Telefonnummer des Kunden. In Bitrix24 wird ein Anrufprotokoll aufgezeichnet und nach dem Ende des Anrufs wird das Gesprächsprotokoll abgerufen.
- Ein Anruf wird extern an Asterisk weitergeleitet - im Bitrix24-Interface zeigen wir die Kundendaten dem Mitarbeiter an, auf dessen Nummer der Anruf eingegangen ist.
Falls es einen solchen Kunden nicht gibt, öffnen wir das Formular zur Erstellung eines neuen Leads.
Sobald der Anruf beendet ist, reflektieren wir dies in der Karte und rufen das Gesprächsprotokoll ab.
Unter dem Beitrag erkläre ich, wie man alles auf seinem Server einrichtet, und gebe einen Link zu GitHub - ja, ja, holt es euch und nutzt es!
Allgemeine Beschreibung
Unsere Integration haben wir CallMe genannt. CallMe ist eine kleine Webanwendung, die in PHP geschrieben wurde.
Verwendete Technologien und Dienste
- PHP 5.6
- Composer
- Nginx + php-fpm
- Supervisor
- AMI (Asterisk Manager Interface)
- Webhooks von Bitrix (vereinfachte Implementierung von REST API)
Vorbereitende Konfiguration
Auf dem Server mit Asterisk muss ein Webserver installiert werden (bei uns ist es nginx+php-fpm), Supervisor und git.
Befehl zur Installation (CentOS):
yum install nginx php-fpm supervisor gitWir wechseln in das Verzeichnis, das für den Webserver zugänglich ist, ziehen die Anwendung aus git und setzen die notwendigen Berechtigungen für den Ordner:
cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/
Danach konfigurieren wir nginx, unsere Konfiguration befindet sich in
/etc/nginx/conf.d/pbx.vistep.ru.confserver {
server_name www.pbx.vistep.de pbx.vistep.de;
listen *:80;
rewrite ^ https://pbx.vistep.de$request_uri? permanent;
}
server {
# listen *:80;
# server_name pbx.vistep.de;
access_log /var/log/nginx/pbx.vistep.de.access.log main;
error_log /var/log/nginx/pbx.vistep.de.error.log;
listen 443 ssl http2;
server_name pbx.vistep.de;
resolver 8.8.8.8;
ssl_stapling on;
ssl on;
ssl_certificate /etc/letsencrypt/live/pbx.vistep.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.de/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; # Zugriff auf versteckte Dateien verboten
}
location ~* \/(?:uploads|files)\/.*.php$ {
deny all; # Zugriff auf hochgeladene Skripte verboten
}
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; # Statik Caching
}
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;
}
}
Die Analyse der Konfiguration, Sicherheitsfragen, das Erlangen des Zertifikats und sogar die Auswahl des Webservers bleiben hier unerwähnt – darüber wurde bereits viel geschrieben. Die Anwendung hat keine Einschränkungen, sie funktioniert sowohl über http als auch über https.
Wir haben https, das Zertifikat von Let's Encrypt.
Wenn Sie alles richtig gemacht haben, sollten Sie beim Klicken auf den Link etwas Ähnliches sehen.

Konfiguration von Bitrix24
Lassen Sie uns zwei Webhooks erstellen.
Eingehender Webhook.
Unter dem Administratorkonto (mit ID 1) gehen wir zu: Anwendungen -> Webhooks -> Webhook hinzufügen -> Eingehender Webhook

Füllen Sie die Parameter des eingehenden Webhooks wie auf den Screenshots aus:


Und klicken Sie auf Speichern.
Nach dem Speichern stellt Bitrix24 die URL des eingehenden Webhooks zur Verfügung, z. B.:

Speichern Sie Ihre Variante der URL ohne den abschließenden /profile/ – sie wird in der Anwendung zur Bearbeitung eingehender Anrufe verwendet.
Das wäre für mich https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/
Ausgehender Webhook.
Anwendungen -> Webhooks -> Webhook hinzufügen -> Ausgehender Webhook
Die Details wieder auf den Screenshots:


Speichern und den Autorisierungscode erhalten.

Das wäre für mich xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Dies muss ebenfalls kopiert werden, da es für ausgehende Anrufe benötigt wird.
Wichtig!
Auf dem Bitrix24-Server muss ein SSL-Zertifikat eingerichtet sein (Letsencrypt kann verwendet werden), andernfalls funktioniert die Bitrix-API nicht. Wenn Sie die Cloud-Version nutzen, brauchen Sie sich keine Sorgen zu machen — dort ist bereits ein SSL-Zertifikat vorhanden.
Wichtig!
Im Feld "Handler-Adresse" muss eine aus dem Internet zugängliche Adresse angegeben werden!
Und als letzten Schliff installieren wir unsere CallMeOut-App für Telefonanrufe (damit beim Klicken auf eine Nummer im PBX ein Befehl zur Initiierung des Anrufs gesendet wird).
Im Menü wählen wir: Weitere -> Telefonie -> Weitere -> Einstellungen, setzen im Feld "Standardnummer für ausgehende Anrufe" die App: CallMeOut und klicken auf "Speichern".

Asterisk-Konfiguration
Für eine erfolgreiche Interaktion zwischen Asterisk und Bitrix24 müssen wir den AMI-Benutzer callme in die manager.conf hinzufügen:
[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
Es gibt noch einige Tricks, die wir im Dialplan (bei uns extensions.ael) implementieren müssen.
Ich führe die gesamte Datei auf, danach gebe ich Erklärungen:
globals {
WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/ Temporäres Verzeichnis für WAV
MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/ Wo die mp3-Dateien gespeichert werden
URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
RECORDING=1; \/\/ Aufnahme, 1 - aktiviert.
};
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()); \/\/ setzen CallerID basierend auf Information von 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 war bereits gesetzt ===));
}
}
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});
}
};
Lass uns von vorne beginnen: die Direktive globals.
Variable URLRECORDS speichert die URL zu den Aufzeichnungsdateien der Gespräche, von der Bitrix24 die Dateien in das Kontaktformular ziehen wird.
Als nächstes interessiert uns das Makro recording.
Hier, neben der Aufnahme der Gespräche, setzen wir die Variable FullFname.
Set(FullFname=${URLRECORDS}\/${datedir}\/${fname}.mp3);Sie speichert die vollständige URL zu einer bestimmten Datei (das Makro wird überall aufgerufen).
Lass uns den ausgehenden Anruf durchgehen:
_. => {
&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});
}
Angenommen, wir rufen die 89991234567 an, zunächst landen wir hier:
&recording(${CALLERID(number)},${EXTEN});d.h. das Makro zur Aufzeichnung des Gesprächs wird aufgerufen und die erforderlichen Variablen gesetzt.
Dann
Set(__CallIntNum=${CALLERID(num)})
Set(CallStart=${STRFTIME(epoch,,%s)});
wir erfassen, wer den Anruf initiiert hat, und protokollieren die Startzeit des Anrufs.
Und bei dessen Abschluss, im speziellen Kontext 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});
}
wir deaktivieren die Aufzeichnung in der CDR-Tabelle für diese Durchwahl (es ist nicht nötig), setzen die Abschlusszeit des Anrufs und berechnen die Dauer, wenn das Ergebnis des Anrufs unbekannt ist — setzen wir (Variable CallMeDISPOSITION) und als letzten Schritt senden wir alles über einen systemeigenen curl an Bitrix.
Und noch ein bisschen Magie — eingehender Anruf:
888999 => {
&recording(${CALLERID(number)},${EXTEN});
Answer();
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // wir setzen CallerID, wenn wir ihn von Bitrix24 erhalten haben
Set(CallStart=${STRFTIME(epoch,,%s)}); // wir starten den Zeitmesser für den Anruf
Queue(Q1,tT);
Set(CallMeDISPOSITION=${CDR(disposition)});
Hangup();
}
Hier interessiert uns nur eine Zeile.
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());Sie sagt der TK-Anlage, den CallerID(name) auf die Variable CallMeCallerIDName.
Die Variable CallMeCallerIDName wird wiederum von der Anwendung CallMe gesetzt (wenn in Bitrix24 ein Name für die Anrufernummer vorhanden ist — setzen wir ihn als CallerID(name), andernfalls unternehmen wir nichts).
Konfiguration der Anwendung
Die Konfigurationsdatei der Anwendung — /var/www/pbx.vistep.ru/config.php
Beschreibung der Anwendungsparameter:
- CallMeDEBUG — wenn 1, werden alle vom Programm verarbeiteten Ereignisse in die Protokolldatei geschrieben, 0 — nichts wird geschrieben
- tech — SIP/PJSIP/IAX/etc.
- authToken — Token zur Autorisierung Bitrix24, Autorisierungscode des ausgehenden Webhooks
- bitrixApiUrl — URL des eingehenden Webhooks, ohne profile/
- extentions — Liste externer Nummern
- context — Kontext für die Ursprungserstellung des Anrufs
- listener_timeout — Geschwindigkeit der Ereignisverarbeitung von Asterisk
- asterisk — Array mit Verbindungseinstellungen zu Asterisk:
- host — IP oder Hostname des Asterisk-Servers
- scheme — Verbindungsprotokoll (tcp://, tls://)
- port — Port
- username — Benutzername
- secret — Passwort
- connect_timeout — Verbindungszeitüberschreitung
- read_timeout — Lesezeitüberschreitung
Beispiel für eine Konfigurationsdatei:
1, // Debugging-Nachrichten im Protokoll: 1 - schreiben, 0 - nicht schreiben
'tech' => 'SIP',
'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', // Token zur Autorisierung bei Bitrix
'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', // URL zur Bitrix API (eingehender Webhook)
'extentions' => array('888999'), // Liste externer Nummern, durch Kommas getrennt
'context' => 'dial_out', // Ausgangskontext für die Ursprungserstellung des Anrufs
'asterisk' => array( // Einstellungen zur Verbindung zu 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, // Geschwindigkeit der Ereignisverarbeitung von Asterisk
);Supervisor-Konfiguration
Supervisor dient zum Starten des Ereignisverarbeitungsprozesses von Asterisk CallMeIn.php, der eingehende Anrufe überwacht und mit Bitrix24 interagiert (Karte anzeigen, Karte ausblenden usw.).
Die zu erstellende Konfigurationsdatei lautet:
/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.logStart und Neustart der Anwendung:
supervisorctl start callme
supervisorctl restart callmeStatus der Anwendung überprüfen:
supervisorctl status callme
callme RUNNING pid 11729, uptime 17 days, 16:58:07Fazit
Es war ziemlich komplex, aber ich bin mir sicher, dass ein erfahrener Administrator dies implementieren und seine Benutzer begeistern kann.
Wie versprochen, .
Fragen oder Wünsche — bitte in die Kommentare. Wenn Sie auch daran interessiert sind, wie die Entwicklung dieser Integration verlief, schreiben Sie es, und in meinem nächsten Artikel werde ich alles detaillierter erklären.
Quelle: habr.com
