Integração do Asterisk com o Bitrix24

Integração do Asterisk com o Bitrix24
Na rede, existem diferentes opções de integração da central telefônica IP Asterisk com o CRM Bitrix24, mas decidimos criar a nossa própria.

As funcionalidades são padrão:

  • Ao clicar no link com o número de telefone do cliente no Bitrix24, o Asterisk conecta o número interno do usuário que fez o clique ao número de telefone do cliente. No Bitrix24, é registrado um registro da chamada e, ao final da ligação, a gravação da conversa é acessada.
  • Uma chamada externa chega ao Asterisk — na interface do Bitrix24, mostramos o cartão do cliente para o funcionário que recebeu a ligação.
    Se esse cliente não existir, abrimos o cartão para criar um novo lead.
    Assim que a chamada termina, registramos isso no cartão e acessamos a gravação da conversa.

Abaixo, explicarei como configurar tudo em seu sistema e fornecerei um link para o GitHub — sim, pegue e utilize!

Descrição Geral

Chamamos nossa integração de CallMe. CallMe é um pequeno aplicativo web escrito em PHP.

Tecnologias e Serviços Utilizados

  • PHP 5.6
  • Biblioteca AMI do PHP
  • Composer
  • Nginx + php-fpm
  • supervisor
  • AMI (Interface do Gerenciador Asterisk)
  • Webhooks do Bitrix (implementação simplificada da REST API)

Configuração preliminar

No servidor com Asterisk, é necessário instalar um servidor web (nós usamos nginx+php-fpm), supervisor e git.

Comando para instalação (CentOS):

yum install nginx php-fpm supervisor git

Acesse o diretório acessível ao servidor web, clonar o aplicativo do git e definir as permissões necessárias na pasta:


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

Em seguida, configuraremos o nginx, nossa configuração está em

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

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

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


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

    listen 443 ssl http2;
    server_name pbx.vistep.pt;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.pt/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.pt/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; # Proibido para arquivos ocultos
        }

        location ~* \/(?:uploads|files)\/.*.php$ {
                deny all; # Proibido para scripts enviados
        }

        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 para arquivos estáticos
        }

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

A análise da configuração, questões de segurança, obtenção do certificado e até a escolha do servidor web eu deixarei de fora do artigo — sobre isso já foi muito escrito. O aplicativo não tem restrições, ele funciona tanto por http quanto por https.

Estamos utilizando https, certificado Let's Encrypt.

Se você fez tudo corretamente, ao acessar o link deverá ver algo semelhante

Integração do Asterisk com o Bitrix24

Configuração do Bitrix24

Vamos criar dois webhooks.

Webhook de entrada.

Com a conta de administrador (com id 1), navegue até: Aplicativos -> Webhooks -> Adicionar webhook -> Webhook de entrada

Integração do Asterisk com o Bitrix24

Preencha os parâmetros do webhook de entrada conforme as telas:

Integração do Asterisk com o Bitrix24

Integração do Asterisk com o Bitrix24

E clique em salvar.

Após salvar, o Bitrix24 fornecerá a URL do webhook de entrada, por exemplo:

Integração do Asterisk com o Bitrix24

Salve sua versão da URL sem o final /profile/ — ela será usada no aplicativo para gerenciar chamadas de entrada.

Aqui está: https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Webhook de saída.

Aplicativos -> Webhooks -> Adicionar webhook -> Webhook de saída

Mais detalhes novamente nas telas:

Integração do Asterisk com o Bitrix24

Integração do Asterisk com o Bitrix24

Salve e obtenha o código de autorização

Integração do Asterisk com o Bitrix24

Aqui está: xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Ele também precisa ser copiado, pois será necessário para realizar chamadas de saída.

Importante!

No servidor Bitrix24, um certificado SSL deve ser configurado (pode usar letsencrypt), caso contrário, a API do Bitrix não funcionará. Se você estiver usando a versão em nuvem, não se preocupe, pois já há um SSL configurado.

Importante!

O endereço no campo "Endereço do manipulador" deve ser um endereço acessível pela Internet!

E, como último toque, vamos instalar nosso CallMeOut como um aplicativo para realizar chamadas (para que, ao clicar no número, um comando para originar a chamada seja enviado para a central telefônica).

No menu, escolhemos: Mais -> Telefonia -> Mais -> Configurações, definimos como "Número para chamada de saída por padrão" o Aplicativo: CallMeOut e clicamos em "Salvar".

Integração do Asterisk com o Bitrix24

Configuração do Asterisk.

