Integration av Asterisk och Bitrix24

Integration av Asterisk och Bitrix24
Det finns olika alternativ för integration av IP-ATC Asterisk och CRM Bitrix24, men vi beslutade oss för att skriva vÄr egen lösning.

Funktionaliteten Àr standardiserad:

  • Genom att klicka pĂ„ lĂ€nken med kundens telefonnummer i Bitrix24 kopplar Asterisk den interna telefonnummeranvĂ€ndaren, som gjorde klicket, med kundens telefonnummer. I Bitrix24 registreras ett samtalslogg och efter samtalet hĂ€mtas inspelningen.
  • NĂ€r ett samtal kommer in externt visar vi kundens kort i Bitrix24 för den medarbetare vars nummer samtalet ringdes till.
    Om det inte finns en sÄdan kund öppnar vi ett kort för att skapa en ny lead.
    SÄ snart samtalet Àr avslutat, Äterspeglar vi detta i kortet och hÀmtar samtalsinspelningen.

Under rubriken kommer jag att berĂ€tta hur du stĂ€ller in allt och ge dig lĂ€nken till github – ja, ja, ta och anvĂ€nd!

AllmÀn beskrivning

Vi kallade vÄr integration CallMe. CallMe Àr en liten webbapplikation som Àr skriven i PHP.

AnvÀnda teknologier och tjÀnster

  • PHP 5.6
  • PHP AMI-bibliotek
  • Composer
  • Nginx + php-fpm
  • supervisor
  • AMI (Asterisk Manager Interface)
  • Bitrix-webhooks (förenklad implementation av REST API)

FörinstÀllning

PÄ servern med Asterisk mÄste du installera en webbserver (vi anvÀnder nginx+php-fpm), supervisor och git.

Kommando för att installera (CentOS):

yum install nginx php-fpm supervisor git

GÄ till katalogen som Àr tillgÀnglig för webbservern, dra applikationen frÄn git och stÀll in rÀttigheter för mappen:


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

Sedan konfigurerar vi nginx, vÄr konfiguration ligger i

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

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

server {
#        listen *:80;
#	server_name pbx.vistep.se;


	access_log /var/log/nginx/pbx.vistep.se.access.log main;
        error_log /var/log/nginx/pbx.vistep.se.error.log;

    listen 443 ssl http2;
    server_name pbx.vistep.se;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.se/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.se/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; # förbud mot dolda filer
        }

        location ~* \/(?:uploads|files)\/.*.php$ {
                deny all; # förbud mot uppladdade skript
        }

        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; # caching av statiskt innehÄll
        }

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

Jag lĂ€mnar konfigurationens analys, sĂ€kerhetsfrĂ„gor, certifikatförvĂ€rv och till och med valet av webbserver utanför artikeln — det har skrivits mycket om detta. Applikationen har inga begrĂ€nsningar, den fungerar bĂ„de med http och https.

Vi anvĂ€nder https, certifikat frĂ„n Let’s Encrypt.

Om du har gjort allt rÀtt, sÄ bör du se nÄgot liknande nÀr du följer lÀnken.

Integration av Asterisk och Bitrix24

Konfiguration av Bitrix24

Vi skapar tvÄ webbhookar.

Inkommande webhook.

Under administratörskontot (med id 1) gÄr vi till: Applikationer -> Webbhookar -> LÀgg till webhook -> Inkommande webhook

Integration av Asterisk och Bitrix24

Fyll i parametrarna för det inkommande webhooket som pÄ skÀrmdumparna:

Integration av Asterisk och Bitrix24

Integration av Asterisk och Bitrix24

Och klicka pÄ spara.

Efter att ha sparat kommer Bitrix24 att tillhandahÄlla URL:en för det inkommande webhooket, till exempel:

Integration av Asterisk och Bitrix24

Spara din variant av URL:en utan slutande /profile/ — den kommer att anvĂ€ndas i applikationen för att hantera inkommande samtal.

Detta Àr min https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

UtgÄende webhook.

Applikationer -> Webbhookar -> LÀgg till webhook -> UtgÄende webhook

Detaljer igen pÄ skÀrmdumparna:

Integration av Asterisk och Bitrix24

Integration av Asterisk och Bitrix24

Spara och fÄ autorisationskoden

Integration av Asterisk och Bitrix24

Detta Àr min xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Denna mÄste ocksÄ kopieras, den behövs för att göra utgÄende samtal.

Viktigt!

PĂ„ Bitrix24-servern mĂ„ste ett SSL-certifikat (man kan anvĂ€nda Let’s Encrypt) vara instĂ€llt, annars fungerar inte Bitrix API. Om du har en molnversion behöver du inte oroa dig – den har redan SSL.

Viktigt!

I fÀltet "Handler-adress" mÄste en adress som Àr tillgÀnglig frÄn internet anges!

Som sista steg installerar vi vÄrt CallMeOut som en applikation för att göra samtal (sÄ att en kommando skickas till telefonvÀxeln för att initiera samtalet nÀr man klickar pÄ numret).

I menyn vÀljer vi: Mer -> Telefonilösning -> Mer -> InstÀllningar, sÀtter "Nummer för standardutgÄende samtal" till Applikation: CallMeOut och klickar pÄ "Spara".

Integration av Asterisk och Bitrix24

