User Tools

Site Tools


сервис_asterisk

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
сервис_asterisk [2022/04/07 10:56]
val [Просмотр текущих звонков]
сервис_asterisk [2024/12/06 13:36] (current)
val [Аутентификация и учет звонков в RADIUS]
Line 8: Line 8:
 ===== Установка ===== ===== Установка =====
  
 +  * [[https://​community.asterisk.org/​t/​install-asterisk-via-apt-or-from-source/​99713|Install Asterisk via apt or from source?]]
 ==== Debian/​Ubuntu ==== ==== Debian/​Ubuntu ====
 <​code>​ <​code>​
Line 38: Line 39:
 </​code><​code>​ </​code><​code>​
 [general] [general]
-;​udpbindaddr=0.0.0.0:​5061+;​udpbindaddr=0.0.0.0:​6050
 transport=udp transport=udp
 disallow=all disallow=all
Line 45: Line 46:
 directmedia=no ​          ; for webinar directmedia=no ​          ; for webinar
 nat=force_rport,​comedia ​ ; for webinar nat=force_rport,​comedia ​ ; for webinar
 +qualify=yes ​             ; for webinar
  
 ;​context=default ;​context=default
Line 72: Line 74:
 ;​disallow=all ;​disallow=all
 ;allow=gsm ;allow=gsm
-;​canreinvite=no ;1.4 
-;​directmedia=no ;1.6 
-;;;nat=yes 
-;​nat=force_rport,​comedia 
-;​qualify=yes 
 ;​call-limit=1 ;​call-limit=1
 ;​deny=0.0.0.0/​0.0.0.0 ;​deny=0.0.0.0/​0.0.0.0
 ;​permit=172.16.1.0/​255.255.255.0 ;​permit=172.16.1.0/​255.255.255.0
 +;​directmedia=no
 +;​nat=force_rport,​comedia
 +;​qualify=yes
  
 ;[user2] ;[user2]
Line 93: Line 93:
 ==== Использование шаблонов в именах CHAN_SIP каналов ==== ==== Использование шаблонов в именах CHAN_SIP каналов ====
 <​code>​ <​code>​
-root@server# cat /​etc/​asterisk/​sip.conf+server# cat /​etc/​asterisk/​sip.conf
 </​code><​code>​ </​code><​code>​
 ... ...
-;[office](!) +[office](!) 
-;type=friend +type=friend 
-;host=dynamic +host=dynamic 
-;deny=0.0.0.0/​0.0.0.0 +deny=0.0.0.0/​0.0.0.0 
-;permit=192.168.X.0/​255.255.255.0+permit=192.168.X.0/​255.255.255.0 
 + 
 +[internet](!) 
 +type=friend 
 +host=dynamic 
 +permit=0.0.0.0/​0.0.0.0 
 +nat=force_rport,​comedia 
 +qualify=yes 
 +directmedia=no 
 +;​call-limit=1 
 + 
 +[401](office) 
 +secret=tpassword401 
 + 
 +[402](internet) 
 +secret=tpassword402
  
-;[403](office) +[403](office) 
-;secret=tpassword403+secret=tpassword403
  
-;[404](office) +[404](office) 
-;secret=tpassword404+secret=tpassword404
 ... ...
 </​code>​ </​code>​
Line 224: Line 239:
 </​code><​code>​ </​code><​code>​
 ... ...
-; voip1.un и server.corp.un одна и та же система+; voip1.un и server.corp.un ​(курс CGP) одна и та же система
 ; приходится подключаться к ней с разных портов :) ; приходится подключаться к ней с разных портов :)
  
Line 231: Line 246:
 protocol=udp protocol=udp
 bind=0.0.0.0:​5062 bind=0.0.0.0:​5062
 +;​local_net=192.168.1.0/​255.255.255.0
 ;​local_net=192.168.X.0/​255.255.255.0 ;​local_net=192.168.X.0/​255.255.255.0
 ;​external_media_address=172.16.1.X ;​external_media_address=172.16.1.X
