Comprender FreePBX e integrándoo con Bitrix24 e moito máis

Bitrix 24 é unha gran combinación que combina CRM, fluxo de traballo, contabilidade e moitas outras cousas que lles gusta moito aos xestores e ao persoal de TI non lles gusta moito. O portal é usado por moitas pequenas e medianas empresas, incluíndo pequenas clínicas, fabricantes e mesmo salóns de beleza. A función principal que "encanta" aos xestores é a integración de telefonía e CRM, cando calquera chamada se rexistra inmediatamente en CRM, créanse tarxetas de cliente, cando entran, móstrase información sobre o cliente e pódese ver inmediatamente quen é, que é pode vender e canto debe. Pero a telefonía de Bitrix24 e a súa integración con CRM custa cartos, ás veces moito. No artigo vouvos contar a experiencia de integración con ferramentas abertas e a popular IP PBX PBX gratuíto, e tamén considerar a lóxica do traballo de varias partes

Traballo como subcontratista nunha empresa que vende e configura, integra telefonía IP. Cando me preguntaron se podíamos ofrecerlle algo a esta e a esta empresa para integrar Bitrix24 coas PBX que teñen os clientes, así como coas PBX virtuais de varias empresas de VDS, fun a Google. E por suposto deume unha ligazón artigo en habr, onde hai unha descrición, e github, e todo parece funcionar. Pero ao intentar usar esta solución, resultou que Bitrix24 xa non é o mesmo que antes e hai que refacer moito. Ademais, FreePBX non é un simple asterisco para ti, aquí tes que pensar en como combinar a facilidade de uso e un plan de marcación duro nos ficheiros de configuración.

Estudiamos a lóxica do traballo

Entón, para comezar, como debería funcionar todo. Cando se recibe unha chamada desde o exterior na PBX (evento SIP INVITE do provedor), comeza o procesamento do plan de marcación (plan de marcación, plan de marcación) - as regras de que e en que orde facer coa chamada. Desde o primeiro paquete, podes obter moita información, que despois podes usar nas regras. Unha excelente ferramenta para estudar os elementos internos de SIP é o analizador sngrep (Ligazón) que simplemente se instala en distribucións populares a través de apt install/yum install e similares, pero tamén se pode construír desde a fonte. Vexamos o rexistro de chamadas en sngrep

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

Nunha forma simplificada, o dialplan trata só do primeiro paquete, ás veces tamén durante a conversa transfírense chamadas, pulsacións de botóns (DTMF), varias cousas interesantes como FollowMe, RingGroup, IVR e outras.

Que hai dentro do paquete de invitacións

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

En realidade, a maioría dos plans de marcación sinxelos funcionan cos dous primeiros campos, e toda a lóxica xira en torno a DID e CallerID. DID - onde estamos a chamar, CallerID - quen está a chamar.

Pero despois de todo, temos unha empresa e non un teléfono, o que significa que o PBX probablemente teña grupos de chamadas (soa simultánea/consecutiva de varios dispositivos) en números da cidade (Grupo de chamada), IVR (Ola, chamou... Preme un para...), Contestadores automáticos (Frases), Condicións de tempo, Reenvío a outros números ou a unha cela (FollowMe, Forward). Isto significa que é moi difícil determinar sen ambigüidades quen recibirá realmente unha chamada e con quen manterá unha conversa cando chegue unha chamada. Aquí tes un exemplo do inicio dunha chamada típica na central dos nosos clientes

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

Despois de que a chamada entra correctamente na PBX, viaxa polo plan de marcación en diferentes "contextos". O contexto desde o punto de vista de Asterisk é un conxunto numerado de comandos, cada un dos cales contén un filtro polo número marcado (chámase exten, para unha chamada externa na fase inicial exten=DID). Os comandos da liña de dialplan poden ser calquera cousa: funcións internas (por exemplo, chamar a un abonado interno - Dial(), baixa o teléfono - Hangup()), operadores condicionais (IF, ELSE, ExecIF e similares), transicións a outras regras deste contexto (Goto, GotoIF), transición a outros contextos en forma de chamada de función (Gosub, Macro). Unha directiva separada include имя_контекста, que engade comandos doutro contexto ao final do contexto actual. Os comandos incluídos mediante include execútanse sempre despois comandos do contexto actual.