Konfigurera Asterisk

För att Asterisk och Bitrix24 ska kunna kommunicera framgÄngsrikt behöver vi lÀgga till AMI-anvÀndaren 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

Vidare finns det flera knep som behöver implementeras genom dialplan (hos oss Àr det extensions.ael).

HÀr Àr hela filen, och efter det kommer jag att ge förklaringar:

globals {
    WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/ TemporÀr katalog med WAV
    MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/ Var man laddar upp mp3-filer
    URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
    RECORDING=1; \/\/ Inspelning, 1 - aktiverad.
};

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 om vi har kÀnslighet av 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 redan var instÀllt ===));  
}

}


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

};

LÄt oss börja frÄn början: direktiv globals.

Variabel URLRECORDS innehÄller URL till samtalsinspelningarna, som Bitrix24 kommer att dra in i kontaktkortet.

Vidare Àr vi intresserade av makrot recording.

HÀr, förutom inspelning av samtal, kommer vi att stÀlla in variabeln FullFname.

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

Den lagrar den fullstÀndiga URL:en till en specifik fil (makrot anropas överallt).

LÄt oss analysera ett utgÄende samtal:

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

LÄt oss sÀga att vi ringer till 89991234567, först hamnar vi hÀr:

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

Det vill sÀga, makrot för samtalsinspelning körs och nödvÀndiga variabler sÀtts.

NĂ€sta

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

Vi registrerar vem som initierade samtalet och registrerar starttiden för samtalet.

Och efter att det har avslutats, i en speciell 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});
}

Vi stĂ€nger av inspelningen i CDR-tabellen för denna förlĂ€ngning (det Ă€r inte nödvĂ€ndigt dĂ€r), sĂ€tter tiden för samtalets slut, berĂ€knar varaktigheten, om resultatet av samtalet Ă€r okĂ€nt – sĂ„ sĂ€tter vi (variabeln CallMeDISPOSITION) och, som sista steg, skickar allt till Bitrix via systemcurl.

Och lite mer magi – inkommande samtal:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // sÀtter CallerID om vi kÀnner till den frÄn Bitrix24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // börjar tidtagning för samtalet
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)});
        Hangup();
        }

HÀr Àr vi endast intresserade av en rad.

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

Den sÀger till vÀxel att stÀlla in CallerID(name) till vÀrdet av variabeln CallMeCallerIDName.

SjĂ€lva variabeln CallMeCallerIDName sĂ€tts av applikationen CallMe (om det finns en fullstĂ€ndig namnregistrering i Bitrix24 för numret som ringer – sĂ„ sĂ€tts det som CallerID(name), om inte – sĂ„ gör vi ingenting).

AppinstÀllning

InstĂ€llningsfilen för applikationen – /var/www/pbx.vistep.ru/config.php

Beskrivning av applikationens parametrar:

  • CallMeDEBUG – om 1, sĂ„ kommer alla hĂ€ndelser som applikationen bearbetar att skrivas till loggfilen, 0 – ingen loggning
  • tech – SIP/PJSIP/IAX/etc
  • authToken — autentiseringstoken för Bitrix24, kod för den utgĂ„ende webhooken
  • bitrixApiUrl — inkommande webhook-URL, utan profile/
  • extentions — lista över externa nummer
  • context — kontext för uppringning
  • listener_timeout — hastigheten för hĂ€ndelsebehandling frĂ„n Asterisk
  • asterisk — array med anslutningsinstĂ€llningar till Asterisk:
  • host — ip eller vĂ€rdnamn för Asterisk-servern
  • scheme — anslutningsschema (tcp://, tls://)
  • port — port
  • username — anvĂ€ndarnamn
  • secret — lösenord
  • connect_timeout — anslutningstimeout
  • read_timeout — lĂ€stimeout

exempel pÄ konfigurationsfil:

 <?php
return array(

        'CallMeDEBUG' => 1, // debugmeddelanden i loggen: 1 - skriver, 0 - skriver inte
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', // autentiseringstoken för Bitrix
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', // url till Bitrix API (inkommande webhook)
        'extentions' => array('888999'), // lista över externa nummer, separerade med kommatecken
        'context' => 'dial_out', // utgÄende kontext för uppringning
        'asterisk' => array( // instÀllningar för anslutning till 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, // hastighet för hÀndelsebehandling frÄn Asterisk

);

Konfigurera supervisor

Supervisor anvÀnds för att köra processhanteraren för hÀndelser frÄn Asterisk CallMeIn.php, som övervakar inkommande samtal och interagerar med Bitrix24 (visa kort, dölja kort osv.).

Konfigurationsfilen som behöver skapas:

/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

Starta och starta om applikationen:

supervisorctl start callme
supervisorctl restart callme

visa applikationens status:

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

Slutsats

Det har blivit ganska komplicerat, men jag Àr sÀker pÄ att en erfaren administratör kan implementera detta och glÀdja sina anvÀndare.

Som jag lovade, lÀnk till GitHub.

FrĂ„gor, önskemĂ„l — vĂ€nligen lĂ€mna i kommentarerna. Om du Ă€r intresserad av hur utvecklingen av denna integration gick till, skriv gĂ€rna, sĂ„ ska jag i nĂ€sta artikel försöka förklara allt mer detaljerat.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster