Integração de Asterisk e Bitrix24

Integração de Asterisk e Bitrix24
A rede possui diferentes opções de integração IP-PBX Asterisk e Bitrix24 CRM, mas mesmo assim decidimos escrever a nossa própria.

Funcionalmente, tudo é 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 em nome de quem este clique foi feito com o número de telefone do cliente. No Bitrix24, um registro da chamada é gravado e, ao final da chamada, o registro da conversa é puxado.
  • O Asterisk recebe uma ligação externa - na interface do Bitrix24 mostramos o cartão do cliente ao funcionário para cujo número chegou a ligação.
    Caso não exista esse cliente, abra o cartão para criação de um novo lead.
    Assim que a ligação for finalizada, refletimos no cartão e abrimos a gravação da conversa.

Abaixo, vou lhe dizer como configurar tudo sozinho e fornecer um link para o github - sim, sim, pegue e use!

Descrição geral

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

Tecnologias e serviços usados

  • PHP 5.6
  • Biblioteca PHP AMI
  • Compor
  • nginx + phpfpm
  • supervisor
  • AMI (Interface do Gerenciador Asterisk)
  • Webhooks Bitrix (implementação simplificada da API REST)

predefinição

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

Comando de instalação (CentOS):

yum install nginx php-fpm supervisor git

Vamos ao diretório acessível ao servidor web, extraímos o aplicativo do Git e definimos os direitos necessários para a pasta:


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

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

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

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

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


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

    listen 443 ssl http2;
    server_name pbx.vistep.ru;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.ru/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; # запрет для скрытых файлов
        }

        location ~* /(?:uploads|files)/.*.php$ {
                deny all; # запрет для загруженных скриптов
        }

        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; # кеширование статики
        }

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

Deixarei análise de configuração, questões de segurança, obtenção de certificado e até escolha de servidor web fora do escopo do artigo - muito já foi escrito sobre isso. O aplicativo não tem restrições, funciona tanto em http quanto em https.

Temos https, vamos criptografar o certificado.

Se você fez tudo corretamente, clicando no link você verá algo assim

Integração de Asterisk e Bitrix24

Configurando Bitrix24

Vamos criar dois webhooks.

Webhook de entrada.

Na conta de administrador (com id 1), siga o caminho: Aplicativos -> Webhooks -> Adicionar webhook -> webhook de entrada

Integração de Asterisk e Bitrix24

Preencha os parâmetros do webhook de entrada como nas capturas de tela:

Integração de Asterisk e Bitrix24

Integração de Asterisk e Bitrix24

E clique em salvar.

Depois de salvar, o Bitrix24 fornecerá a URL do webhook recebido, por exemplo:

Integração de Asterisk e Bitrix24

Salve sua versão da URL sem o /profile/ final - ela será usada no aplicativo para trabalhar com chamadas recebidas.

eu tenho isto https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Webhook de saída.

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

Os detalhes estão nas capturas de tela:

Integração de Asterisk e Bitrix24

Integração de Asterisk e Bitrix24

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

Integração de Asterisk e Bitrix24

eu tenho isto xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Você também precisa copiá-lo para você mesmo, pois é necessário para fazer chamadas.

Importante!

Um certificado SSL deve ser configurado no servidor Bitrix24 (você pode usar letsencrypt), caso contrário a API Bitrix não funcionará. Se você possui uma versão em nuvem, não se preocupe – o SSL já está lá.

Importante!

No campo “Endereço do processador” deve ser indicado um endereço acessível pela Internet!

E com o toque final, vamos instalar nosso CallMeOut como um aplicativo para fazer chamadas (para que ao clicar no número do PABX voe um comando para originar a chamada).

No menu, selecione: Mais -> Telefonia -> Mais -> Configurações, coloque o "Número para chamadas efetuadas por padrão" Aplicativo: CallMeOut e clique em "Salvar"

Integração de Asterisk e Bitrix24

configuração de asterisco

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

A seguir, existem vários truques que precisarão ser implementados via dialplan (para nós é extensions.ael).

Citarei o arquivo inteiro e depois darei explicações:

globals {
    WAV=/var/www/pbx.vistep.ru/callme/records/wav; //Временный каталог с WAV
    MP3=/var/www/pbx.vistep.ru/callme/records/mp3; //Куда выгружать mp3 файлы
    URLRECORDS=https://pbx.vistep.ru/callme/records/mp3;
    RECORDING=1; // Запись, 1 - включена.
};

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()); // выставляем CallerID если узнали его у Битрикс24
        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 already was set ===));  
}

}


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: diretiva globals.