Toda a lóxica de FreePBX baséase na inclusión de diferentes contextos entre si a través de incluir e chamar a través dos controladores Gosub, Macro e Handler. Considere o contexto das chamadas entrantes de FreePBX

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

A chamada percorre todos os contextos de arriba abaixo á súa vez, en cada contexto pode haber chamadas a outros contextos como macros (Macro), funcións (Gosub) ou só transicións (Goto), polo que a árbore real do que se chama só pode ser rastrexado nos rexistros.

A continuación móstrase un diagrama de configuración típico para unha central PBX típica. Ao chamar, búscase DID nas rutas de entrada, compróbanse as condicións temporais para el, se todo está en orde, lánzase o menú de voz. Desde el, premendo o botón 1 ou tempo de espera, sae ao grupo de operadores de marcación. Despois de finalizar a chamada, chámase a macro de hangupcall, despois do cal non se pode facer nada no dialplan, agás os manejadores especiais (manexador de hangup).

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

Onde neste algoritmo de chamada debemos proporcionar información sobre o inicio da chamada a CRM, onde comezar a gravar, onde finalizar a gravación e enviala xunto coa información sobre a chamada a CRM?

Integración con sistemas externos

Que é a integración de PBX e CRM? Trátase de configuracións e programas que converten datos e eventos entre estas dúas plataformas e se envían entre si. A forma máis común dos sistemas independentes de comunicarse é a través das API, e a forma máis popular de acceder ás API é HTTP REST. Pero non por asterisco.

Dentro de Asterisk está:

  • AGI - chamada síncrona a programas/compoñentes externos, usado principalmente no plano de marcación, hai bibliotecas como phpagi, PAXI

  • AMI: un socket TCP de texto que funciona co principio de subscribirse a eventos e introducir comandos de texto, parécese a SMTP desde dentro, pode rastrexar eventos e xestionar chamadas, hai unha biblioteca PAMI - o máis popular para crear unha conexión con Asterisk

Exemplo de saída AMI

Evento: nova canle
Privilexio: chamar, todos
Canle: PJSIP/VMS_pjsip-0000078b
Estado da canle: 4
ChannelStateDesc: anel
Número de chamada: 111222
Nome do identificador de chamada: 111222
ConnectedLineNum:
nome da liña conectada:
Idioma: gl
código de conta:
Contexto: from-pstn
Extensión: s
Prioridade: 1
Identificación Única: 1599589046.5244
Linkedid: 1599589046.5244

  • ARI é unha mestura de ambos, todo a través de REST, WebSocket, en formato JSON, pero con bibliotecas e envoltorios novos, non moi bos, atopados de xeito desenfadado (phparia, phpari) que se converteron no seu desenvolvemento hai uns 3 anos.

Exemplo de saída ARI cando se inicia unha chamada

{ "variable":"CallMeCallerIDName", "value":"111222", "type":"ChannelVarset", "timestamp":"2020-09-09T09:38:36.269+0000", "channel":{ "id »:»1599644315.5334″, «nome»:»PJSIP/VMSpjsip-000007b6″, "state":"Soar", "chamante":{ "nome":"111222″, "número":"111222" }, "conectado":{ "nome":"", "número" :"" }, "código de conta":"", "dialplan":{ "context":"from-pstn", "exten":"s", "priority":2, "appname":"Estase", "appdata":"hello-world" }, "creationtime":"2020-09-09T09:38:35.926+0000", "language":"gl" }, "asterisco"id":"48:5b:aa:aa:aa:aa", "aplicación":"hola-mundo" }

A conveniencia ou inconveniente, a posibilidade ou a imposibilidade de traballar cunha API determinada están determinadas polas tarefas que hai que resolver. As tarefas para a integración con CRM son as seguintes:

  • Rastrexa o inicio da chamada, onde foi transferida, saca CallerID, DID, horas de inicio e finalización, quizais datos do directorio (para buscar unha conexión entre o teléfono e o usuario do CRM)

  • Inicia e finaliza a gravación da chamada, gárdaa no formato desexado, informa ao final da gravación onde se atopa o ficheiro

  • Inicie unha chamada nun evento externo (do programa), chame a un número interno, a un número externo e conécteos

  • Opcional: integración con CRM, grupos de marcación e FollowME para a transferencia automática de chamadas en ausencia de lugar (segundo CRM)

Todas estas tarefas pódense resolver a través de AMI ou ARI, pero ARI proporciona moita menos información, non hai moitos eventos, moitas variables que aínda ten AMI (por exemplo, chamadas de macro, configuración de variables dentro de macros, incluída a gravación de chamadas) non son rastrexas. Polo tanto, para un seguimento correcto e preciso, elixamos AMI por agora (pero non completamente). Ademais (ben, onde estaría sen isto, somos preguiceiros) - na obra orixinal (artigo en habr) use PAMI. *Entón cómpre tentar reescribir en ARI, pero non o feito de que funcione.

Reinventando a integración

Para que a nosa FreePBX poida informar a AMI de xeito sinxelo sobre o inicio da chamada, a hora de finalización, os números, os nomes dos ficheiros gravados, o máis sinxelo é calcular a duración da chamada usando o mesmo truco que os autores orixinais. - introduza as súas variables e analice a saída para determinar a súa presenza. PAMI suxire facelo simplemente a través dunha función de filtro.

Aquí tes un exemplo de configuración da túa propia variable para a hora de inicio da chamada (s é un número especial no plan de marcación que se realiza ANTES de iniciar a busca DID)

[ext-did-custom]

exten => s,1,Set(CallStart=${STRFTIME(epoch,,%s)})

Un exemplo de evento AMI para esta liña

Evento: nova canle

Privilexio: chamar, todos

Canle: PJSIP/VMS_pjsip-0000078b

Estado da canle: 4

ChannelStateDesc: anel

Número de chamada: 111222

Nome do identificador de chamada: 111222

ConnectedLineNum:

nome da liña conectada:

Idioma: gl

código de conta:

Contexto: from-pstn

Extensión: s

Prioridade: 1

Identificación Única: 1599589046.5244

Linkedid: 1599589046.5244

Aplicación: Establecer AppData:

CallStart=1599571046

Porque FreePBX sobrescribe os ficheiros extention.conf e extention_adicional.conf, utilizaremos o ficheiro extensión_personalizado.conf

Código completo de extension_custom.conf

[globals]	
;; Проверьте пути и права на папки - юзер asterisk должен иметь права на запись
;; Сюда будет писаться разговоры
WAV=/var/www/html/callme/records/wav 
MP3=/var/www/html/callme/records/mp3

;; По этим путям будет воспроизводится и скачиваться запись
URLRECORDS=https://www.host.ru/callmeplus/records/mp3

;; Адрес для калбека при исходящем вызове
URLPHP=https://www.host.ru/callmeplus

;; Да пишем разговоры
RECORDING=1

;; Это макрос для записи разговоров в нашу папку. 
;; Можно использовать и системную запись, но пока пусть будет эта - 
;; она работает
[recording]
exten => ~~s~~,1,Set(LOCAL(calling)=${ARG1})
exten => ~~s~~,2,Set(LOCAL(called)=${ARG2})
exten => ~~s~~,3,GotoIf($["${RECORDING}" = "1"]?4:14)
exten => ~~s~~,4,Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called})
exten => ~~s~~,5,Set(datedir=${STRFTIME(${EPOCH},,%Y/%m/%d)})
exten => ~~s~~,6,System(mkdir -p ${MP3}/${datedir})
exten => ~~s~~,7,System(mkdir -p ${WAV}/${datedir})
exten => ~~s~~,8,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")
exten => ~~s~~,9,Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3)
exten => ~~s~~,10,Set(CDR(filename)=${fname}.mp3)
exten => ~~s~~,11,Set(CDR(recordingfile)=${fname}.wav)
exten => ~~s~~,12,Set(CDR(realdst)=${called})
exten => ~~s~~,13,MixMonitor(${WAV}/${datedir}/${fname}.wav,b,${monopt})
exten => ~~s~~,14,NoOp(Finish if_recording_1)
exten => ~~s~~,15,Return()


