Доброго времени суток!
Работая со звездочкой достаточно продолжительное время, мне периодически приходится решать тривиальную задачу: организовать вариант очереди входящих звонков в call-центре, который по максимуму задействует имеющиеся ресурсы (операторов, линии и т.д.).
Вроде все просто: настраиваешь queues и раскидываешь по операторам, но…понаблюдав за работой этой схемы я заметил одну не очевидную с первого взгляда вещь – пока не будет обработан первый входящий звонок в очереди, остальные клиенты этой очереди будут просто висеть и не попадать на свободных операторов (см. схему). А операторы, как известно, тоже люди…и без должного контроля очень даже ленивые!
Схема работы queue в Asterisk
Поразмыслив над задачей, я решил полностью отказаться от queue и сделать все на dial-ах.
Алгоритм написан на ael-ке и реализует стратегию обзвона linear, хотя никто не мешает переделать его под фактически любую из queues.conf:
context from-in {
_X. => {
Set(dialnum=10,20,30,40); // внутренние номера наших операторов
y=3; //количество повторов прохождения по операторам
array: // метка для возврата
while (${y} > 0) { // запускаем первый цикл
x=1; // задаем первый элемент массива номеров операторов
z=1; // инициируем переменную, чтобы запустить цикл перебора номеров
while (${z} > 0) { //запускаем цикл перебора номеров в переменной dialnum
nextstep: //метка для возврата
z=0; // обнуляем переменную
Set(num=${CUT(dialnum,\,,${x})}); //вытягиваем из переменной dialnum значение номера оператора
z=LEN(${num}); // вычисляем длину значения переменной
NoOp(-----------------${num}--------------);
if (${z} = 0) { //если номера закончились, то
y=${y}-1; //уменьшить значение количества повторов
Wait(3); //вставляем паузу пока все операторы заняты (на самом деле сюда можно запихать например Playback с какой нибудь фразой, типа "все операторы заняты ожидайте" и проиграть короткий ролик с рекламой)
goto array; //и повторяем прозвон операторов
} else { //вытащили значение номера оператора
Set(devstat=${DEVICE_STATE(SIP/${num})}); //присваиваем переменной devsat значение статуса оператора
switch (${devstat}) { //проверяем статус оператора
case NOT_INUSE: //если он не занят, то
x=${x}+1; //увеличиваем значение для выборки по следующему номеру оператора из списка в случае если данный оператор не возьмет трубку
Dial(SIP/${num},10,trg); //вызываем оператора
goto nextstep; //если он ен взял трубку - переходим к следующему
default: //если оператор занят, не в сети или вызывается, то
x=${x}+1; // переходим к следующему оператору
NooP(--------device is ${devstat}---------);
goto nextstep;
};
};
};
NoOp(------------ARRAY FINISH------------);
};
Hangup();
};
};
Как вариант, задействовать базу данных в том случае, если наши операторы не статические, а постоянно меняются или добавляются. Для этого создаем таблицу, например, такую:
create table operators (`extension` int(12) NOT NULL default '', `numbers` varchar(255) NOT NULL default '');
И вместо:
Set(dialnum=10,20,30,40);
Прописываем:
Set(dialnum=${ODBC_DIALNUM(${EXTEN})}); //делает выборку из таблицы в БД по соответствующему полю
Открываем func-odbc.conf и добавляем:
[DIALNUM]
readsql=SELECT numbers FROM operators WHERE EXTENSION LIKE '%${SQL_ESC(${ARG1})}%'
Рассказывать как подключается odbc и что это такое здесь не буду — есть куча замечательной документации в интернетах!
Добавляем в табличку несколько направлений с соответствующими операторами:
extension | numbers |
---|---|
222222 | 10,20,30 |
333333 | 10,20,40 |
444444 | 30,20,40 |
И теперь при звонке на определенный номер будут вызываться нужные операторы.
Прикрутить сюда musiconhold, announce можно точно также как это делается в queues.conf.
Спасибо за внимание и конструктивную критику!