Variável URLRECORDS armazena a URL dos arquivos de gravação de conversas, de acordo com os quais o Bitrix24 os colocará no cartão de contato.

A seguir, estamos interessados ​​em macro macro gravação.

Aqui, além de gravar as conversas, vamos definir a variável NomeFcompleto.

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

Ele armazena o URL completo em um arquivo específico (a macro é chamada em qualquer lugar).

Vamos analisar a chamada efetuada:

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

Digamos que ligamos para 89991234567, a primeira coisa que recebemos aqui:

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

aqueles. a macro de gravação de chamadas é chamada e as variáveis ​​necessárias são definidas.

Próximo

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

gravamos quem iniciou a chamada e registramos a hora de início da chamada.

E após a sua conclusão, num contexto especial 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});
}

desabilitar a entrada na tabela CDR para este ramal (não é necessário lá), definir o horário de término da chamada, calcular a duração, se o resultado da chamada não for conhecido - definir (variável CallMeDISPOSIÇÃO) e, por último passo, enviar tudo para o Bitrix através do curl do sistema.

E um pouco mais de magia - uma chamada recebida:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // выставляем CallerID если узнали его у Битрикс24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // начинаем отсчет времени звонка
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

Aqui estamos interessados ​​apenas em uma linha.

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

Ela diz instalação de PBX ID do chamador (nome) variável CallMeCallerIDNome.

A própria variável CallMeCallerIDName, por sua vez, é definida pelo aplicativo CallMe (se Bitrix24 tiver um nome completo para o número do chamador, iremos defini-lo como ID do chamador (nome), não - não faremos nada).

Configuração do aplicativo

Arquivo de configurações do aplicativo - /var/www/pbx.vistep.ru/config.php

Descrição dos parâmetros da aplicação:

  • Ligue para mimDEBUG — se for 1, então todos os eventos processados ​​pela aplicação serão gravados no arquivo de log, 0 — não escrevemos nada
  • tecnologia SIP/PJSIP/IAX/etc
  • authToken — Token de autorização Bitrix24, código de autorização de webhook de saída
  • bitrixApiUrl — URL do webhook recebido, sem perfil/
  • extensões — lista de números externos
  • contexto — contexto para originação de chamadas
  • listener_timeout - velocidade de processamento de eventos do asterisco
  • asterisco — um array com configurações para conectar ao asterisco:
  • hospedeiro - ip ou nome do host do servidor asterisk
  • esquema — diagrama de conexão (tcp://, tls://)
  • porta - porto
  • nome de usuário - Nome de usuário
  • segredo - senha
  • connect_timeout - tempo limite de conexão
  • tempo de ler esgotado - tempo de ler esgotado

arquivo de configurações de exemplo:

 <?php
return array(

        'CallMeDEBUG' => 1, // дебаг сообщения в логе: 1 - пишем, 0 - не пишем
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //токен авторизации битрикса
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //url к api битрикса (входящий вебхук)
        'extentions' => array('888999'), // список внешних номеров, через запятую
        'context' => 'dial_out', //исходящий контекст для оригинации звонка
        'asterisk' => array( // настройки для подключения к астериску
                    'host' => '10.100.111.249',
                    'scheme' => 'tcp://',
                    'port' => 5038,
                    'username' => 'callme',
                    'secret' => 'JD3clEB8_f23r-3ry84gJ',
                    'connect_timeout' => 10000,
                    'read_timeout' => 10000
                ),
        'listener_timeout' => 300, //скорость обработки событий от asterisk

);

Configuração do supervisor

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

Arquivo de configurações a 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

Iniciando e reiniciando o aplicativo:

supervisorctl start callme
supervisorctl restart callme

veja o status do aplicativo:

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

Conclusão

Acabou sendo bastante difícil, mas tenho certeza que um administrador experiente será capaz de implementar e agradar seus usuários.

Como prometido, link para o github.

Dúvidas, sugestões - por favor nos comentários. Além disso, se você estiver interessado em saber como foi o desenvolvimento dessa integração, escreva, e no próximo artigo tentarei revelar tudo com mais detalhes.

Fonte: habr.com

Adicionar um comentário