Kami menangani FreePBX dan mengintegrasikannya dengan Bitrix24 dan tidak hanya

Bitrix24 adalah pemanen besar yang menggabungkan CRM, aliran dokumen, akuntansi, dan banyak hal lain yang sangat disukai manajer dan staf TI tidak terlalu menyukainya. Portal ini digunakan oleh banyak perusahaan kecil dan menengah, termasuk klinik kecil, pekerja manufaktur, dan bahkan salon kecantikan. Fungsi utama yang "disukai" oleh manajer adalah integrasi telepon dan CRM, ketika panggilan apa pun segera direkam di CRM, kartu pelanggan dibuat, informasi tentang pelanggan ditampilkan saat masuk, dan Anda dapat segera melihat siapa dia, apa yang dapat dia jual dan berapa banyak hutangnya. Tetapi telepon dari Bitrix24 dan integrasinya dengan CRM membutuhkan biaya, terkadang banyak. Dalam artikel ini saya akan memberi tahu Anda pengalaman integrasi dengan alat terbuka dan IP PBX FreePBX yang populer , dan juga mempertimbangkan logika pekerjaan berbagai bagian

Saya bekerja sebagai perusahaan outsourcing di sebuah perusahaan yang menjual dan mengkonfigurasi, mengintegrasikan telepon IP. Ketika saya ditanya apakah kami dapat menawarkan ini dan perusahaan ini sesuatu untuk mengintegrasikan Bitrix24 dengan PBX yang dimiliki pelanggan, serta dengan PBX virtual di berbagai perusahaan VDS, saya pergi ke Google. Dan, tentu saja, dia memberi saya tautan ke artikel di Habr , di mana ada deskripsi, dan github, dan semuanya tampak berfungsi. Tetapi ketika mencoba menggunakan solusi ini, ternyata Bitrix24 tidak seperti dulu lagi, dan banyak yang perlu diulang. Selain itu, FreePBX bukanlah tanda bintang telanjang untuk Anda, di sini Anda perlu memikirkan tentang cara menggabungkan kegunaan dan dialplan hardcore dalam file konfigurasi.

Kami mempelajari logika kerja

Jadi pertama, bagaimana cara kerjanya. Ketika panggilan datang dari luar PBX (acara SIP INVITE dari penyedia), pemrosesan dialplan (dialplan) dimulai - aturan tentang apa yang harus dilakukan dengan panggilan tersebut dan dalam urutan apa. Banyak informasi dapat diperoleh dari paket pertama, yang kemudian dapat digunakan dalam aturan. Alat yang sangat baik untuk mempelajari bagian dalam SIP adalah sngrep analyzer ( tautan ), yang hanya dipasang di distribusi populer melalui apt install / yum install dan sejenisnya, tetapi Anda juga dapat membangunnya dari sumber. Mari kita lihat log panggilan di sngrep

Dalam bentuk yang disederhanakan, dialplan hanya berurusan dengan paket pertama, terkadang selama percakapan, panggilan ditransfer, tombol ditekan (DTMF), berbagai hal menarik seperti FollowMe, RingGroup, IVR dan lainnya.

Apa yang ada di dalam paket Undang

DID CallerID. DID - , CallerID - .

- (/ ) (Ring Group), IVR (, ... ...), (Phrases), (Time Conditions), (FollowMe, Forward). , .

"". Asterisk - , ( exten, exten=DID). - ( - Dial(), - Hangup()), (IF, ELSE, ExecIF ), (Goto, GotoIF), (Gosub, Macro). include _, . , include .

FreePBX include Gosub, Macro Handler. FreePBX

, (Macro), (Gosub) (Goto), , .

. DID, , - . 1 . hangupcall, , (hangup handler).

CRM, , CRM?

CRM? , . API, API HTTP REST. asterisk.

Asterisk :

AMI

Event: Newchannel Privilege: call,all Channel: PJSIP/VMS_pjsip-0000078b ChannelState: 4 ChannelStateDesc: Ring CallerIDNum: 111222 CallerIDName: 111222 ConnectedLineNum: ConnectedLineName: Language: en AccountCode: Context: from-pstn Exten: s Priority: 1 Uniqueid: 1599589046.5244 Linkedid: 1599589046.5244

ARI

{ "variable":"CallMeCallerIDName", "value":"111222", "type":"ChannelVarset", "timestamp":"2020-09-09T09:38:36.269+0000", "channel":{ "id":"1599644315.5334", "name":"PJSIP/VMSpjsip-000007b6", "state":"Ring", "caller":{ "name":"111222", "number":"111222" }, "connected":{ "name":"", "number":"" }, "accountcode":"", "dialplan":{ "context":"from-pstn", "exten":"s", "priority":2, "appname":"Stasis", "appdata":"hello-world" }, "creationtime":"2020-09-09T09:38:35.926+0000", "language":"ru" }, "asteriskid":"48:5b:aa:aa:aa:aa", "application":"hello-world" }

, API , . CRM :

  • , , CallerID, DID, , ( CRM)

  • , ,

  • ( ), ,

  • : CRM, FollowME ( CRM)

AMI ARI, ARI , , , AMI ( , , ). , - AMI ( ). ( , ) - ( ) PAMI. * ARI, .

, FreePBX AMI , , , , , - . PAMI -.

(s - , DID)

[ext-did-custom]

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

Event: Newchannel

Privilege: call,all

Channel: PJSIP/VMS_pjsip-0000078b

ChannelState: 4

ChannelStateDesc: Ring

CallerIDNum: 111222

CallerIDName: 111222

ConnectedLineNum:

ConnectedLineName:

Language: en

AccountCode:

Context: from-pstn

Exten: s

Priority: 1

Uniqueid: 1599589046.5244

Linkedid: 1599589046.5244

Application: Set AppData:

CallStart=1599571046

FreePBX extention.conf extention_additional.conf, extention_custom.conf

extention_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

-

  • .conf, FreePBX ( .ael, )

  • exten=>h hangup_handler, FreePBX

  • , ExtNum

  • _custom FreePBX - [ext-did-custom], [outbound-allroutes-custom]

  • -

AMI - FreePBX _custom

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

/etc/asterisk, ( )

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

PHP

24, AMI , . AMI . , . , PAMI , , ..

, NewExten [from-pstn], . _custom CallMeCallerIDName CallStart

  1. UserID, , . ? , ( ) ? Fisrt Available, , .

  2. 24, CallID, . UserID

, (, , ), mp3 ( ).

CallMeIn.php , SystemD callme.service, /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

systemctl service

# systemctl enable callme
# systemctl start callme

( ). , php ( FeePBX). ( https) .

. CallMeOut.php :

  • php ( "" ). , HTTP POST,

  • , . Asterisk [sub-call-internal-ended]

- ( HTTPS) CallMeOut.php. FreePBX, /var/www/html, .

(, , ). , FreeDomain( https://www.freenom.com/ru/index.html), IP ( 80, 443 , ). DNS , ( 15 48 ) . - 1 .

github , . - , , , . (

Docker

- Docker - , , ( LetsEncrypt , , FreePBX ( - 88), LetsEncrypt

( git clone), ( asterisk) URL

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:

docker-compose.yaml,

docker-compose up -d

nginx , nginx/ssl_docker.conf

CRM , . API CRM, - ShugarCRM Vtiger, ! , . , .

: ,




All Articles