;; Это основной контекст для начала разговора
[ext-did-custom]

;; Это хулиганство, делать это так и здесь, но работает - добавляем к номеру '8'
exten =>  s,1,Set(CALLERID(num)=8${CALLERID(num)})

;; Тут всякие переменные для скрипта
exten =>  s,n,Gosub(recording,~~s~~,1(${CALLERID(number)},${EXTEN}))
exten =>  s,n,ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp())
exten =>  s,n,Set(CallStart=${STRFTIME(epoch,,%s)})
exten =>  s,n,Set(CallMeDISPOSITION=${CDR(disposition)})

;; Самое главное! Обработчик окончания разговора. 
;; Обычные пути обработки конца через (exten=>h,1,чтототут) в FreePBX не работают - Macro(hangupcall,) все портит. 
;; Поэтому вешаем Hangup_Handler на окончание звонка
exten => s,n,Set(CHANNEL(hangup_handler_push)=sub-call-from-cid-ended,s,1(${CALLERID(num)},${EXTEN}))

;; Обработчик окончания входящего вызова
[sub-call-from-cid-ended]

;; Сообщаем о значениях при конце звонка
exten => s,1,Set(CDR_PROP(disable)=true)
exten => s,n,Set(CallStop=${STRFTIME(epoch,,%s)})
exten => s,n,Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)})

;; Статус вызова - Ответ, не ответ...
exten => s,n,Set(CallMeDISPOSITION=${CDR(disposition)})
exten => s,n,Return


;; Обработчик исходящих вызовов - все аналогичено
[outbound-allroutes-custom]

;; Запись
exten => _.,1,Gosub(recording,~~s~~,1(${CALLERID(number)},${EXTEN}))
;; Переменные
exten => _.,n,Set(__CallIntNum=${CALLERID(num)})
exten => _.,n,Set(CallExtNum=${EXTEN})
exten => _.,n,Set(CallStart=${STRFTIME(epoch,,%s)})
exten => _.,n,Set(CallmeCALLID=${SIPCALLID})

;; Вешаем Hangup_Handler на окончание звонка
exten => _.,n,Set(CHANNEL(hangup_handler_push)=sub-call-internal-ended,s,1(${CALLERID(num)},${EXTEN}))

;; Обработчик окончания исходящего вызова
[sub-call-internal-ended]

;; переменные
exten => s,1,Set(CDR_PROP(disable)=true)
exten => s,n,Set(CallStop=${STRFTIME(epoch,,%s)})
exten => s,n,Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)})
exten => s,n,Set(CallMeDISPOSITION=${CDR(disposition)})

;; Вызов скрипта, который сообщит о звонке в CRM - это исходящий, 
;; так что по факту окончания
exten => s,n,System(curl -s ${URLPHP}/CallMeOut.php --data action=sendcall2b24 --data ExtNum=${CallExtNum} --data call_id=${SIPCALLID} --data-urlencode FullFname='${FullFname}' --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition='${CallMeDISPOSITION}')
exten => s,n,Return

Característica e diferenza do plano de marcación orixinal dos autores do artigo orixinal -

  • Dialplan en formato .conf, como quere FreePBX (si, pode .ael, pero non todas as versións e non sempre é conveniente)

  • En lugar de procesar o final a través de exten => h, o procesamento foi introducido a través de hangup_handler, porque o plan de marcación FreePBX só funcionaba con el.

  • Corrixiuse a cadea de chamadas de guión, as comiñas engadidas e o número de chamada externo ExtNum

  • O procesamento móvese a contextos _personalizados e permítelle non tocar nin editar as configuracións de FreePBX - entrante a través de [ext-did-personalizado], saída por [saída-allroutes-personalizado]

  • Sen vinculación a números: o ficheiro é universal e só precisa ser configurado para a ruta e a ligazón ao servidor