Para uma interação bem-sucedida entre Asterisk e Bitrix24, precisamos adicionar o usuário AMI callme no 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

Em seguida, existem algumas dicas que precisarão ser implementadas através do dialplan (neste caso, é o extensions.ael).

Apresento o arquivo completo e, em seguida, fornecerei explicações:

globals {
    WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/Diretório temporário para WAV
    MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/Local onde os arquivos mp3 serão armazenados
    URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
    RECORDING=1; \/\/ Gravação, 1 - ativada.
};

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()); \/\/ ajustamos o CallerID se soubermos através do 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 já estava definido ===));  
}

}


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

};

Vamos começar do início: a diretiva globals.

Variável URLRECORDS armazenando a URL dos arquivos de gravação das chamadas, que o Bitrix24 usará para puxá-los para o cartão de contato.

A seguir, estamos interessados no macro recording.

Aqui, além de gravar as chamadas, iremos definir a variável FullFname.

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

Ela armazena a URL completa para um arquivo específico (o macro é chamado em todos os lugares).

Vamos analisar a chamada de saída:

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

Suponha que estamos ligando para 89991234567, a primeira coisa que encontramos é:

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

ou seja, o macro de gravação da conversa é chamado e as variáveis necessárias são definidas.

Em seguida

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

registramos quem iniciou a chamada e fixamos o momento de início da ligação.

E ao seu término, em um contexto específico 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});
}

desativamos a gravação na tabela CDR para essa extensão (não é necessário lá), definimos o horário de término da chamada, calculamos a duração, se o resultado da chamada não for conhecido — colocamos (variável CallMeDISPOSITION) e, por fim, enviamos tudo para o Bitrix através do curl do sistema.

E mais um pouco de mágica — chamada recebida:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // definimos CallerID se soubermos pelo Bitrix24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // começamos a contagem do tempo da chamada
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)});
        Hangup();
        }

Aqui nos interessa apenas uma linha.

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

Ela instrui a PBX a definir CallerID(name) igual à variável CallMeCallerIDName.

A própria variável CallMeCallerIDName, por sua vez, é definida pelo aplicativo CallMe (se no Bitrix24 houver um nome para o número que chamou — configuramos como CallerID(name), se não — nada será feito).

Configuração do aplicativo

O arquivo de configuração do aplicativo — /var/www/pbx.vistep.ru/config.php

Descrição dos parâmetros do aplicativo:

  • CallMeDEBUG — se for 1, todas as atividades processadas pelo aplicativo serão registradas no arquivo de log, 0 — não registramos nada
  • tech — SIP/PJSIP/IAX/etc
  • authToken — token de autorização do Bitrix24, código de autorização do webhook de saída
  • bitrixApiUrl — URL do webhook de entrada, sem profile/
  • extentions — lista de números externos
  • contexto — contexto para a origem da chamada
  • listener_timeout — taxa de processamento de eventos do Asterisk
  • asterisk — array com as configurações de conexão ao Asterisk:
  • host — ip ou hostname do servidor Asterisk
  • scheme — esquema de conexão (tcp://, tls://)
  • port — porta
  • nome de usuário — nome de usuário
  • secret — senha
  • connect_timeout — tempo limite de conexão
  • read_timeout — tempo limite de leitura

exemplo de arquivo de configuração:

 1, // mensagens de debug no log: 1 - escreve, 0 - não escreve
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', // token de autorização do Bitrix
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', // url da API do Bitrix (webhook de entrada)
        'extentions' => array('888999'), // lista de números externos, separados por vírgula
        'context' => 'dial_out', // contexto de saída para a origem da chamada
        'asterisk' => array( // configurações para conexão ao 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, // taxa de processamento de eventos do Asterisk

);

Configuração do supervisor

Supervisor serve para iniciar o processo manipulador de eventos CallMeIn.php do Asterisk, que monitora chamadas recebidas e interage com o Bitrix24 (mostrar ou ocultar o cartão, etc.).

Arquivo de configuração que precisa ser criado:

/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

Início e reinício da aplicação:

supervisorctl start callme
supervisorctl restart callme

verificar o status da aplicação:

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

Conclusão

Parece bastante complicado, mas estou certo de que um administrador experiente conseguirá implementá-lo e satisfazer seus usuários.

Como prometido, link no GitHub.

Dúvidas, sugestões — fiquem à vontade para deixar comentários. Também, se tiver interesse em saber como foi o desenvolvimento dessa integração, escreva e na próxima postagem tentarei explicar tudo de forma mais detalhada.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster