Merged revisions 77424,77429 via svnmerge from
[asterisk/asterisk.git] / doc / tex / queues-with-callback-members.tex
1
2 \section{Introduction}
3
4 Pardon, but the dialplan in this tutorial will be expressed
5 in AEL, the new Asterisk Extension Language. If you are 
6 not used to its syntax, we hope you will find it to some
7 degree intuitive. If not, there are documents explaining
8 its syntax and constructs.
9
10
11 \section{Configuring Call Queues}
12
13 \subsection{queues.conf}
14 First of all, set up call queues in queue.conf
15
16 Here is an example:
17
18 \begin{verbatim}
19    =========== queues.conf ===========
20    | ; Cool Digium Queues            |
21    | [general]                       |
22    | persistentmembers = yes         |
23    |                                 |
24    | ; General sales queue           |
25    | [sales-general]                 |
26    | music=default                   |
27    | context=sales                   |
28    | strategy=ringall                |
29    | joinempty=strict                |
30    | leavewhenempty=strict           |
31    |                                 |
32    | ; Customer service queue        |
33    | [customerservice]               |
34    | music=default                   |
35    | context=customerservice         |
36    | strategy=ringall                |
37    | joinempty=strict                |
38    | leavewhenempty=strict           |
39    |                                 |
40    | ; Support dispatch queue        |
41    | [dispatch]                      |
42    | music=default                   |
43    | context=dispatch                |
44    | strategy=ringall                |
45    | joinempty=strict                |
46    | leavewhenempty=strict           |
47    ===================================
48 \end{verbatim}
49
50 In the above, we have defined 3 separate calling queues: 
51 sales-general, customerservice, and dispatch.
52
53 Please note that the sales-general queue specifies a
54 context of "sales", and that customerservice specifies the
55 context of "customerservice", and the dispatch
56 queue specifies the context "dispatch". These three
57 contexts must be defined somewhere in your dialplan.
58 We will show them after the main menu below.
59
60 In the [general] section, specifying the persistentmembers=yes,
61 will cause the agent lists to be stored in astdb, and 
62 recalled on startup.
63
64 The strategy=ringall will cause all agents to be dialed
65 together, the first to answer is then assigned the incoming
66 call. 
67
68 "joinempty" set to "strict" will keep incoming callers from
69 being placed in queues where there are no agents to take calls.
70 The Queue() application will return, and the dial plan can 
71 determine what to do next.
72
73 If there are calls queued, and the last agent logs out, the
74 remaining incoming callers will immediately be removed from
75 the queue, and the Queue() call will return, IF the "leavewhenempty" is
76 set to "strict".
77
78 \subsection{Routing incoming Calls to Queues}
79
80
81 Then in extensions.ael, you can do these things:
82
83 \subsubsection{The Main Menu} 
84
85 At Digium, incoming callers are sent to the "mainmenu" context, where they
86 are greeted, and directed to the numbers they choose...
87
88 \begin{verbatim}
89 context mainmenu {
90
91         includes {
92                 digium;
93                 queues-loginout;
94         }
95
96         0 => goto dispatch|s|1;
97         2 => goto sales|s|1;
98         3 => goto customerservice|s|1;
99         4 => goto dispatch|s|1;
100
101         s => {
102                 Ringing();
103                 Wait(1);
104                 Set(attempts=0);
105                 Answer();
106                 Wait(1);
107                 Background(digium/ThankYouForCallingDigium);
108                 Background(digium/YourOpenSourceTelecommunicationsSupplier);
109                 WaitExten(0.3);
110         repeat:
111                 Set(attempts=$[${attempts} + 1]);
112                 Background(digium/IfYouKnowYourPartysExtensionYouMayDialItAtAnyTime);
113                 WaitExten(0.1);
114                 Background(digium/Otherwise);
115                 WaitExten(0.1);
116                 Background(digium/ForSalesPleasePress2);
117                 WaitExten(0.2);
118                 Background(digium/ForCustomerServicePleasePress3);
119                 WaitExten(0.2);
120                 Background(digium/ForAllOtherDepartmentsPleasePress4);
121                 WaitExten(0.2);
122                 Background(digium/ToSpeakWithAnOperatorPleasePress0AtAnyTime);
123                 if( ${attempts} < 2 ) {
124                         WaitExten(0.3);
125                         Background(digium/ToHearTheseOptionsRepeatedPleaseHold);
126                 }
127                 WaitExten(5);
128                 if( ${attempts} < 2 ) goto repeat;
129                 Background(digium/YouHaveMadeNoSelection);
130                 Background(digium/ThisCallWillBeEnded);
131                 Background(goodbye);
132                 Hangup();
133         }
134 }
135 \end{verbatim}
136
137 \subsubsection{The Contexts referenced from the queues.conf file}
138
139 \begin{verbatim}
140 context sales {
141
142         0 => goto dispatch|s|1;
143         8 => Voicemail(${SALESVM});
144
145         s => {
146                 Ringing();
147                 Wait(2);
148                 Background(digium/ThankYouForContactingTheDigiumSalesDepartment);
149                 WaitExten(0.3);
150                 Background(digium/PleaseHoldAndYourCallWillBeAnsweredByOurNextAvailableSalesRepresentative);
151                 WaitExten(0.3);
152                 Background(digium/AtAnyTimeYouMayPress0ToSpeakWithAnOperatorOr8ToLeaveAMessage);
153                 Set(CALLERID(name)=Sales);
154                 Queue(sales-general|t);
155                 Set(CALLERID(name)=EmptySalQ);
156                 goto dispatch|s|1;
157                 Playback(goodbye);
158                 Hangup();
159         }
160 }
161 \end{verbatim}
162
163 Please note that there is only one attempt to queue a call in the sales queue. All sales agents that
164 are logged in will be rung.
165
166 \begin{verbatim}
167 context customerservice {
168
169         0 => {
170                 SetCIDName(CSVTrans);
171                 goto dispatch|s|1;
172         }
173         8 => Voicemail(${CUSTSERVVM});
174
175         s => {
176                 Ringing();
177                 Wait(2);
178                 Background(digium/ThankYouForCallingDigiumCustomerService);
179                 WaitExten(0.3);
180         notracking:
181                 Background(digium/PleaseWaitForTheNextAvailableCustomerServiceRepresentative);
182                 WaitExten(0.3);
183                 Background(digium/AtAnyTimeYouMayPress0ToSpeakWithAnOperatorOr8ToLeaveAMessage);
184                 Set(CALLERID(name)=Cust Svc);
185                 Set(QUEUE_MAX_PENALTY=10);
186                 Queue(customerservice|t);
187                 Set(QUEUE_MAX_PENALTY=0);
188                 Queue(customerservice|t);
189                 Set(CALLERID(name)=EmptyCSVQ);
190                 goto dispatch|s|1;
191                 Background(digium/NoCustomerServiceRepresentativesAreAvailableAtThisTime);
192                 Background(digium/PleaseLeaveAMessageInTheCustomerServiceVoiceMailBox);
193                 Voicemail(${CUSTSERVVM});
194                 Playback(goodbye);
195                 Hangup();
196         }
197 }
198 \end{verbatim}
199
200 Note that calls coming into customerservice will first be try to queue
201 calls to those agents with a QUEUE\_MAX\_PENALTY of 10, and if none are available,
202 then all agents are rung.
203
204 \begin{verbatim}
205 context dispatch
206 {
207
208         s => {
209                 Ringing();
210                 Wait(2);
211                 Background(digium/ThankYouForCallingDigium);
212                 WaitExten(0.3);
213                 Background(digium/YourCallWillBeAnsweredByOurNextAvailableOperator);
214                 Background(digium/PleaseHold);
215                 Set(QUEUE_MAX_PENALTY=10);
216                 Queue(dispatch|t);
217                 Set(QUEUE_MAX_PENALTY=20);
218                 Queue(dispatch|t);
219                 Set(QUEUE_MAX_PENALTY=0);
220                 Queue(dispatch|t);
221                 Background(digium/NoOneIsAvailableToTakeYourCall);
222                 Background(digium/PleaseLeaveAMessageInOurGeneralVoiceMailBox);
223                 Voicemail(${DISPATCHVM});
224                 Playback(goodbye);
225                 Hangup();
226         }
227 }
228 \end{verbatim}
229
230 And in the dispatch context, first agents of priority 10 are tried, then
231 20, and if none are available, all agents are tried. 
232
233 Notice that a common pattern is followed in each of the three queue contexts:
234
235 First, you set QUEUE\_MAX\_PENALTY to a value, then you call
236 Queue($<$queue-name$>$,option,...) (see the Queue application documetation for details)
237
238 In the above, note that the "t" option is specified, and this allows the 
239 agent picking up the incoming call the luxury of transferring the call to 
240 other parties.
241
242 The purpose of specifying the QUEUE\_MAX\_PENALTY is to develop a set of priorities
243 amongst agents. By the above usage, agents with lower number priorities will 
244 be given the calls first, and then, if no-one picks up the call, the QUEUE\_MAX\_PENALTY
245 will be incremented, and the queue tried again. Hopefully, along the line, someone
246 will pick up the call, and the Queue application will end with a hangup.
247
248 The final attempt to queue in most of our examples sets the QUEUE\_MAX\_PENALTY
249 to zero, which means to try all available agents.
250
251
252 \subsection{Assigning agents to Queues}
253
254 In this example dialplan, we want to be able to add and remove agents to 
255 handle incoming calls, as they feel they are available. As they log in,
256 they are added to the queue's agent list, and as they log out, they are
257 removed. If no agents are available, the queue command will terminate, and
258 it is the duty of the dialplan to do something appropriate, be it sending
259 the incoming caller to voicemail, or trying the queue again with a higher 
260 QUEUE\_MAX\_PENALTY.
261
262 Because a single agent can make themselves available to more than one queue,
263 the process of joining multiple queues can be handled automatically by the
264 dialplan.
265
266 \subsubsection{Agents Log In and Out}
267
268 \begin{verbatim}
269 context queues-loginout
270 {
271         6092 => {
272                         Answer();
273                         Read(AGENT_NUMBER,agent-enternum);
274                         VMAuthenticate(${AGENT_NUMBER}@default,s);
275                         Set(queue-announce-success=1);
276                         goto queues-manip,I${AGENT_NUMBER},1;
277                 }
278
279         6093 => {
280                         Answer();
281                         Read(AGENT_NUMBER,agent-enternum);
282                         Set(queue-announce-success=1);
283                         goto queues-manip,O${AGENT_NUMBER},1;
284                 }
285 }
286 \end{verbatim}
287
288 In the above contexts, the agents dial 6092 to log into their queues,
289 and they dial 6093 to log out of their queues. The agent is prompted
290 for their agent number, and if they are logging in, their passcode, 
291 and then they are transferred to the proper extension in the 
292 queues-manip context.  The queues-manip context does all the 
293 actual work:
294
295 \begin{verbatim}
296 context queues-manip {
297
298         // Raquel Squelch
299         _[IO]6121 => {
300                 &queue-addremove(dispatch,10,${EXTEN});
301                 &queue-success(${EXTEN});
302         }
303
304         // Brittanica Spears
305         _[IO]6165 => {
306                 &queue-addremove(dispatch,20,${EXTEN});
307                 &queue-success(${EXTEN});
308         }
309
310         // Rock Hudson
311         _[IO]6170 => {
312                 &queue-addremove(sales-general,10,${EXTEN});
313                 &queue-addremove(customerservice,20,${EXTEN});
314                 &queue-addremove(dispatch,30,${EXTEN});
315                 &queue-success(${EXTEN});
316         }
317
318         // Saline Dye-on
319         _[IO]6070 => {
320                 &queue-addremove(sales-general,20,${EXTEN});
321                 &queue-addremove(customerservice,30,${EXTEN});
322                 &queue-addremove(dispatch,30,${EXTEN});
323                 &queue-success(${EXTEN});
324         }
325 }
326 \end{verbatim}
327
328 In the above extensions, note that the queue-addremove macro is used
329 to actually add or remove the agent from the applicable queue,
330 with the applicable priority level. Note that agents with a 
331 priority level of 10 will be called before agents with levels
332 of 20 or 30.
333
334 In the above example, Raquel will be dialed first in the dispatch
335 queue, if she has logged in. If she is not, then the second call of
336 Queue() with priority of 20 will dial Brittanica if she is present,
337 otherwise the third call of Queue() with MAX\_PENALTY of 0 will 
338 dial Rock and Saline simultaneously.
339
340 Also note that Rock will be among the first to be called in the sales-general 
341 queue, and among the last in the dispatch queue. As you can see in
342 main menu, the callerID is set in the main menu so they can tell 
343 which queue incoming calls are coming from.
344
345 The call to queue-success() gives some feedback to the agent
346 as they log in and out, that the process has completed.
347
348 \begin{verbatim}
349 macro queue-success(exten)
350 {
351         if( ${queue-announce-success} > 0 )
352         {
353                 switch(${exten:0:1})
354                 {
355                 case I:
356                         Playback(agent-loginok);
357                         Hangup();
358                 case O:
359                         Playback(agent-loggedoff);
360                         Hangup();
361                 }
362         }
363 }
364 \end{verbatim}
365
366 The queue-addremove macro is defined in this manner:
367
368 \begin{verbatim}
369 macro queue-addremove(queuename,penalty,exten)
370 {
371         switch(${exten:0:1})
372         {
373         case I:  // Login
374                 {
375                  AddQueueMember(${queuename},Local/${exten:1}@agents,${penalty});
376                  break;
377                 }
378         case O:  // Logout
379                 {
380                  RemoveQueueMember(${queuename},Local/${exten:1}@agents);
381                  break;
382                 }
383         case P:  // Pause
384                 {
385                  PauseQueueMember(${queuename},Local/${exten:1}@agents);
386                  break;
387                 }
388         case U:  // Unpause
389                 {
390                  UnpauseQueueMember(${queuename},Local/${exten:1}@agents);
391                  break;
392                 }
393         default: // Invalid
394                 {
395                  Playback(invalid);
396                 }
397         }
398 }
399 \end{verbatim}
400
401 Basically, it uses the first character of the exten variable, to determine the
402 proper actions to take. In the above dial plan code, only the cases I or O are used,
403 which correspond to the Login and Logout actions.
404
405
406 \subsection{Controlling The Way Queues Call the Agents}
407
408 Notice in the above, that the commands to manipulate agents in queues have
409 "@agents" in their arguments. This is a reference to the agents context:
410
411 \begin{verbatim}
412 context agents
413 {
414         // General sales queue
415         8010 =>
416         {
417                 Set(QUEUE_MAX_PENALTY=10);
418                 Queue(sales-general|t);
419                 Set(QUEUE_MAX_PENALTY=0);
420                 Queue(sales-general|t);
421                 Set(CALLERID(name)=EmptySalQ);
422                 goto dispatch|s|1;
423         }
424         // Customer Service queue
425         8011 =>
426         {
427                 Set(QUEUE_MAX_PENALTY=10);
428                 Queue(customerservice|t);
429                 Set(QUEUE_MAX_PENALTY=0);
430                 Queue(customerservice|t);
431                 Set(CALLERID(name)=EMptyCSVQ);
432                 goto dispatch|s|1;
433         }
434         8013 =>
435         {
436                 Dial(iax2/sweatshop/9456@from-ecstacy);
437
438                 Set(CALLERID(name)=EmptySupQ);
439                 Set(QUEUE_MAX_PENALTY=10);
440                 Queue(support-dispatch,t);
441                 Set(QUEUE_MAX_PENALTY=20);
442                 Queue(support-dispatch,t);
443                 Set(QUEUE_MAX_PENALTY=0); // means no max
444                 Queue(support-dispatch,t);
445                 goto dispatch|s|1;
446         }
447         6121 => &callagent(${RAQUEL},${EXTEN});
448         6165 => &callagent(${SPEARS},${EXTEN});
449         6170 => &callagent(${ROCK},${EXTEN});
450         6070 => &callagent(${SALINE},${EXTEN});
451 }
452 \end{verbatim}
453
454 In the above, the variables \${RAQUEL}, etc stand for
455 actual devices to ring that person's
456 phone (like Zap/37).
457
458 The 8010, 8011, and 8013 extensions are purely for transferring
459 incoming callers to queues. For instance, a customer service 
460 agent might want to transfer the caller to talk to sales. The 
461 agent only has to transfer to extension 8010, in this case.
462
463 Here is the callagent macro, note that if a person in the
464 queue is called, but does not answer, then they are automatically
465 removed from the queue.
466
467 \begin{verbatim}
468 macro callagent(device,exten)
469 {
470         if( ${GROUP_COUNT(${exten}@agents)}=0 )
471         {
472                 Set(OUTBOUND_GROUP=${exten}@agents);
473                 Dial(${device}|300|t);
474                 switch(${DIALSTATUS})
475                 {
476                 case BUSY:
477                         Busy();
478                         break;
479                 case NOANSWER:
480                         Set(queue-announce-success=0);
481                         goto queues-manip|O${exten}|1;
482                 default:
483                         Hangup();
484                         break;
485                 }
486         }
487         else
488         {
489                 Busy();
490         }
491 }
492 \end{verbatim}
493
494 In the callagent macro above, the \${exten} will
495 be 6121, or 6165, etc, which is the extension of the agent.
496
497 The use of the GROUP\_COUNT, and OUTBOUND\_GROUP follow this line
498 of thinking. Incoming calls can be queued to ring all agents in the
499 current priority. If some of those agents are already talking, they
500 would get bothersome call-waiting tones. To avoid this inconvenience,
501 when an agent gets a call, the OUTBOUND\_GROUP assigns that 
502 conversation to the group specified, for instance 6171@agents.
503 The \${GROUP\_COUNT()} variable on a subsequent call should return
504 "1" for that group. If GROUP\_COUNT returns 1, then the busy() 
505 is returned without actually trying to dial the agent.
506
507 \subsection{Pre Acknowledgement Message}
508
509 If you would like to have a pre acknowledge message with option to reject the message
510 you can use the following dialplan Macro as a base with the 'M' dial argument.
511
512 \begin{verbatim}
513 [macro-screen]
514 exten=>s,1,Wait(.25)
515 exten=>s,2,Read(ACCEPT|screen-callee-options|1)
516 exten=>s,3,Gotoif($[${ACCEPT} = 1] ?50)
517 exten=>s,4,Gotoif($[${ACCEPT} = 2] ?30)
518 exten=>s,5,Gotoif($[${ACCEPT} = 3] ?40)
519 exten=>s,6,Gotoif($[${ACCEPT} = 4] ?30:30)
520 exten=>s,30,Set(MACRO_RESULT=CONTINUE)
521 exten=>s,40,Read(TEXTEN|custom/screen-exten|)
522 exten=>s,41,Gotoif($[${LEN(${TEXTEN})} = 3]?42:45)
523 exten=>s,42,Set(MACRO_RESULT=GOTO:from-internal^${TEXTEN}^1)
524 exten=>s,45,Gotoif($[${TEXTEN} = 0] ?46:4)
525 exten=>s,46,Set(MACRO_RESULT=CONTINUE)
526 exten=>s,50,Playback(after-the-tone)
527 exten=>s,51,Playback(connected)
528 exten=>s,52,Playback(beep)
529 \end{verbatim}
530
531 \subsection{Caveats}
532
533 In the above examples, some of the possible error checking has been omitted,
534 to reduce clutter and make the examples clearer.