Para comezar, tamén debes executar scripts en AMI mediante o inicio de sesión e o contrasinal; para iso, FreePBX tamén ten un ficheiro _personalizado

ficheiro manager_custom.conf

;;  это логин
[callmeplus]
;; это пароль
secret = trampampamturlala
deny = 0.0.0.0/0.0.0.0

;; я работаю с локальной машиной - но если надо, можно и другие прописать
permit = 127.0.0.1/255.255.255.255
read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
write = system,call,agent,log,verbose,user,config,command,reporting,originate

Estes dous ficheiros deben colocarse en /etc/asterisk, despois volver a ler as configuracións (ou reiniciar o asterisco)

# astrisk -rv
  Connected to Asterisk 16.6.2 currently running on freepbx (pid = 31629)
#freepbx*CLI> dialplan reload
     Dialplan reloaded.
#freepbx*CLI> exit

Agora imos pasar a PHP

Inicialización de scripts e creación dun servizo

Dado que o esquema para traballar con Bitrix 24, un servizo para AMI, non é totalmente sinxelo e transparente, hai que discutilo por separado. Asterisk, cando se activa AMI, simplemente abre o porto e xa está. Cando un cliente se une, solicita autorización, entón o cliente subscríbese aos eventos necesarios. Os eventos veñen en texto plano, que PAMI converte en obxectos estruturados e ofrece a posibilidade de establecer a función de filtrado só para eventos de interese, campos, números, etc.

Tan pronto como chega a chamada, o evento NewExten desenvólvese a partir do contexto pai [from-pstn], entón todos os eventos van na orde das liñas nos contextos. Cando se recibe información das variables CallMeCallerIDName e CallStart especificadas no _plan de marcado personalizado, o

  1. A función de solicitar o UserID correspondente ao número de extensión onde chegou a chamada. E se é un grupo de acceso telefónico? A pregunta é política, é preciso crear unha chamada a todos á vez (cando todos chaman á vez) ou crear como chaman cando chaman á súa vez? A maioría dos clientes teñen a estratexia Fisrt Dispoñible, polo que non hai ningún problema con isto, só un chama. Pero o tema hai que abordalo

  2. A función de rexistro de chamadas en Bitrix24, que devolve o CallID, que despois é necesario para informar dos parámetros da chamada e unha ligazón á gravación. Require número de extensión ou UserID

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

Despois do final da chamada, chámase a función de descarga do rexistro, que informa ao mesmo tempo do estado da finalización da chamada (Ocupado, Sen resposta, Éxito) e tamén descarga unha ligazón ao ficheiro mp3 co rexistro (se o hai).

Dado que o módulo CallMeIn.php debe executarse continuamente, creouse un ficheiro de inicio SystemD para el chame.servizo, que se debe poñer en /etc/systemd/system/callme.service

[Unit]
Description=CallMe

[Service]
WorkingDirectory=/var/www/html/callmeplus
ExecStart=/usr/bin/php /var/www/html/callmeplus/CallMeIn.php 2>&1 >>/var/log/callmeplus.log
ExecStop=/bin/kill -WINCH ${MAINPID}
KillSignal=SIGKILL

Restart=on-failure
RestartSec=10s

#тут надо смотреть,какие права на папки
#User=www-data  #Ubuntu - debian
#User=nginx #Centos

[Install]
WantedBy=multi-user.target

a inicialización e o lanzamento do script prodúcese a través do systemctl ou do servizo

# systemctl enable callme
# systemctl start callme

O servizo reiniciarase segundo sexa necesario (en caso de fallos). O servizo de seguimento da caixa de entrada non require que se instale un servidor web, só se necesita php (que definitivamente está no servidor FeePBX). Pero a falta de acceso aos rexistros de chamadas a través do servidor web (tamén con https), non será posible escoitar os rexistros de chamadas.

