
En la red hay distintas opciones para integrar la IP-PBX Asterisk y el CRM Bitrix24, pero decidimos crear la nuestra.
La funcionalidad es estándar:
- Al hacer clic en el enlace con el número de teléfono del cliente en Bitrix24, Asterisk conecta el número interno del usuario que hizo clic con el número de teléfono del cliente. En Bitrix24 se registra la llamada y, al finalizar, se añade el registro de la conversación.
- Asterisk recibe una llamada externa — en la interfaz de Bitrix24, mostramos la tarjeta del cliente al empleado al que llegó la llamada.
Si no hay tal cliente, abrimos la tarjeta para crear un nuevo lead.
Una vez finalizada la llamada, reflejamos esto en la tarjeta y añadimos el registro de la conversación.
A continuación, explicaré cómo configurarlo en tu propio sistema y proporcionaré un enlace a github — ¡sí, sí, tómalo y úsalo!
Descripción general
Hemos llamado a nuestra integración CallMe. CallMe es una pequeña aplicación web escrita en PHP.
Tecnologías y servicios utilizados
- PHP 5.6
- Composer
- Nginx + php-fpm
- supervisor
- AMI (Interfaz de Gestión de Asterisk)
- Webhooks de Bitrix (implementación simplificada de REST API)
Configuración preliminar
En el servidor con Asterisk, es necesario instalar el servidor web (nosotros usamos nginx+php-fpm), supervisor y git.
Comando para instalar (CentOS):
yum install nginx php-fpm supervisor gitCambiamos al directorio accesible para el servidor web, clonamos la aplicación desde git y establecemos los permisos necesarios en la carpeta:
cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/
A continuación, configuramos nginx, nuestro archivo de configuración se encuentra en
/etc/nginx/conf.d/pbx.vistep.ru.confserver {
server_name www.pbx.vistep.es pbx.vistep.es;
listen *:80;
rewrite ^ https://pbx.vistep.es$request_uri? permanent;
}
server {
# listen *:80;
# server_name pbx.vistep.es;
access_log /var/log/nginx/pbx.vistep.es.access.log main;
error_log /var/log/nginx/pbx.vistep.es.error.log;
listen 443 ssl http2;
server_name pbx.vistep.es;
resolver 8.8.8.8;
ssl_stapling on;
ssl on;
ssl_certificate /etc/letsencrypt/live/pbx.vistep.es/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.es/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; # prohibido para archivos ocultos
}
location ~* \/(?:uploads|files)\/.*.php$ {
deny all; # prohibido para scripts subidos
}
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 de archivos 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;
}
}
Dejaré fuera de este artículo el análisis de la configuración, las cuestiones de seguridad, la obtención del certificado e incluso la elección del servidor web: hay mucho escrito al respecto. La aplicación no tiene limitaciones, funciona tanto por http como por https.
Estamos usando https, certificado de lets encrypt.
Si lo hiciste todo correctamente, al hacer clic en el enlace deberías ver algo similar

Configuración de Bitrix24
Crearemos dos webhooks.
Webhook de entrada.
Bajo la cuenta de administrador (con id 1) vamos a: Aplicaciones -> Webhooks -> Añadir webhook -> Webhook de entrada

Rellenamos los parámetros del webhook de entrada como en las capturas de pantalla:


Y hacemos clic en guardar.
Después de guardar, Bitrix24 te proporcionará la URL del webhook de entrada, por ejemplo:

Guarda tu versión de la URL sin la barra diagonal final /profile/ — se utilizará en la aplicación para trabajar con llamadas entrantes.
Para mí esto es https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/
Webhook de salida.
Aplicaciones -> Webhooks -> Añadir webhook -> Webhook de salida
Los detalles nuevamente en las capturas de pantalla:


Guardamos y obtenemos el código de autorización

Para mí esto es xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. También debes copiarlo, será necesario para realizar llamadas salientes.
¡Importante!
En el servidor de Bitrix24 debe estar configurado un certificado ssl (se puede usar letsencrypt), de lo contrario, el api de Bitrix no funcionará. Si tiene la versión en la nube, no tiene de qué preocuparse, ya que ahí ya hay ssl.
¡Importante!
¡En el campo «Dirección del controlador» debe especificarse una dirección accesible desde Internet!
Y como último toque, instalaremos nuestro CallMeOut como aplicación para realizar llamadas (para que al hacer clic en el número en el PBX se envíe un comando para la originación de la llamada).
En el menú seleccionamos: Más -> Telefonía -> Más -> Configuraciones, establecemos en «Número para llamada saliente por defecto» la aplicación: CallMeOut y hacemos clic en «Guardar»

