
Der er forskellige muligheder for integration af IP-PBX Asterisk og CRM Bitrix24, men vi har alligevel besluttet at skrive vores egen.
Funktionaliteten er standard:
- Ved at klikke pÄ linket med kundens telefonnummer i Bitrix24, forbinder Asterisk brugerens interne nummer, som dette klik blev udfÞrt fra, med kundens telefonnummer. I Bitrix24 registreres der en optegnelse af opkaldet, og efter opkaldets afslutning hentes optagelsen af samtalen.
- Asterisk modtager et opkald udefra â i Bitrix24 viser vi kundekortet til den medarbejder, hvis nummer dette opkald kom til.
Hvis kunden ikke findes, Äbner vi kortet til oprettelse af et nyt lead.
NÄr opkaldet er afsluttet, afspejler vi dette i kortet og henter optagelsen af samtalen.
Nedenfor vil jeg fortĂŠlle, hvordan man opsĂŠtter det selv og give et link til GitHub â ja, tag det endelig og gĂžr brug af det!
Generel beskrivelse
Vi har kaldt vores integration CallMe. CallMe er en lille webapplikation skrevet i PHP.
Brugte teknologier og tjenester
- PHP 5.6
- Composer
- Nginx + php-fpm
- supervisor
- AMI (Asterisk Manager Interface)
- Bitrix-webhooks (forenklet REST API-implementering)
Forudkonfiguration
PĂ„ serveren med Asterisk skal der installeres en webserver (vi bruger nginx+php-fpm), supervisor og git.
Kommandoen til installation (CentOS):
yum install nginx php-fpm supervisor gitGÄ til den mappe, der er tilgÊngelig for webserveren, trÊk applikationen fra git og sÊt de nÞdvendige rettigheder pÄ mappen:
cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/
DernĂŠst konfigurerer vi nginx, vores konfigurationsfil ligger i
/etc/nginx/conf.d/pbx.vistep.ru.confserver {
server_name www.pbx.vistep.dk pbx.vistep.dk;
listen *:80;
rewrite ^ https://pbx.vistep.dk$request_uri? permanent;
}
server {
# listen *:80;
# server_name pbx.vistep.dk;
access_log /var/log/nginx/pbx.vistep.dk.access.log main;
error_log /var/log/nginx/pbx.vistep.dk.error.log;
listen 443 ssl http2;
server_name pbx.vistep.dk;
resolver 8.8.8.8;
ssl_stapling on;
ssl on;
ssl_certificate /etc/letsencrypt/live/pbx.vistep.dk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.dk/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; # Forbud mod skjulte filer
}
location ~* /(?:uploads|files)/.*.php$ {
deny all; # Forbud mod uploadede scripts
}
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; # Cache statiske filer
}
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;
}
}
Jeg efterlader konfiguration, sikkerhedsspĂžrgsmĂ„l, certifikatgenerering og valg af webserver uden for denne artikel â der er allerede skrevet meget om det. Applikationen har ingen begrĂŠnsninger, den fungerer bĂ„de via http og https.
Vi bruger https, certifikat fra letâs encrypt.
Hvis du har gjort alt korrekt, skal du ved at fĂžlge linket se noget lignende.

Konfiguration af Bitrix24
Lad os oprette to webhooks.
IndgÄende webhook.
Log ind med administratoraccount (id 1) og gÄ til: Applikationer -> Webhooks -> TilfÞj webhook -> IndgÄende webhook

Udfyld parametrene for den indgÄende webhook som vist i skÊrmbillederne:


Og tryk pÄ gem.
Efter gemmelsen vil Bitrix24 give dig URL'en til den indgÄende webhook, for eksempel:

Gem din version af URL'en uden den afsluttende /profile/ â den vil blive brugt i applikationen til at hĂ„ndtere indgĂ„ende opkald.
For mig er det https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/
UdgÄende webhook.
Applikationer -> Webhooks -> TilfÞj webhook -> UdgÄende webhook
Detaljerne findes igen i skĂŠrmbillederne:


Gem og fÄ autorisationskoden

For mig er det xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Denne skal ogsÄ kopieres, da den er nÞdvendig for at foretage udgÄende opkald.
Vigtigt!
PĂ„ Bitrix24-serveren skal SSL-certifikatet vĂŠre konfigureret (letsencrypt kan bruges), ellers vil Bitrix API ikke fungere. Hvis du har en cloud-version, behĂžver du ikke bekymre dig â der er allerede SSL.
Vigtigt!
I feltet "Handler URL" skal du angive en adresse, der er tilgĂŠngelig fra internettet!
Og som det sidste trin installerer vi vores CallMeOut som en applikation til at foretage opkald (sÄ nÄr du klikker pÄ et nummer, sendes en kommando til ACD for at initiere opkaldet).
I menuen vÊlger vi: Flere -> Telefonisystem -> Flere -> Indstillinger, sÊtter "Standardnummer til udgÄende opkald" til App: CallMeOut og klikker pÄ "Gem".

