Как стать автором
Обновить
70.56
Слёрм
Учебный центр для тех, кто работает в IT

Отправка уведомлений о пропущенных звонках из Asterisk

Время на прочтение5 мин
Количество просмотров39K
В данном посте я расскажу вам о возможностях отправки уведомлений о пропущенных звонках с помощью Asterisk. Я постараюсь привести простые примеры конфигурации и подробнее раскрыть данную тему, далее вы можете экспериментировать по своему усмотрению или потребностям. Asterisk предлагает довольно широкие возможности для решения различных задач, поэтому одну и ту же задачу можно решать по разному, главное результат — стабильная работа ваших сервисов.

Отправка отчета о пропущенном звонке на email



Что имеем:
Входящая многоканальная линия с номером +7 (495) 1234567, IVR, 4 оператора в очереди вызова.

Задачи:
1. Отправлять отчет о пропущенном звонке, с указанием номера звонящего, времени поступления звонка и времени ожидания на линии.
2. Если абонент ждал на линии более 10 секунд и по какой-либо причине положил трубку, не дождавшись ответа оператора — отправляем отчет о пропущенном звонке.
3. Заносить в БД (в текущем примере MySQL) данные о том, какой оператор в очереди ответил звонок и фиксируем время в которое разговор был завершен.



В качестве решения приведу пример конфигурации (один из возможных вариантов решения), с комментариями на самых интересных по-моему мнению моментах.
Вот так выглядит конфигурация IVR рабочего времени + очереди вызова:

[globals]
CIDFILE=/etc/asterisk/inc-calls/call-noanswer
SQLHOST=db.domain.ru
SQLUSER=asterisksql
SQLPASS=Gt6Rju8FkS
SQLDB=asteriskdb
IVRWORK=custom/IVR_company_wav

[incoming-74951234567]
exten => h,1,Set(WAITTIME=10)
exten => h,n,Set(CTALL=$[${CDR(duration)}])
exten => h,n,Set(CTANSWER=$[${CDR(billsec)}])
exten => h,n,Set(CTDTIME=$[${CTALL}-${CTANSWER}])
exten => h,n,NoOP(${CDR(disposition)})
exten => h,n,NoOP(${CTDTIME})
exten => h,n,GotoIf($["${CDR(disposition)}" = "NO ANSWER"]?timecheck:n1)
exten => h,n(n1),GotoIf($["${CDR(disposition)}" = "BUSY"]?timecheck:n2)
exten => h,n(n2),GotoIf($["${CDR(disposition)}" = "FAILED"]?timecheck:n3)
exten => h,n(n3),GotoIf($["${CDR(disposition)}" = "ANSWERED"]?n4:misscall)
exten => h,n(n4),MYSQL(Connect connid ${SQLHOST} ${SQLUSER} ${SQLPASS} ${SQLDB})
exten => h,n,MYSQL(Query resultid ${connid} UPDATE office_calls SET active=0 WHERE asterisk_id='${QID}')
exten => h,n,MYSQL(Clear ${resultid})
exten => h,n,MYSQL(Disconnect ${connid})
exten => h,n(hang),Hangup()
exten => h,n(timecheck),GotoIf($[${CTDTIME} > ${WAITTIME}]?misscall:hang)
exten => h,n(misscall),Goto(noanswer,s,1)
exten => s,1,NoOp(${CALLERID(num)})
exten => s,n,Set(CALLID=74951234567)
exten => s,n,Set(CALLER=${CALLERID(num)})
exten => s,n,Set(__QID=${CDR(uniqueid)})
exten => s,n(begin),GotoIfTime(10:00-22:00,mon-sat,*,*?workdays:outofoffice)
exten => s,n(workdays),NoOp(Incoming CALL from ${CALLERID(num)} to ${EXTEN})
exten => s,n,Answer()
exten => s,n,ResetCDR(w)
exten => s,n,Wait(1)
exten => s,n,Background(${IVRWORK})
exten => s,n,Queue(operators,t,,,300,,startflag1)
exten => s,n,NoOp(${DIALSTATUS})
exten => s,n,Goto(noanswer,s,1)
exten => s,n,Hangup()


Обратите внимание, что если работает IVR и требуется узнать точное время ожидания абонента на линии (в обратном случае, у вас посчитается и время, которое абонет слушал голосовое меню), то нужно после Answer() добавить ResetCDR(w). Еще один интересный момент — запись в БД нам нужно заносить как только оператор в очереди ответит на звонок — тут нам поможет макрос startflag1, который будет выполнен, как только любой оператор в очереди ответит на звонок.
Тут все довольно просто, если на вызов не ответили, переходим в контекст noanswer, который выглядит следующим образом:

