Доброго времени суток!

Работая со звездочкой достаточно продолжительное время, мне периодически приходится решать тривиальную задачу: организовать вариант очереди входящих звонков в call-центре, который по максимуму задействует имеющиеся ресурсы (операторов, линии и т.д.).

Вроде все просто: настраиваешь queues и раскидываешь по операторам, но…понаблюдав за работой этой схемы я заметил одну не очевидную с первого взгляда вещь – пока не будет обработан первый входящий звонок в очереди, остальные клиенты этой очереди будут просто висеть и не попадать на свободных операторов (см. схему). А операторы, как известно, тоже люди…и без должного контроля очень даже ленивые!

Схема работы queue в Asterisk
image

Поразмыслив над задачей, я решил полностью отказаться от 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.

Спасибо за внимание и конструктивную критику!