Configuración de asterisk
Para una interacción exitosa entre Asterisk y Bitrix24 necesitamos agregar al usuario AMI callme en 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 continuación, hay algunos trucos que necesitaremos implementar a través del dialplan (en nuestro caso es extensions.ael).
Presento todo el archivo, y luego daré explicaciones:
globals {
WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/Carpeta temporal para WAV
MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/Dónde descargar archivos mp3
URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
RECORDING=1; \/\/ Grabación, 1 - habilitada.
};
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()); \/\/ Establecemos CallerID si lo sabemos a través de 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 ya estaba configurado ===));
}
}
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});
}
};
Comencemos desde el principio: la directiva globals.
Variable URLRECORDS almacena la URL de los archivos de grabaciones de llamadas, desde donde Bitrix24 los cargará en la ficha de contacto.
A continuación, nos interesa el macro recording.
Aquí, además de grabar las llamadas, estableceremos la variable FullFname.
Set(FullFname=${URLRECORDS}\/${datedir}\/${fname}.mp3);Almacena la URL completa a un archivo específico (el macro se invoca en todas partes).
Analizaremos la llamada saliente:
_. => {
&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});
}
Supongamos que estamos llamando al 89991234567, primero aterrizamos aquí:
&recording(${CALLERID(number)},${EXTEN});es decir, se invoca el macro de grabación de la llamada y se configuran las variables necesarias.
Siguiente
Set(__CallIntNum=${CALLERID(num)})
Set(CallStart=${STRFTIME(epoch,,%s)});
registramos quién inició la llamada y fijamos el tiempo de inicio de la misma.
Y al finalizar, en un 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});
}
desactivamos el registro en la tabla CDR para esta extensión (no es necesario allí), marcamos el tiempo de finalización de la llamada, calculamos la duración, si el resultado de la llamada es desconocido — establecemos (variable CallMeDISPOSITION) y, como último paso, enviamos todo a Bitrix a través de curl del sistema.
Y un poco de magia más — llamada entrante:
888999 => {
&recording(${CALLERID(number)},${EXTEN});
Answer();
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // establecemos CallerID si lo conocemos de Bitrix24
Set(CallStart=${STRFTIME(epoch,,%s)}); // comenzamos el conteo del tiempo de la llamada
Queue(Q1,tT);
Set(CallMeDISPOSITION=${CDR(disposition)});
Hangup();
}
Aquí solo nos interesa una línea.
ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());Esto indica a la centralita que establezca CallerID(name) igual a la variable CallMeCallerIDName.
La variable CallMeCallerIDName, por su parte, se establece por la aplicación CallMe (si en Bitrix24 hay nombre completo para el número que llama — se establece como CallerID(name), si no — no haremos nada).
Configuración de la aplicación
Archivo de configuración de la aplicación — /var/www/pbx.vistep.ru/config.php
Descripción de los parámetros de la aplicación:
- CallMeDEBUG — si es 1, todos los eventos procesados por la aplicación se escribirán en el archivo de registro, 0 — no escribimos nada
- tech — SIP/PJSIP/IAX/etc.
- authToken — token de autorización Bitrix24, código de autorización del webhook saliente
- bitrixApiUrl — URL del webhook entrante, sin profile/
- extentions — lista de números externos
- contexto — contexto para la originación de la llamada
- listener_timeout — velocidad de procesamiento de eventos de Asterisk
- asterisk — matriz con la configuración de conexión a Asterisk:
- host — ip o nombre de host del servidor Asterisk
- scheme — esquema de conexión (tcp://, tls://)
- port — puerto
- username — nombre de usuario
- secret — contraseña
- connect_timeout — tiempo de espera de conexión
- read_timeout — tiempo de espera de lectura
ejemplo de archivo de configuración:
1, // depurar mensajes en el registro: 1 - escribir, 0 - no escribir
'tech' => 'SIP',
'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', // token de autorización de Bitrix
'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', // url a la api de Bitrix (webhook entrante)
'extentions' => array('888999'), // lista de números externos, separados por comas
'context' => 'dial_out', // contexto saliente para la originación de la llamada
'asterisk' => array( // configuración para conexión a 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, // velocidad de procesamiento de eventos de Asterisk
);Configuración de supervisor
Supervisor se utiliza para ejecutar el proceso de manejador de eventos Asterisk CallMeIn.php, que monitorea llamadas entrantes e interactúa con Bitrix24 (mostrar tarjeta, ocultar tarjeta, etc.).
Archivo de configuración que debe crearse:
/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.logInicio y reinicio de la aplicación:
supervisorctl start callme
supervisorctl restart callmever el estado de la aplicación:
supervisorctl status callme
callme RUNNING pid 11729, uptime 17 days, 16:58:07Conclusión
Resultó ser bastante complicado, pero estoy seguro de que un administrador experimentado podrá implementarlo y complacer a sus usuarios.
Como prometí, .
Preguntas, sugerencias - los invito a comentar. También si están interesados en cómo fue el desarrollo de esta integración, háganmelo saber, y en el próximo artículo intentaré detallar todo más.
Fuente: habr.com