Agora imos falar das chamadas saíntes. O script CallMeOut.php ten dúas funcións:

  • Iniciación dunha chamada cando se recibe unha solicitude para un script php (incluído o uso do botón "Call" no propio Bitrix). Non funciona sen un servidor web, a solicitude recíbese a través de HTTP POST, a solicitude contén un token

  • Mensaxe sobre a chamada, os seus parámetros e rexistros en Bitrix. Despedido por Asterisk no plan de marcación [subchamada-internal-terminada] cando finaliza unha chamada

Comprender FreePBX e integrándoo con Bitrix24 e moito máis

O servidor web só é necesario para dúas cousas: descargar ficheiros de rexistro de Bitrix (a través de HTTPS) e chamar ao script CallMeOut.php. Podes usar o servidor FreePBX integrado, cuxos ficheiros son /var/www/html, podes instalar outro servidor ou especificar un camiño diferente.

Servidor web

Deixemos a configuración do servidor web para o estudo independente (titos, titos, titos). Se non tes un dominio, podes probar FreeDomain( https://www.freenom.com/ru/index.html), que che dará un nome gratuíto para a túa IP branca (non esquezas reenviar os portos 80, 443 a través do router se o enderezo externo só está nel). Se acabas de crear un dominio DNS, terás que esperar (de 15 minutos a 48 horas) ata que se carguen todos os servidores. Segundo a experiencia de traballar con provedores domésticos - de 1 hora a un día.

Automatización de instalacións

Desenvolveuse un instalador en github para que a instalación sexa aínda máis sinxela. Pero foi suave no papel, mentres o estamos instalando todo manualmente, xa que despois de retocar todo isto quedou claro que é o que é amigo de quen, quen vai a onde e como depuralo. Aínda non hai instalador

Estivador

Se queres probar rapidamente a solución - hai unha opción con Docker - crea rapidamente un contedor, dálle portos fóra, desliza os ficheiros de configuración e proba (esta é a opción co contedor LetsEncrypt, se xa tes un certificado, só precisa redirixir o proxy inverso ao servidor web FreePBX (demoslle outro porto 88), LetsEncrypt no docker baseado en Este artigo

Debe executar o ficheiro no cartafol do proxecto descargado (despois do clon de git), pero primeiro entrar na configuración do asterisco (cartafol do asterisco) e escribir alí os camiños dos rexistros e o URL do seu sitio.

version: '3.3'
services:
  nginx:
    image: nginx:1.15-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/ssl_docker.conf:/etc/nginx/conf.d/ssl_docker.conf
  certbot:
    image: certbot/certbot
  freepbx:
    image: flaviostutz/freepbx
    ports:
      - 88:80 # для настройки
      - 5060:5060/udp
      - 5160:5160/udp
      - 127.0.0.1:5038:5038 # для CallMeOut.php
#      - 3306:3306
      - 18000-18100:18000-18100/udp
    restart: always
    environment:
      - ADMIN_PASSWORD=admin123
    volumes:
      - backup:/backup
      - recordings:/var/spool/asterisk/monitor
      - ./callme:/var/www/html/callme
      - ./systemd/callme.service:/etc/systemd/system/callme.conf
      - ./asterisk/manager_custom.conf:/etc/asterisk/manager_custom.conf
      - ./asterisk/extensions_custom.conf:/etc/asterisk/extensions_custom.conf
#      - ./conf/startup.sh:/startup.sh

volumes:
  backup:
  recordings:

Este ficheiro docker-compose.yaml execútase mediante

docker-compose up -d

Se nginx non se inicia, algo está mal coa configuración no cartafol nginx/ssl_docker.conf

Outras integracións

E por que non poñer algún CRM nos scripts ao mesmo tempo, pensamos. Estudamos varias outras API de CRM, especialmente a PBX integrada gratuíta: ShugarCRM e Vtiger, e si! si, o principio é o mesmo. Pero esta é outra historia, que máis tarde subiremos ao github por separado.

referencias

Descargo de responsabilidade: calquera semellanza coa realidade é ficticia e non fun eu.

Fonte: www.habr.com

Engadir un comentario