use a macro instead of an inline function, so that backtraces will report the caller...
[asterisk-bristuff.git] / doc / queues-with-callback-members.txt
blob3a2c3e785b1b77ddf9a0bdef1a46112c10851e1f
2 Setting up Call Queues -- A Tutorial
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.
11 ======  Configuring Call Queues
13 First of all, set up call queues in queue.conf
15 Here is an example:
17    =========== queues.conf ===========
18    | ; Cool Digium Queues            |
19    | [general]                       |
20    | persistentmembers = yes         |
21    |                                 |
22    | ; General sales queue           |
23    | [sales-general]                 |
24    | music=default                   |
25    | context=sales                   |
26    | strategy=ringall                |
27    | joinempty=strict                |
28    | leavewhenempty=strict           |
29    |                                 |
30    | ; Customer service queue        |
31    | [customerservice]               |
32    | music=default                   |
33    | context=customerservice         |
34    | strategy=ringall                |
35    | joinempty=strict                |
36    | leavewhenempty=strict           |
37    |                                 |
38    | ; Support dispatch queue        |
39    | [support-dispatch]              |
40    | music=default                   |
41    | context=dispatch                |
42    | strategy=ringall                |
43    | joinempty=strict                |
44    | leavewhenempty=strict           |
45    ===================================
47 In the above, we have defined 3 separate calling queues: 
48 sales-general, customerservice, and support-dispatch.
50 Please note that the sales-general queue specifies a
51 context of "sales", and that customerservice specifies the
52 context of "customerservice", and the support-dispatch
53 queue specifies the context "dispatch". These three
54 contexts must be defined somewhere in your dialplan.
55 We will show them after the main menu below.
57 <verbage explaining options above>
58 In the [general] section, specifying the persistentmembers=yes,
59 will cause the agent lists to be stored in astdb, and 
60 recalled on startup.
62 The strategy=ringall will cause all agents to be dialed
63 together, the first to answer is then assigned the incoming
64 call. 
66 "joinempty" set to "strict" will keep incoming callers from
67 being placed in queues where there are no agents to take calls.
68 The Queue() application will return, and the dial plan can 
69 determine what to do next.
71 If there are calls queued, and the last agent logs out, the
72 remaining incoming callers will immediately be removed from
73 the queue, and the Queue() call will return, IF the "leavewhenempty" is
74 set to "strict".
77 =====================================
78 |  Routing incoming Calls to Queues |
79 =====================================
82 Then in extensions.ael, you can do these things:
84 ================ The Main Menu 
86 At Digium, incoming callers are sent to the "mainmenu" context, where they
87 are greeted, and directed to the numbers they choose...
89 context mainmenu {
91         includes {
92                 digium;
93                 queues-loginout;
94         }
96         0 => goto dispatch|s|1;
97         2 => goto sales|s|1;
98         3 => goto customerservice|s|1;
99         4 => goto dispatch|s|1;
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         }
137 ============= The Contexts referenced from the queues.conf file
141 context sales {
143         0 => goto dispatch|s|1;
144         8 => Voicemail(${SALESVM});
146         s => {
147                 Ringing();
148                 Wait(2);
149                 Background(digium/ThankYouForContactingTheDigiumSalesDepartment);
150                 WaitExten(0.3);
151                 Background(digium/PleaseHoldAndYourCallWillBeAnsweredByOurNextAvailableSalesRepresentative);
152                 WaitExten(0.3);
153                 Background(digium/AtAnyTimeYouMayPress0ToSpeakWithAnOperatorOr8ToLeaveAMessage);
154                 Set(CALLERID(name)=Sales);
155                 Queue(sales-general|t);
156                 Set(CALLERID(name)=EmptySalQ);
157                 goto dispatch|s|1;
158                 Playback(goodbye);
159                 Hangup();
160         }
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.
167 context customerservice {
169         0 => {
170                 SetCIDName(CSVTrans);
171                 goto dispatch|s|1;
172         }
173         8 => Voicemail(${CUSTSERVVM});
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         }
199 Note that calls coming into customerservice will first be try to queue
200 calls to those agents with a QUEUE_MAX_PENALTY of 10, and if none are available,
201 then all agents are rung.
204 context dispatch
207         s => {
208                 Ringing();
209                 Wait(2);
210                 Background(digium/ThankYouForCallingDigium);
211                 WaitExten(0.3);
212                 Background(digium/YourCallWillBeAnsweredByOurNextAvailableOperator);
213                 Background(digium/PleaseHold);
214                 Set(QUEUE_MAX_PENALTY=10);
215                 Queue(dispatch|t);
216                 Set(QUEUE_MAX_PENALTY=20);
217                 Queue(dispatch|t);
218                 Set(QUEUE_MAX_PENALTY=0);
219                 Queue(dispatch|t);
220                 Background(digium/NoOneIsAvailableToTakeYourCall);
221                 Background(digium/PleaseLeaveAMessageInOurGeneralVoiceMailBox);
222                 Voicemail(${DISPATCHVM});
223                 Playback(goodbye);
224                 Hangup();
225         }
228 And in the dispatch context, first agents of priority 10 are tried, then
229 20, and if none are available, all agents are tried. 
231 Notice that a common pattern is followed in each of the three queue contexts:
233 First, you set QUEUE_MAX_PENALTY to a value, then you call
234 Queue(<queue-name>,option,... (see the documentation for the Queue application));
236 In the above, note that the "t" option is specified, and this allows the 
237 agent picking up the incoming call the luxury of transferring the call to 
238 other parties.
240 The purpose of specifying the QUEUE_MAX_PENALTY is to develop a set of priorities
241 amongst agents. By the above usage, agents with lower number priorities will 
242 be given the calls first, and then, if no-one picks up the call, the QUEUE_MAX_PENALTY
243 will be incremented, and the queue tried again. Hopefully, along the line, someone
244 will pick up the call, and the Queue application will end with a hangup.
246 The final attempt to queue in most of our examples sets the QUEUE_MAX_PENALTY
247 to zero, which means to try all available agents.
250 =========================================
251 |      Assigning agents to Queues       |
252 =========================================
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.
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.
267 ================= Agents Log In and Out 
270 context queues-loginout
272         6092 => {
273                         Answer();
274                         Read(AGENT_NUMBER,agent-enternum);
275                         VMAuthenticate(${AGENT_NUMBER}@default,s);
276                         Set(queue-announce-success=1);
277                         goto queues-manip,I${AGENT_NUMBER},1;
278                 }
280         6093 => {
281                         Answer();
282                         Read(AGENT_NUMBER,agent-enternum);
283                         Set(queue-announce-success=1);
284                         goto queues-manip,O${AGENT_NUMBER},1;
285                 }
289 In the above contexts, the agents dial 6092 to log into their queues,
290 and they dial 6093 to log out of their queues. The agent is prompted
291 for their agent number, and if they are logging in, their passcode, 
292 and then they are transferred to the proper extension in the 
293 queues-manip context.  The queues-manip context does all the 
294 actual work:
297 context queues-manip {
299         // Raquel Squelch
300         _[IO]6121 => {
301                 &queue-addremove(dispatch,10);
302                 &queue-success();
303         }
305         // Brittanica Spears
306         _[IO]6165 => {
307                 &queue-addremove(dispatch,20);
308                 &queue-success();
309         }
311         // Rock Hudson
312         _[IO]6170 => {
313                 &queue-addremove(sales-general,10);
314                 &queue-addremove(customerservice,20);
315                 &queue-addremove(dispatch,30);
316                 &queue-success();
317         }
319         // Saline Dye-on
320         _[IO]6070 => {
321                 &queue-addremove(sales-general,20);
322                 &queue-addremove(customerservice,30);
323                 &queue-addremove(dispatch,30);
324                 &queue-success();
325         }
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.
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.
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.
345 The call to queue-success() gives some feedback to the agent
346 as they log in and out, that the process has completed.
348 macro queue-success()
350         if( ${queue-announce-success} > 0 )
351         {
352                 switch(${MACRO_EXTEN:0:1})
353                 {
354                 case I:
355                         Playback(agent-loginok);
356                         Hangup();
357                 case O:
358                         Playback(agent-loggedoff);
359                         Hangup();
360                 }
361         }
365 The queue-addremove macro is defined in this manner:
367 macro queue-addremove(queuename,penalty)
369         switch(${MACRO_EXTEN:0:1})
370         {
371         case I:  // Login
372                 {
373                 AddQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents,${penalty});
374                 }
375         case O:  // Logout
376                 {
377                 RemoveQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents);
378                 }
379         case P:  // Pause
380                 {
381                 PauseQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents);
382                 }
383         case U:  // Unpause
384                 {
385                 UnpauseQueueMember(${queuename},Local/${MACRO_EXTEN:1}@agents);
386                 }
387         default: // Invalid
388                 {
389                 Playback(invalid);
390                 }
391         }
394 Basically, it uses the first character of the MACRO_EXTEN variable, to determine the
395 proper actions to take. In the above dial plan code, only the cases I or O are used,
396 which correspond to the Login and Logout actions.
399 =======================================================
400 |    Controlling The Way Queues Call the Agents       |
401 =======================================================
403 Notice in the above, that the commands to manipulate agents in queues have
404 "@agents" in their arguments. This is a reference to the agents context:
406 context agents
408         // General sales queue
409         8010 =>
410         {
411                 Set(QUEUE_MAX_PENALTY=10);
412                 Queue(sales-general|t);
413                 Set(QUEUE_MAX_PENALTY=0);
414                 Queue(sales-general|t);
415                 Set(CALLERID(name)=EmptySalQ);
416                 goto dispatch|s|1;
417         }
418         // Customer Service queue
419         8011 =>
420         {
421                 Set(QUEUE_MAX_PENALTY=10);
422                 Queue(customerservice|t);
423                 Set(QUEUE_MAX_PENALTY=0);
424                 Queue(customerservice|t);
425                 Set(CALLERID(name)=EMptyCSVQ);
426                 goto dispatch|s|1;
427         }
428         8013 =>
429         {
430                 Dial(iax2/sweatshop/9456@from-ecstacy);
432                 Set(CALLERID(name)=EmptySupQ);
433                 Set(QUEUE_MAX_PENALTY=10);
434                 Queue(support-dispatch,t);
435                 Set(QUEUE_MAX_PENALTY=20);
436                 Queue(support-dispatch,t);
437                 Set(QUEUE_MAX_PENALTY=0); // means no max
438                 Queue(support-dispatch,t);
439                 goto dispatch|s|1;
440         }
441         6121 => &callagent(${RAQUEL});
442         6165 => &callagent(${SPEARS});
443         6170 => &callagent(${ROCK});
444         6070 => &callagent(${SALINE});
447 In the above, the variables ${RAQUEL}, etc stand for
448 actual devices to ring that person's
449 phone (like Zap/37).
451 The 8010, 8011, and 8013 extensions are purely for transferring
452 incoming callers to queues. For instance, a customer service 
453 agent might want to transfer the caller to talk to sales. The 
454 agent only has to transfer to extension 8010, in this case.
456 Here is the callagent macro, note that if a person in the
457 queue is called, but does not answer, then they are automatically
458 removed from the queue.
460 macro callagent(device)
462         if( ${GROUP_COUNT(${MACRO_EXTEN}@agents)}=0 )
463         {
464                 Set(OUTBOUND_GROUP=${MACRO_EXTEN}@agents);
465                 Dial(${device}|300|t);
466                 switch(${DIALSTATUS})
467                 {
468                 case BUSY:
469                         Busy();
470                         break;
471                 case NOANSWER:
472                         Set(queue-announce-success=0);
473                         goto queues-manip|O${MACRO_EXTEN}|1;
474                 default:
475                         Hangup();
476                         break;
477                 }
478         }
479         else
480         {
481                 Busy();
482         }
485 In the callagent macro above, the ${MACRO_EXTEN} will
486 be 6121, or 6165, etc, which is the extension of the agent.
488 The use of the GROUP_COUNT, and OUTBOUND_GROUP follow this line
489 of thinking. Incoming calls can be queued to ring all agents in the
490 current priority. If some of those agents are already talking, they
491 would get bothersome call-waiting tones. To avoid this inconvenience,
492 when an agent gets a call, the OUTBOUND_GROUP assigns that 
493 conversation to the group specified, for instance 6171@agents.
494 The ${GROUP_COUNT()} variable on a subsequent call should return
495 "1" for that group. If GROUP_COUNT returns 1, then the busy() 
496 is returned without actually trying to dial the agent.
498 ================ Pre Acknowledgement Message
500 If you would like to have a pre acknowledge message with option to reject the message
501 you can use the following dialplan Macro as a base with the 'M' dial argument.
503 [macro-screen]
504 exten=>s,1,Wait(.25)
505 exten=>s,2,Read(ACCEPT|screen-callee-options|1)
506 exten=>s,3,Gotoif($[${ACCEPT} = 1] ?50)
507 exten=>s,4,Gotoif($[${ACCEPT} = 2] ?30)
508 exten=>s,5,Gotoif($[${ACCEPT} = 3] ?40)
509 exten=>s,6,Gotoif($[${ACCEPT} = 4] ?30:30)
510 exten=>s,30,Set(MACRO_RESULT=CONTINUE)
511 exten=>s,40,Read(TEXTEN|custom/screen-exten|)
512 exten=>s,41,Gotoif($[${LEN(${TEXTEN})} = 3]?42:45)
513 exten=>s,42,Set(MACRO_RESULT=GOTO:from-internal^${TEXTEN}^1)
514 exten=>s,45,Gotoif($[${TEXTEN} = 0] ?46:4)
515 exten=>s,46,Set(MACRO_RESULT=CONTINUE)
516 exten=>s,50,Playback(after-the-tone)
517 exten=>s,51,Playback(connected)
518 exten=>s,52,Playback(beep)
520 ================ Caveats 
522 In the above examples, some of the possible error checking has been omitted,
523 to reduce clutter and make the examples clearer.