[noanswer]
exten => s,1,NoOp(UID CALL: ${UNIQUEID} / DATE: ${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}))
exten => s,n,Set(RANDOM=${RAND(1000,9999)})
exten => s,n,Set(COUNT=${DB(fwcid2/count)})
exten => s,n,GotoIf($[${ISNULL(${COUNT})}]?:nextstep)
exten => s,n,Set(DB(fwcid2/count)=1)
exten => s,n,NoOp()
exten => s,n,NoOp(UNIQID = ${COUNT})
exten => s,n,Set(COUNT=$[${COUNT} + 1])
exten => s,n,Set(DB(fwcid2/count)=${COUNT})
exten => s,n,System(echo "Неотвеченный вызов с номера +7${CALLERID(NUM)} в ${STRFTIME(${EPOCH},,%H:%M)}" > ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
exten => s,n,System(echo "" >> ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
exten => s,n,System(echo "Время ожидания абонента на линии составило ${CTDTIME} сек" >> ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
exten => s,n,System(echo "hello" | mutt -x -s "+74951234567: пропущенный звонок ${STRFTIME(${EPOCH},,%d.%m.%Y)} ${STRFTIME(${EPOCH},,%H:%M)}" -e "set from="voip@domain.ru"" -e 'set realname='Asterisk'' voip@domain.ru < ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
exten => s,n,System(/bin/rm -f ${CIDFILE}-${CALLERID(NUM)}-${COUNT})
exten => s,n,Hangup()


${STRFTIME(${EPOCH},,%H:%M)} — время поступления звонка.
${CALLERID(NUM)} — номер звонящего.
${COUNT} — по большей части пример работы с ASTBD, значение переменной добавляется в конец создаваемого файла, чтобы сделать его уникальным, на случай если с одного и того же номера, в одно и то же время поступит звонок.

Теперь о добавлении записей в таблицу MySQL.
${SQLHOST/SQLUSER/SQLPASS/SQLD} — данные переменные я определил в секции globals.
${QID} — переменная которую мы передаем в макрос, предварительно определив ее при входящем звонке 'Set(__QID=${CDR(uniqueid)})'. Обратите внимание на два ведущих символа подчеркивания, позволяющих унаследовать переменную в макрос macro-startflag1.

[macro-startflag1]
exten => s,1,Set(CALLID=74951234567)
exten => s,n,MYSQL(Connect connid ${SQLHOST} ${SQLUSER} ${SQLPASS} ${SQLDB})
exten => s,n,MYSQL(Query resultid ${connid} INSERT INTO office_calls VALUES (NULL,'${STRFTIME(,GMT,%G-%m-%d %H:%M:%S)}',1,'${CALLID}','${CDR(src)}','${CDR(dstcha
nnel):0:9}','${STRFTIME(,GMT,%G-%m-%d %H:%M:%S)}','${STRFTIME(,GMT,%G-%m-%d %H:%M:%S)}','${QID}'))
exten => s,n,MYSQL(Clear ${resultid})
exten => s,n,MYSQL(Disconnect ${connid})
exten => s,n,Hangup()


Рассмотрим еще одну задачу: требуется формировать XML файл при пропущенных звонках.
Формат файла должен быть следующего вида:

<?xml version="1.0" encoding="UTF-8"?>
<callback_request>
  <id>100XXXX</id> --- XXX какой-то уникальный идентификатор
  <name></name> --- номер телефона, на который пришел звонок
  <phone>123456</phone> --- номер телефона, с которого пришел звонок
  <comment>Пропущенный звонок</comment>
  <completed>false</completed>
  <created_at>11.12.2012 - 17:19</created_at> --- дата звонка
  <updated_at>11.12.2012 - 17:19</updated_at> --- дата звонка
  <no_answer/>
</callback_request>


В решении задачи я воспользуюсь командой System() и perl- скриптом.
Установим XML::Writer

yum install perl-XML-Writer


Скрипт /etc/asterisk/scripts/genxml.pl выглядит следующим образом:

#!/usr/bin/env perl

# Create XML file

use strict;
use warnings;
use XML::Writer;

# Out to file 
#open STDOUT, ">", "REQUEST.20121211171903.xml" or die "$0: open: $!";

my $doc = new XML::Writer();

# Pring attributes

$doc->xmlDecl('UTF-8');
$doc->startTag("callback_request");
$doc->dataElement( id => "$ARGV[0]");
$doc->startTag( "name");
$doc->characters( "$ARGV[1]");
$doc->endTag( "name");
$doc->dataElement( phone => "$ARGV[2]");
$doc->dataElement( comment => "Пропущенный звонок");
$doc->dataElement( completed => "false");
$doc->dataElement( created_at => "$ARGV[3]");
$doc->dataElement( updated_at => "$ARGV[3]");
$doc->emptyTag( "no_answer");
$doc->endTag();
$doc->end();


Запуск скрипта производится следующим образом:

exten => s,n,System(/usr/bin/perl /etc/asterisk/scripts/genxml.pl "100${RANDOM}" "74951234567" "${CALLERID(NUM)}" "${STRFTIME(${EPOCH},,%d.%m.%Y - %H:%M)}" > /srv/www/domain.ru/xml/REQUEST.${STRFTIME(${EPOCH},,%Y%m%d%H%M%S)}.xml)


Надеюсь данный материал будет полезен вам.
Спасибо за внимание.
Теги:
Хабы:
+21
Комментарии7

Публикации

Информация

Сайт
slurm.io
Дата регистрации
Дата основания
Численность
51–100 человек
Местоположение
Россия
Представитель
Антон Скобин