
V omrežju obstajajo različne možnosti integracije IP-ATK Asterisk in CRM Bitrix24, vendar smo se vseeno odločili napisati svojo.
Funkcionalnost je povsem standardna:
- S klikom na povezavo s telefonsko številko stranke v Bitrix24, Asterisk poveže notranjo številko uporabnika, s katerega je bil ta klik izveden, s telefonsko številko stranke. V Bitrix24 se zabeleži zapis o klicu in ob koncu klica se prikliče zapis pogovora.
- Na Asterisk prejme klic od zunaj – v vmesniku Bitrix24 prikažemo kartico stranke tistemu zaposlenemu, na katerega številko je ta klic prišel.
Če takšne stranke ni, odpremo kartico za ustvarjanje novega lead-a.
Ko je klic končan, to odražamo na kartici in prikličejo se zapisi pogovora.
Podrobneje bom opisal, kako vse nastaviti pri sebi in dal povezavo na github – da-da, vzemite in uporabljajte!
Splošni opis
Svojo integracijo smo poimenovali CallMe. CallMe je majhna spletna aplikacija, napisana v PHP.
Uporabljene tehnologije in storitve
- PHP 5.6
- Composer
- Nginx + php-fpm
- supervisor
- AMI (Asterisk Manager Interface)
- Bitrix Webhooki (poenostavljena realizacija REST API)
Predhodna nastavitev
Na strežniku z Asterisk je potrebno namestiti spletni strežnik (pri nas je to nginx+php-fpm), supervisor in git.
Ukaz za namestitev (CentOS):
yum install nginx php-fpm supervisor gitPremaknemo se v direktorij, ki je dostopen spletnemu strežniku, potegnemo iz gita aplikacijo in postavimo ustrezna dovoljenja za mapo:
cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/
Nato nastavimo nginx, naš konfiguracijski datoteka se nahaja v
/etc/nginx/conf.d/pbx.vistep.ru.confserver {
server_name www.pbx.vistep.si pbx.vistep.si;
listen *:80;
rewrite ^ https://pbx.vistep.si$request_uri? permanent;
}
server {
# listen *:80;
# server_name pbx.vistep.si;
access_log /var/log/nginx/pbx.vistep.si.access.log main;
error_log /var/log/nginx/pbx.vistep.si.error.log;
listen 443 ssl http2;
server_name pbx.vistep.si;
resolver 8.8.8.8;
ssl_stapling on;
ssl on;
ssl_certificate /etc/letsencrypt/live/pbx.vistep.si/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.si/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; # prepovedano za skrite datoteke
}
location ~* /(?:uploads|files)/.*.php$ {
deny all; # prepovedano za naložene skripte
}
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; # predpomnjenje statike
}
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;
}
}
Razlaga konfiguracije, vprašanja varnosti, pridobitev certifikata in celo izbira spletnega strežnika ostajajo zunaj okvira tega članka — o tem je že veliko napisanega. Aplikacija nima omejitev, deluje tako po http kot po https.
Imamo https, certifikat Let's Encrypt.
Če ste vse pravilno naredili, bi ob prehodu na povezavo morali videti nekaj podobnega.

Nastavitev Bitrix24.
Ustvarimo dva spletna vhoda.
Vhodni spletni vhod.
Pod uporabniškim računom skrbnika (s id 1) gremo po poti: Aplikacije -> Spletni vhodi -> Dodaj spletni vhod -> Vhodni spletni vhod.

Izpolnimo parametre vhodnega spletnega vhoda, kot je prikazano na screenih:


In pritisnemo shraniti.
Po shranjevanju bo Bitrix24 zagotovil URL vhodnega spletnega vhoda, na primer:

Shrani si različico URL brez zaključnega /profile/ — ta se bo uporabljala v aplikaciji za delo z vhodnimi klici.
To je moje. https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/
Izhodni spletni vhod.
Aplikacije -> Spletni vhodi -> Dodaj spletni vhod -> Izhodni spletni vhod.
Podrobnosti znova na screenih:


Shranjujemo in pridobimo avtentikacijsko kodo.

To je moje. xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. To je treba prav tako kopirati, potrebna bo za izvajanje odhodnih klicev.
Důležité!
Na strežniku Bitrix24 mora biti nastavljen ssl-certifikat (lahko uporabite letsencrypt), sicer API Bitrixa ne bo deloval. Če imate oblačno različico, se lahko ne obremenjujete — tam je že ssl.
Důležité!
V polju „Naslov obdelovalca“ mora biti naveden naslov, dostopen iz interneta!
In kot zadnji korak bomo naš CallMeOut nastavili kot aplikacijo za klicanje (da ob kliknjenju na številko pošlje ukaz za izvor klica na ATE).
V meniju izberite: Več -> Telefonija -> Več -> Nastavitve, v „Številka za odhodni klic po privzetku“ izberite Aplikacija: CallMeOut in pritisnite „Shrani“