Konfiguration af Asterisk
For at sikre, at Asterisk og Bitrix24 fungerer sammen, skal vi tilfĂžje AMI-brugeren callme i 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
Der er nogle tricks, som skal implementeres gennem dialplan (i vores tilfĂŠlde extensions.ael).
Her er hele filen, og jeg vil give forklaringer bagefter:
globals {
WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/Midlertidig katalog med WAV
MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/Hvor mp3-filerne gemmes
URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
RECORDING=1; \/\/ Optagelse, 1 - aktiveret.
};
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()); \/\/ SĂŠtter CallerID hvis vi kender det fra 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 var allerede sat ===));
}
}
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});
}
};
Lad os starte fra begyndelsen: direktivet globals.
Variabel URLRECORDS gemmer URL'en til optagelsesfiler, som Bitrix24 vil trĂŠkke ind i kontaktkortet.
DernĂŠst er vi interesserede i makroen recording.
Her, udover optagelse af samtaler, sĂŠtter vi variablen FullFname.
Set(FullFname=${URLRECORDS}\/${datedir}\/${fname}.mp3);Den gemmer den fulde URL til den specifikke fil (makroen kaldes overalt).
Lad os gennemgÄ udgÄende opkald:
_. => {
&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});
}
Lad os antage, at vi ringer til 89991234567, fĂžrst ender vi her:
&recording(${CALLERID(number)},${EXTEN});dvs. makroen til optagelse af samtalen kaldes og de nĂždvendige variabler indstilles.
NĂŠste
Set(__CallIntNum=${CALLERID(num)})
Set(CallStart=${STRFTIME(epoch,,%s)});
vi registrerer, hvem der initierede opkaldet, og registrerer tiden for opkaldets start.
Og ved dens afslutning, i en specifik kontekst 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});
}
vi deaktiverer optagelsen i CDR-tabellen for denne extension (det er ikke nÞdvendigt der), indstiller tidspunkterne for opkaldets afslutning, beregner varigheden, hvis resultaterne af opkaldet er ukendte, sÄ sÊttes variablen CallMeDISPOSITION) og som det sidste skridt sender vi alt til Bitrix via systemets curl.
Og lidt mere magi - indgÄende opkald:
888999 => {
&recording(${CALLERID(number)},${EXTEN});
Answer();
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // sĂŠtter CallerID, hvis vi genkender det fra Bitrix24
Set(CallStart=${STRFTIME(epoch,,%s)}); // starter tidtagning for opkaldet
Queue(Q1,tT);
Set(CallMeDISPOSITION=${CDR(disposition)});
Hangup();
}
Her er vi kun interesseret i én linje.
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());Den instruerer PBX'en til at indstille CallerID(name) lig med variablen CallMeCallerIDName.
Selve variablen CallMeCallerIDName, i sin tur, indstilles af applikationen CallMe (hvis der er et navn i Bitrix24 for det ringende nummer - indstilles som CallerID(name), hvis ikke - gĂžr vi ikke noget).
Indstillinger for applikationen
Applikationens indstillingsfil - /var/www/pbx.vistep.ru/config.php
Beskrivelse af applikationens parametre:
- CallMeDEBUG â hvis 1, sĂ„ vil alle begivenheder, der behandles af applikationen, blive skrevet til logfilen, 0 - ingen optagelse
- tech â SIP/PJSIP/IAX/etc
- authToken â Bitrix24 autorisationstoken, autorisationskode for udgĂ„ende webhook
- bitrixApiUrl â URL for indgĂ„ende webhook, uden profile/
- extentions â liste over eksterne numre
- context â kontekst for opkaldsoprindelse
- listener_timeout â hastigheden for behandling af begivenheder fra Asterisk
- asterisk â array med indstillinger for forbindelse til Asterisk:
- host â ip eller hostname for Asterisk-serveren
- scheme â forbindelsesskema (tcp://, tls://)
- port â port
- brugernavn â brugernavn
- hemmelig â adgangskode
- connect_timeout â forbindelse timeout
- read_timeout â lĂŠse timeout
eksempel pÄ konfigurationsfil:
1, // debugs beskeder i loggen: 1 - vi logger, 0 - vi logger ikke
'tech' => 'SIP',
'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //authorization token for Bitrix
'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //URL til Bitrix API (indgÄende webhook)
'extentions' => array('888999'), // liste over eksterne numre, adskilt af komma
'context' => 'dial_out', // udgÄende kontekst for opkaldsoprindelse
'asterisk' => array( // indstillinger for forbindelse til 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, // hastigheden for behandling af begivenheder fra Asterisk
);Konfiguration af supervisor
Supervisor bruges til at starte proceshandleren for begivenheder fra Asterisk CallMeIn.php, som overvÄger indgÄende opkald og interagerer med Bitrix24 (viser kort, skjuler kort osv.).
Konfigurationsfil, der skal oprettes:
/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 og genstart af applikationen:
supervisorctl start callme
supervisorctl restart callmevis applikationens driftsstatus:
supervisorctl status callme
callme RUNNING pid 11729, uptime 17 days, 16:58:07Konklusion
Det blev lidt kompliceret, men jeg er sikker pÄ, at en erfaren administrator kan implementere det og glÊde deres brugere.
Som lovet, .
SpĂžrgsmĂ„l, Ăžnsker â kontakt venligst i kommentarerne. Hvis du ogsĂ„ er interesseret i, hvordan denne integration blev udviklet, sĂ„ skriv, og jeg vil forsĂžge at uddybe det i en kommende artikel.
Kilde: habr.com