Line 343: Line 359:
 </​code><​code>​ </​code><​code>​
 [general] [general]
 +...
 +disallow=all
 +allow=alaw
 ... ...
 allow=h263 allow=h263
Line 352: Line 371:
  
 ==== Отладка работы Asterisk ==== ==== Отладка работы Asterisk ====
 +
 +  * [[https://​community.asterisk.org/​t/​help-new-installation-full-of-errors/​46614|HELP - New Installation Full of Errors]]
  
 === Сервисные сообщения === === Сервисные сообщения ===
Line 656: Line 677:
 server*CLI>​ channel request hangup SIP/<​TAB>​ server*CLI>​ channel request hangup SIP/<​TAB>​
  
-# watch "​asterisk -x 'cdr show active'"​+# watch -d "​asterisk -x 'cdr show active'"​
  
 # curl -v -X GET "​http://​localhost:​8088/​ari/​channels?​api_key=asterisk:​asterisk"​ # curl -v -X GET "​http://​localhost:​8088/​ari/​channels?​api_key=asterisk:​asterisk"​
Line 823: Line 844:
 <​code>​ <​code>​
 http://​172.16.1.X/​asterisk-cdr-viewer/​ http://​172.16.1.X/​asterisk-cdr-viewer/​
 +</​code>​
 +
 +  * Спасибо Комлеву Александру Павловичу! ​
 +
 +<​code>​
 +Чтобы запись разговора воспроизводилась прямо на странице CDR Viewer, нужно в файле ​
 +/​var/​www/​html/​asterisk-cdr-viewer/​include/​functions.inc.php
 +заменить ​ строку:​
 +
 +echo " ​   <td class=\"​record_col\"><​a href=\"​download.php?​audio=$recorded_file.$system_audio_format\"​ title=\"​Listen to call recording\"><​img src=\"​templates/​images/​sound.png\"​ alt=\"​Call recording\"​ /></​a></​td>​\n";​
 +
 +на такую:
 +
 +echo " ​   <td class=\"​record_col\"><​a href=\"​download.php?​audio=$recorded_file.$system_audio_format\"​ title=\"​Listen to call recording\"><​img src=\"​templates/​images/​sound.png\"​ alt=\"​Call recording\"​ /></​a><​audio controls><​source src=\"​download.php?​audio=$recorded_file.$system_audio_format\"></​audio></​td>​\n";​
 </​code>​ </​code>​
 ===== Asterisk realtime ===== ===== Asterisk realtime =====
Line 1468: Line 1503:
 ... ...
 </​code>​ </​code>​
-===== Аутентификация и учет звонков в RADIUS ===== 
  
-  * [[Сервис FreeRADIUS]] 
- 
-<​code>​ 
-# cat /​usr/​share/​auth.sh 
-</​code><​code>​ 
-#!/bin/sh 
- 
-CALL_FROM=$1 
- 
-# chown asterisk /​tmp/​auth.log 
- 
-if echo "​User-Name=${CALL_FROM},​User-Password=${CALL_FROM},​NAS-IP-Address=127.0.0.1"​ | radclient localhost auth testing123 >>/​tmp/​auth.log 
-then 
-        echo -n YES 
-else 
-        echo -n NO 
-fi 
- 
-exit 0 
-</​code><​code>​ 
-# cat /​usr/​share/​acct-start.sh 
-</​code><​code>​ 
-#!/bin/sh 
- 
-CALL_ID=$1 
-CALL_FROM=$2 
-CALL_TO=$3 
- 
-echo "​User-Name=${CALL_FROM},​Acct-Session-Id=${CALL_ID},​Called-Station-Id=${CALL_TO},​Calling-Station-Id=${CALL_FROM},​Acct-Status-Type=Start,​NAS-IP-Address=127.0.0.1,​NAS-Port=${CALL_FROM}${CALL_TO}"​| radclient localhost acct testing123 
- 
-exit 0 
-</​code><​code>​ 
-# cat /​usr/​share/​acct-stop.sh 
-</​code><​code>​ 
-#!/bin/sh 
- 
-CALL_ID=$1 
-CALL_FROM=$2 
-CALL_TO=$3 
- 
-echo "​User-Name=${CALL_FROM},​Acct-Session-Id=${CALL_ID},​Acct-Status-Type=Stop,​NAS-IP-Address=127.0.0.1,​NAS-Port=${CALL_FROM}${CALL_TO}"​| radclient localhost acct testing123 
- 
-exit 0 
-</​code>​ 
- 
-Примечания:​ 
- 
-  * Помещаем абонента,​ звонки которого надо тарифицировать,​ в контекст billing 
-  * Переводим все тарифицируемые вызовы в контекст aaa-call (что-бы отследить событие окончания разговора через контекст "​h"​) 
-  * В случае MYAUTH!=NO разрешаем абоненту совершить звонок. С помощью макроса "​U"​ программируем вызов кода в момент снятия трубки для начала тарификации. По какой то причине переменные ${CALLERID(num)} ${CALLERID(dnid)} не передаются,​ а ${UNIQUEID} меняет значение в этом коде, поэтому занчения передаются через аргументы. 
-  * В контексте "​h"​ проверяем факт наличия разговора и только в этом случае тарифицируем его окончание 
- 
-<​code>​ 
-# cat /​etc/​asterisk/​extensions.conf 
-</​code><​code>​ 
-... 
-[billing] 
-... 
-exten => _4XX,​1,​Goto(aaa-call,​s,​1) 
-... 
-[aaa-call] 
-exten => s,​1,​Verbose(AUTH CALL_ID=${UNIQUEID} CALL_FROM=${CALLERID(num)} CALL_TO=${CALLERID(dnid)}) 
-exten => s,​n,​Set(MYAUTH=${SHELL(/​usr/​share/​auth.sh ${CALLERID(num)})});​ 
-exten => s,​n,​GotoIf($["​${MYAUTH}"​ = "​NO"​]?​end_call) 
-exten => s,​n,​Dial(SIP/​${CALLERID(dnid)},,​U(aaa-call-beg-acct,​${UNIQUEID},​${CALLERID(num)},​${CALLERID(dnid)}));​ 
-exten => s,​n(end_call),​Hangup() 
- 
-exten => h,​1,​GotoIf($["​${DIALSTATUS}"​ != "​ANSWER"​]?​no-answer) 
-exten => h,​n,​Verbose(END ACCT DIALSTATUS=${DIALSTATUS} CALL_ID=${UNIQUEID} CALL_FROM=${CALLERID(num)} CALL_TO=${CALLERID(dnid)}) 
-exten => h,​n,​System(/​usr/​share/​acct-stop.sh ${UNIQUEID} ${CALLERID(num)} ${CALLERID(dnid)}) 
-exten => h,​n(no-answer),​NoOp() 
- 
-[aaa-call-beg-acct] 
-exten => s,​1,​Verbose(BEGIN ACCT CALL_ID=${ARG1} CALL_FROM=${ARG2} CALL_TO=${ARG3}) 
-exten => s,​n,​System(/​usr/​share/​acct-start.sh ${ARG1} ${ARG2} ${ARG3}) 
-exten => s,n,return 
-... 
-</​code>​ 
 ===== Настройка дополнительных видов обслуживания ===== ===== Настройка дополнительных видов обслуживания =====
  
Line 1577: Line 1533:
 [general] [general]
 ... ...
-;featuredigittimeout = 1000+featuredigittimeout = 3000
 ... ...
 [featuremap] [featuremap]
Line 1667: Line 1623:
 ... ...
 pickupexten = *88 pickupexten = *88
-... 
-</​code><​code>​ 
-server# cat /​etc/​asterisk/​extensions.conf 
-</​code><​code>​ 
-... 
-exten => _8XXXXXXXXXX,​1,​Dial(SIP/​voip1_00000X/​${EXTEN},,​T) 
-... 
-exten => voip1_00000X,​1,​Dial(SIP/​401,,​t) 
 ... ...
 </​code><​code>​ </​code><​code>​
Line 1701: Line 1649:
  
 include => parkedcalls include => parkedcalls
 +...
 +exten => _8XXXXXXXXXX,​1,​Dial(SIP/​voip1_00000X/​${EXTEN},,​T)
 +...
 +exten => voip1_00000X,​1,​Dial(SIP/​401,,​t)
 ... ...
 </​code>​ </​code>​
Line 1775: Line 1727:
 ... ...
  
-;For IMAP/SMTP+;;;For IMAP/SMTP
 ;​charset=UTF-8 ;​charset=UTF-8
 ;​locale=ru_RU.UTF-8 ;​locale=ru_RU.UTF-8
Line 1784: Line 1736:
 ... ...
  
-;For IMAP +;;;For IMAP 
-;debian# apt install asterisk-voicemail-imapstorage +;;;debian# apt install asterisk-voicemail-imapstorage 
-;debian# cp /​etc/​dovecot/​private/​dovecot.pem /​usr/​local/​share/​ca-certificates/​dovecot.crt +;;;debian# cp /​etc/​dovecot/​private/​dovecot.pem /​usr/​local/​share/​ca-certificates/​dovecot.crt 
-;debian# update-ca-certificates +;;;debian# update-ca-certificates 
-;debian# service asterisk restart+;;;debian# service asterisk restart
 ;​imapserver=server.corpX.un ;​imapserver=server.corpX.un
 ;​imapfolder=INBOX ;​imapfolder=INBOX
  
-;For SMTP+;;;For SMTP
 ;debian# apt install postfix mailutils ;debian# apt install postfix mailutils
  
Line 1913: Line 1865:
 ==== С использованием Call файлов ==== ==== С использованием Call файлов ====
  
-  * [[http://wiki.pro-voip.ru/asterisk/asterisk-call-files.html|Синтаксис вызова ​Asterisk Call Files]]+  * [[https://docs.asterisk.org/Configuration/Interfaces/​Asterisk-Call-Files/|Asterisk Call Files]]
   * [[Сервис atrun]]   * [[Сервис atrun]]
  
 <​code>​ <​code>​
-server# cat 1.call+# cat call.txt
 </​code><​code>​ </​code><​code>​
-Channel: ​sip/401 +Channel: ​Local/voip1_00000X@default 
-Extension: ​601+Extension: ​89161234567
 Context: default Context: default
-CallerId: ​Conferencia ​<601>+CallerId: ​CorpX<84992636363>
 </​code><​code>​ </​code><​code>​
-server# ​cat 2.call +server# ​grep astspooldir ​/etc/​asterisk/asterisk.conf 
-</code><​code>​ + 
-Channel: sip/402 +server# ​cp call.txt /var/​spool/​asterisk/​outgoing
-Extension: 601 + 
-Context: default +server# ​ls /​var/​spool/​asterisk/​outgoing_done
-CallerId: Conferencia <​601>​ +
-</​code><​code>​ +
-server# ​cat 3.call +
-</code><​code>​ +
-Channel: sip/403 +
-Extension: 601 +
-Context: default +
-CallerId: Conferencia <​601>​ +
-</​code><​code>​ +
-server# ​cp [123].call ​/​var/​spool/​asterisk/​outgoing/+
 </​code><​code>​ </​code><​code>​
 # cat /​usr/​share/​originate_call_file.sh # cat /​usr/​share/​originate_call_file.sh
Line 2029: Line 1971:
 ;[menu2] ;[menu2]
 ;exten => s,​1,​Background(silence/​8) ;exten => s,​1,​Background(silence/​8)
-;exten => s,1,​WaitExten(8) ​   ; работает только после Answer или Background+;exten => s,n,​WaitExten(8) ​   ; работает только после Answer или Background
 ;exten => _4XX,​1,​Goto(default,​${EXTEN},​1) ;exten => _4XX,​1,​Goto(default,​${EXTEN},​1)
 ;exten => t,​1,​Goto(menu,​s,​1) ​ ; timeout exceeded, работает только с WaitExten ;exten => t,​1,​Goto(menu,​s,​1) ​ ; timeout exceeded, работает только с WaitExten
Line 2261: Line 2203:
 ;​number=>​89162323232,​30 ;​number=>​89162323232,​30
 context=>​default context=>​default
 +;​context=>​to-pstn
 [401] [401]
 number=>​89162323232,​30 number=>​89162323232,​30
 ;​number=>​89163434345,​30 ;​number=>​89163434345,​30
 context=>​default context=>​default
 +;​context=>​to-pstn
 </​code><​code>​ </​code><​code>​
 server# cat /​etc/​asterisk/​extensions.conf server# cat /​etc/​asterisk/​extensions.conf
Line 2407: Line 2351:
 exten => s,​n,​ExecIf($["​${DIALSTATUS}"​="​${BUSY}"​]?​Bridge(SIP/​854)) exten => s,​n,​ExecIf($["​${DIALSTATUS}"​="​${BUSY}"​]?​Bridge(SIP/​854))
 exten => s,​n,​Dial(SIP/​854) exten => s,​n,​Dial(SIP/​854)
 +</​code>​
 +
 +Кузьмин Алексей предложил решение,​ если требуется только уведомить звонящего
 +
 +<​code>​
 +exten => _X.,​1,​Dial(PJSIP/​${EXTEN},​60)
 +exten => _X.,​n,​Goto(s-${DIALSTATUS},​1) ; Jump based on status (NOANSWER, BUSY, CHANUNAVAIL,​ CONGESTION, ANSWER)
 +exten => s-BUSY,​1,​Playback(ru/​custom/​busy_ru)
 +exten => s-BUSY,​n,​Hangup()
 +exten => s-NOANSWER,​1,​Playback(ru/​custom/​noanswer_ru)
 +exten => s-NOANSWER,​n,​Hangup()
 +exten => s-CHANUNAVAIL,​1,​Playback(ru/​custom/​invalid_ru)
 +exten => s-CHANUNAVAIL,​n,​Hangup()
 </​code>​ </​code>​
 ===== Организация Call центра ===== ===== Организация Call центра =====
Line 2424: Line 2381:
  
 [queue1] [queue1]
-;для демонстрации на многоканальном телефоне установить call-limit=1 +;​timeout=10 
-;member => SIP/401  ; ​в вебинаре ​(занять ​можно ​звонком на 311) + 
-;member => SIP/403  ​в классе+;для демонстрации на многоканальном телефоне установить call-limit=1  
 +;member => SIP/403  ; (можно ​занять звонком на 311) 
 + 
 +;member => SIP/user1@mailcgp 
 +;member => SIP/​user2@mailcgp 
 +;member => SIP/​user3@mailcgp
 </​code><​code>​ </​code><​code>​
 sever# cat /​etc/​asterisk/​extensions.conf sever# cat /​etc/​asterisk/​extensions.conf
Line 2477: Line 2439:
 strategy = rrmemory strategy = rrmemory
 musicclass = default musicclass = default
-timeout=10 
  
 announce = queue-markq announce = queue-markq
Line 2487: Line 2448:
 member => Local/​802@agents member => Local/​802@agents
 member => Local/​803@agents member => Local/​803@agents
- 
-;member => SIP/​user1@mailcgp 
-;member => SIP/​user2@mailcgp 
-;member => SIP/​user3@mailcgp 
 </​code><​code>​ </​code><​code>​
 server*CLI>​ queue show queue1 server*CLI>​ queue show queue1
Line 2515: Line 2472:
 ... ...
 </​code>​ </​code>​
-==== Приложение SHELL ====+==== Функция SHELL ====
  
   * !!! Название функции только ЗАГЛАВНЫМИ буквами   * !!! Название функции только ЗАГЛАВНЫМИ буквами
Line 2559: Line 2516:
  
 === Пример на SHELL === === Пример на SHELL ===
 +
 +
  
 <​code>​ <​code>​
Line 2605: Line 2564:
 exten => 313,​n,​Hangup() exten => 313,​n,​Hangup()
 ... ...
 +</​code>​
 +
 +Решение от Кузьмина Алексея,​ скрипты взаимоисключающие,​ один только переводит полное ФИО в фамилию + инициалы,​ второй еще транслитирует
 +
 +<​code>​
 +Место хранения /​var/​lib/​asterisk/​agi-bin
 +
 +Сделать исполняемыми chmod +x
 +
 +exten => _X.,​1,​AGI(shortname.sh,​${CALLERID(name)},​${CALLERID(num)})
 +exten => _X.,​1,​AGI(translite.sh,​${CALLERID(name)},​${CALLERID(num)})
 +
 +shortname.sh
 +
 +#!/bin/bash
 +fio=""​
 +words=($1)
 +num=$2
 +m=${#​words[@]}
 +for ((i=0;​i<​=m-1;​i++));​ do
 +    word=${words[$i]}
 +    if [ $i -gt 0 ]; then
 +        word=${word:​0:​1}.
 +    fi
 +    if [ $i -eq 0 ]; then
 +        fio="​${word} "
 +    else
 +        fio="​${fio}${word}"​
 +    fi
 +done
 +echo "SET CALLERID \"​$fio\"<​$num>"​
 +
 +translite.sh
 +
 +#!/bin/bash
 +fio=""​
 +words=($1)
 +num=$2
 +m=${#​words[@]}
 +for ((i=0;​i<​=m-1;​i++));​ do
 +    word=${words[$i]}
 +    if [ $i -gt 0 ]; then
 +        word=${word:​0:​1}.
 +    fi
 +    str=`echo $word | sed "​y/​абвгдеёзийклмнопрстуфыэ/​abvgdeeziyklmnoprstufye/"​`
 +    str=`echo $str | sed "​y/​АБВГДЕЁЗИЙКЛМНОПРСТУФЫЭ/​ABVGDEEZIYKLMNOPRSTUFYE/"​`
 +    str=${str//​ж/​zh} str=${str//​Ж/​Zh};​
 +    str=${str//​х/​kh} str=${str//​Х/​Kh};​
 +    str=${str//​ц/​ts} str=${str//​Ц/​Ts};​
 +    str=${str//​ч/​ch} str=${str//​Ч/​Ch};​
 +    str=${str//​ш/​sh} str=${str//​Ш/​Sh};​
 +    str=${str//​щ/​sch} str=${str//​Щ/​Sch};​
 +    str=${str//​ъ/​} str=${str//​Ъ/​};​
 +    str=${str//​ь/​} str=${str//​Ь/​};​
 +    str=${str//​ю/​yu} str=${str//​Ю/​Yu};​
 +    str=${str//​я/​ya} str=${str//​Я/​Ya};​
 +    if [ $i -eq 0 ]; then
 +        fio="​${str} "
 +    else
 +        fio="​${fio}${str}"​
 +    fi
 +done
 +echo "SET CALLERID \"​$fio\"<​$num>"​
 </​code>​ </​code>​
  
Line 3120: Line 3142:
 ==== Использование хешей паролей для каналов типа user ==== ==== Использование хешей паролей для каналов типа user ====
  
-[[http://​www.voip-info.org/​wiki/​view/​Asterisk+sip+md5secret]]+  * [[http://​www.voip-info.org/​wiki/​view/​Asterisk+sip+md5secret]] 
 +  * [[http://​asterisk-support.ru/​forum/​topics/​3032/​|SIP авторизация и MD5]]
  
 <​code>​ <​code>​
Line 3133: Line 3156:
 [402] [402]
 ;​secret=tpassword402 ;​secret=tpassword402
-md5secret=29c91aa064cf462f5146b7ee81e7ba49+md5secret=a77b8ed36b4be2c14c2d7e4dfad34b46
 ... ...
 </​code>​ </​code>​
Line 3228: Line 3251:
  
   * [[Голосовые сервисы помогут голосовой почте]]   * [[Голосовые сервисы помогут голосовой почте]]
 +
 +==== Сотрудник звонит на внешний номер, внешний номер перезванивает ====
 +<​code>​
 +Сотрудник звонит на внешний номер, номер не отвечает или занят.
 +
 +Внешний номер перезванивает на внешний номер организации (с которого у него пропущенный),​ где по умолчанию его должен встретить IVR.
 +
 +Если в течении последних Х минут в cdr есть запись звонка на этот внешний номер с состоянием номер не отвечает или занят, то соединить с внутренним номер с которого ему звонили.
 +
 +ДОП.: Если при этом в cdr есть запись что с этим внешним номером звонок состоялся(по времени после не отвеченного,​ направление не важно, внешний номер сам перезвонил и дозвонился или до него дозвонились со второго раза), то переключить на IVR.
 +
 + 
 +
 +Решение собственное,​ если есть что улучшить буду рад.
 +
 +Адаптировано под вашу методичку,​ но лучше проверить.
 +
 + 
 +
 +/​etc/​asterisk/​func_odbc.conf
 +
 + 
 +
 +[NOTANSWERED_BY_CALLERID]
 +
 +dsn=asterisk
 +
 +readsql=SELECT cnum FROM cdr WHERE dst='​${ARG1}'​ AND disposition<>'​ANSWERED'​ AND (calldate >= (SELECT COALESCE(MAX(calldate),​ now() - interval ${ARG2} minute) AS calldate FROM cdr WHERE (dst='​${ARG1}'​ OR src='​${ARG1}'​) AND disposition='​ANSWERED'​ AND (calldate >= now() - interval ${ARG2} minute) ORDER BY calldate DESC LIMIT 1)) ORDER BY calldate DESC LIMIT 1;
 +
 + 
 +
 +/​etc/​asterisk/​extensions.conf
 +
 + 
 +
 +exten => voip1_00000X,​1,​Set(NOTANSWERED=${ODBC_NOTANSWERED_BY_CALLERID(${CALLERID(num)},​5)}) ; External number, # minutes to search not answered call
 +
 +same => n,​GotoIf($[${LEN(${NOTANSWERED})} != 0]?recall)
 +
 +same => n,​Goto(ivr,​s,​1)
 +
 +same => n(recall),​Set(CALLERID(name)=RECALL ${CALLERID(name)})
 +
 +same => n,​Dial(PJSIP/​${NOTANSWERED},​60)
 +
 + 
 +
 +Вызывается функция ODBC с передачей ей номера звонящего и количества минут за которые искать записи.
 +
 +В SQL запросе вначале выполняется поиск за указанный интервал в минутах отвеченных звонков с участием внешнего номера и возвращается дата самого последнего звонка,​ если он есть, либо дата начала указанного интервала поиска (now() – 5 минут, например) и после этого выполняется поиск не отвеченных звонков на указанный внешний номер за указанный интервал.
 +
 +После этого к CALLERID(name) звонящего добавляется RECALL, чтобы уведомить сотрудника,​ что ему перезванивают,​ и осуществляется соединение с номером сотрудника от которого был последний не отвеченный звонок,​ или переключение на IVR, если не отвеченных звонков не было.
 +
 + 
 +
 +Алексей Михайлович Кузьмин
 +</​code>​
 ==== Принудительный провижининг ==== ==== Принудительный провижининг ====
 <​code>​ <​code>​
сервис_asterisk.1649318203.txt.gz · Last modified: 2022/04/07 10:56 by val