This shows you the differences between two versions of the page.
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> |