Nastavitev asteriska
Za uspešno sodelovanje Asteriska in Bitrix24 moramo dodati AMI-uporabnika callme v 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
Nato je nekaj zvijač, ki jih bo treba uvesti preko dialplana (to so pri nas extensions.ael).
Pripravljen je celoten datoteka, nato pa bom dal razlago:
globals {
WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/Začasni katalog sa WAV
MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/Kamo se izvoze mp3 datoteke
URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
RECORDING=1; \/\/ Snimanje, 1 - uključeno.
};
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()); \/\/ postavljamo CallerID ako smo ga saznali iz 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 već je postavljen ===));
}
}
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});
}
};
Počnimo od samog početka: direktiva globals.
Promenljiva URLRECORDS sadrži URL do datoteka sa snimcima razgovora, na kojem će Bitrix24 povlačiti u karticu kontakta.
Zatim nam je zanimljiv makro recording.
Ovde, osim snimanja razgovora, postavićemo promenljivu FullFname.
Set(FullFname=${URLRECORDS}\/${datedir}\/${fname}.mp3);Ona čuva pun URL do konkretne datoteke (makro se poziva svuda).
Analizirajmo odlazni poziv:
_. => {
&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});
}
Recimo, če kličemo na 89991234567, najprej prispemo sem:
&recording(${CALLERID(number)},${EXTEN});t.j. aktiviramo makro za snemanje klica in nastavimo potrebne spremenljivke.
Naprej
Set(__CallIntNum=${CALLERID(num)})
Set(CallStart=${STRFTIME(epoch,,%s)});
zabeležemo, kdo je iniciiral klic in zabeležemo čas začetka klica.
In ob njegovem zaključku, v posebnem kontekstu 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});
}
izklopimo snemanje v CDR tabeli za to ekstenzijo (ne potrebujemo ga tam), nastavimo čas zaključka klica, izračunamo trajanje, če je rezultat klica neznan — nastavimo (spremenljivka CallMeDISPOSITION) in, zadnji korak, pošljemo vse bitrixu preko sistemskega curl.
In še malo magije — prihajajoči klic:
888999 => {
&recording(${CALLERID(number)},${EXTEN});
Answer();
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // nastavimo CallerID, če smo ga izvedeli iz Bitrix24
Set(CallStart=${STRFTIME(epoch,,%s)}); // začnemo meriti čas klica
Queue(Q1,tT);
Set(CallMeDISPOSITION=${CDR(disposition)});
Hangup();
}
Tukaj nas zanima le ena vrstica.
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());To pravi ATS-u, da nastavi CallerID(name) na spremenljivko CallMeCallerIDName.
Sama spremenljivka CallMeCallerIDName se nastavitev z aplikacijo CallMe (če je v Bitrix24 zapisano ime in priimek za številko klicatelja — nastavimo kot CallerID(name), če ne — ne bomo naredili nič).
Nastavitev aplikacije
Datoteka s configurarcia aplikacije — /var/www/pbx.vistep.ru/config.php
Opis parametrov aplikacije:
- CallMeDEBUG — če je 1, se v dnevnik zapisujejo vsi dogodki, ki jih obdeluje aplikacija, 0 — nič ne pišemo
- tech — SIP/PJSIP/IAX/itd.
- authToken — Bitrix24 authorization token, outgoing webhook authorization code
- bitrixApiUrl — Incoming webhook URL, without profile/
- extentions — List of external numbers
- context — Context for call origination
- listener_timeout — Event processing speed from Asterisk
- asterisk — Array with connection settings for Asterisk:
- host — IP or hostname of the Asterisk server
- scheme — Connection scheme (tcp://, tls://)
- port — Port
- username — Username
- secret — Password
- connect_timeout — Connection timeout
- read_timeout — Read timeout
Example of configuration file:
1, // Debug messages in the log: 1 - write, 0 - do not write
'tech' => 'SIP',
'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', // Bitrix authorization token
'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', // API URL of Bitrix (incoming webhook)
'extentions' => array('888999'), // List of external numbers, comma separated
'context' => 'dial_out', // Outgoing context for call origination
'asterisk' => array( // Settings for Asterisk connection
'host' => '10.100.111.249',
'scheme' => 'tcp://',
'port' => 5038,
'username' => 'callme',
'secret' => 'JD3clEB8_f23r-3ry84gJ',
'connect_timeout' => 10000,
'read_timeout' => 10000
),
'listener_timeout' => 300, // Event processing speed from Asterisk
);Configuring Supervisor
Supervisor is used to run the event handler process CallMeIn.php, which monitors incoming calls and interacts with Bitrix24 (show card, hide card, etc.).
Configuration file to be created:
/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.logStarting and restarting the application:
supervisorctl start callme
supervisorctl restart callmeViewing application status:
supervisorctl status callme
callme RUNNING pid 11729, uptime 17 days, 16:58:07Zaključek
It has become quite challenging, but I am sure — an experienced administrator will be able to implement this and delight their users.
As promised, .
Questions, suggestions — please leave a comment. Also, if you're interested in how the development of this integration went, write to me, and in the next article, I will try to reveal everything in more detail.
Izvor: habr.com
