Contact Selection for Telephony in CCA
This document will describes how CCA determines the next contact to be called. The same method is used for all dialing modes (Manual, Preview, Progressive and Predictive).
This document is created using CCA v5.3.3.
The starting point for a new telephony contact is the outbound group. This group can be linked to a task (possibly through an IVR project), which can be linked to one or more sample lists.
When multiple sample lists are available, the system looks for the next best contact for each list, and then chooses the best one depending on the ‘finish list before using another one’ setting.
- If the setting is enabled, the system will look for a contact in lists sequentially (in the selected order), and use the first contact it finds.
- Otherwise the best contact will be retrieved from each list, and the one with the highest working priority will be used.
When contacts need to be compared, most of the time the ‘telephony working priority’ is used.
This priority is a combination of multiple values, and gives one ‘global’ priority value.
This value is also set to 0 when the contact should not be used anymore. This is mainly to improve performance of the database queries.
The exact calculation isn’t really important. For those who are interested, here is the formula currently used to calculate the telephony working priority:
Where . . .
- User priority - a value set by the user (defaults to 1).
- Order priority - a value between 0 and 1, depending on the list order.
- Appointment importance - a value between 1 and 5, or 0 if no appointment made.
- Call now - 1 if the contact needs to be called immediately , 0 otherwise.
Additionally, the telephony working priority is set to 0 in these cases:
- When the contact is over the current callback settings (either those defined in the settings, or due to a callback script).
- When the contact’s interview is complete.
- When the contact is in a quota category for which the target is reached.
- When the interview is filtered out.
- When the contact is on a do-not-call list.
- When the telephone number is empty.
- When the contact mode is neither telephony nor none.
Finding the best contact in the sample list
N.B.: if 'no agent' is applicable (e.g. for group-based predictive dialing), steps that mention an agent can be ignored.
The selection process goes like this:
- Check whether the list has available contacts within the agent’s skills – if not, abort.
- Look for the best quota categories to be used next (taking into account the agent’s skills and the amount of available contacts per quota and skill category).
The details go outside the scope of this document.
- Search for available contacts in the list which have an appointment, making sure they are within the agents’ skills, are allowed for the quota, and if the appointment can be taken by this agent.
- Search for available contacts which have ‘call now’ enabled.
- Search for regular available contacts.
- Compare the contacts from step (3), (4) and (5) by their working priority. The one with the highest working priority is taken.
- Update the contact’s dynamic fields (if any).
If any of these fields have a new value, the contact is discarded and we start again from step (1). This way we ensure that changed values, which could affect the skills, or quotas are taken into account.
Note: the callback script is not re-executed when dynamic fields have changed. This may change in a later version.
Contacts are only called when they are available. A contact can be available (or not) depending on quotas, skills, do-not-contact lists, interview filters, etc. The contact can also be temporarily unavailable due to callback rules. In this case it will become available again at the availability time or ‘time available’.
This ‘time available’ is determined by the call back rules and the call back script, and can be influenced by a lot of settings (like appointment settings, derivation, etc).
Here’s the way the contact availability and time available is determined:
- Process the call history using the call back rules.
- Run the call back script using the current values.
- If the contact is over call back, derive it.
We’ll go through the most important configuration settings which influence whether a contact is available or not, and when it becomes available.
The callback rules look like this:
The call back options determine the maximum number of attempts for each call result (and the total maximum amount of calls), and the delay after which the contact will be allowed to be called back.
A different setting can be selected per call back result. The maximum amount of call for all call results (and the total amount) is verified. The delay to determine the next time the contact is available is determined by the last call made for a contact.
If these settings are changed while a list is in use, all contacts will be re-evaluated to determine if they are still available, and when they will become available
These are the 3 possible settings for ‘next attempt’:
- After XXX: This is the simplest one; the time available will be the time the last call ended + the selected delay.
- After running XXX: This is similar to the previous option, but only the time where the list was actually running (with agents logged on) will be counted for the delay.
Example: If (in the example screenshot) the list was stopped for an hour, or there weren’t any agents logged in for an hour, a contact with ‘busy’ as last call result will become available 1h04m after the last call ended.
- Next shift: This will cause the next call to happen in the next shift.
This means that if the call happed 20% into shift #1, the contact will become available again 20% into the next upcoming shift #2. To achieve this the time available for this contact will be updated each time a shift ends, to a value of 20% within the new upcoming shift #2.
The shifts can be managed by clicking the ‘Create Shifts’ link (if there aren’t any shifts yet), or the ‘Edit Shifts’ link (if there are already shifts defined).
- Note that calls taken ‘outside’ a shift are handled as shift #0, with their percentage calculated relative to the ‘empty’ section.
So a call at 3h (in our screenshot) will be seen as 50% into shift #0. A call with ‘next shift’ configured as next attempt will become available 50% into shift #1 – so at 9h the same day.
You may also notice there is no ‘next attempt’ setting for appointments. This is normal, because the next attempt will obviously be is the appointment time.
Call (back) now
If an agent chooses the ‘call back now’ option, or ‘call now’ is chosen in find/edit contact, the contact will be called irrespective of any of the maximum number of attempts.
The script is evaluated for all contacts after every call, every time a field is modified, and every time any of the callback options are modified (including the script itself).
Using the callback script you can access (and modify) almost all contact data. This includes setting the exact callback time and/or shift, and whether the contact is called back at all. You can also modify most list fields, including telephone number and user priority.
You can influence whether the contact can be called back, and when it becomes available by changing the [Result.*] variables:
- [Result.IsOverCallback]: Defines whether the contact can still be called back.
- [Result.CallBackShift]: Sets the shift for the next call. If this value is -1, no shift is applied.
- [Result.CallBackTime]: Sets the exact time the contact becomes available again for telephony. If this value is empty (or Nothing in vbscript), and there are shifts configured, this time will be calculated using the [Result.CallBackShift].
This allows you (for example) to call back is a specific shift by setting the callback shift, and resetting the callback time.
Note that these variables are initialized by applying the regular call back rules, as described earlier.
A few other interesting parameters:
- [Contact.CallCount]: The total number of calls made for this contact (within the current derivation).
- [Contact.Priority]: The user priority for the contact.
- [Contact.CallBackIdleTime]: The total time (in seconds) the list has been idle since the last call. This can be used to replicate the ‘after running ’ regular call back rule.
- [CallHistory.arrCallResult]: An array with the main result code for each call.
- [Configuration.arrMaxCallAttempts]: An array with one item per call result containing the maximum nr of attempts as configured for this list.
We’ll include some interesting scripts to illustrate the possibilities and usefulness of this feature.
Calling fresh contacts
By manipulating the user priority it is possible to prefer certain contacts before other ones (if they are within the same quota category).
Because the callback script is only executed after the first call, you should reduce the priority of used contacts so they have a lower working priority than the others.
To do this for all contacts you can use this simple script:
If [Contact.Priority] > 0 Then
[Contact.Priority] = 0.5
Stop dialing in a special case
This can be done by setting [Result.IsOverCallback] to True in certain cases.
Say we want to stop dialing if we get a no answer immediately after a busy:
If [Contact.CallCount] > 1 Then
For callNr = 1 To [Contact.CallCount] - 1 If ([CallHistory.arrCallResult](callNr - 1) = 2 And [CallHistory.arrCallResult](callNr) = 3) Then
[Result.IsOverCallback] = True
Store the call history in a text field
'helper functions Function myDateFormat(myDate) Dim d, m, y, hh, mm, ss d = Pad0(Day(myDate)) m = Pad0(Month(myDate)) y = Year(myDate) hh = Pad0(Hour(myDate)) mm = Pad0(Minute(myDate)) ss = Pad0(Second(myDate)) myDateFormat = y & "-" & m & "-" & d & " " & hh & ":" & mm & ":" & ss End Function Function Pad0(num) If (Len(num) = 1) Then Pad0 = "0" & num Else Pad0 = num End If End Function Function PadRight(text, length) PadRight = text & Space(length - Len(text)) End Function If ([Contact.CallCount] > 0) Then 'header [ListFields.CallHistory] = "Call History:" & vbCrLf & "=============" & vbCrLf [ListFields.CallHistory] = [ListFields.CallHistory] & "Call Time Agent Result" & vbCrLf [ListFields.CallHistory] = [ListFields.CallHistory] & "---- -------------------- ------------------------------ ------" & vbCrLf 'create new call history Dim callNr, callTime For callNr = 0 To [Contact.CallCount] - 1 'index [ListFields.CallHistory] = [ListFields.CallHistory] & PadRight(CStr(callNr + 1), 5) 'time [ListFields.CallHistory] = [ListFields.CallHistory] & PadRight(myDateFormat([CallHistory.arrCallTime](callNr)), 21) 'agent [ListFields.CallHistory] = [ListFields.CallHistory] & PadRight([CallHistory.arrCallAgentName](callNr), 31) 'result [ListFields.CallHistory] = [ListFields.CallHistory] & PadRight("(" & [CallHistory.arrCallResult](callNr) & ", " & [CallHistory.arrCallSubResult](callNr) & ")", 7) 'end [ListFields.CallHistory] = [ListFields.CallHistory] & vbCrLf Next End If
Call missed appointments on the requested hour
If a call after an appointment doesn’t succeed, this script will make sure the next call happens after the configured delay for the call result, but +/- on the original appointment’s hour.
So if an appointment was set for 16h, but nobody picked up (no answer, delay = 1h), instead of making the appointment available in1h, the contact will become available in 24h.
If Not [Result.IsOverCallback] And [CallHistory.LastCallResult]<>0 And [CallHistory.LastCallResult]<>9 Then 'not over callback and no success or appointment If [Contact.IsAppointmentTaken] Then 'appointment made in the past If TimeValue([Result.CallBackTime]) <= TimeValue([Contact.AppointmentTime]) Then [Result.CallBackTime] = DateValue([Result.CallBackTime]) + TimeValue([Contact.AppointmentTime]) Else [Result.CallBackTime] = DateAdd("d",1,DateValue([Result.CallBackTime])) + TimeValue([Contact.AppointmentTime]) End If End If End If
We’ll go over some appointment options which affect the callbacks:
The ‘call back’ section determines which agent is allowed to call back the appointment. The options speak for themselves. One note: the options ‘call back by same agent if …’ should be interpreted as ‘if not, call back by any agent’.
The check box ‘call back by any agent after XXX’ provides a fall-back in case the preferred agent isn’t available for a long time.
The options ‘always call an appointment in spite of quota’ and ‘ignore skills when calling back an appointment’ are self-explanatory.
The setting ‘always blank-out interview data’ does exactly that: when an appointment is called back, the previous interview data is discarded, and a new (empty) interview is started.
The ‘call-back waiting time decrease’ will reduce the delay for call backs made after an appointment.
For example: if the call back delay for a ‘busy’ is set to 1 hour, and the ‘waiting time decrease’ is set to 75%, the actual delay used will be 15 minutes.
One last option which affects the call backs is contact derivation.
Using contact derivation it is possible to now make a new attempt calling the contact after it failed the call back rules, using a different phone number.
This can be configured on the ‘numbers’ tab, in the sample list properties:
For the sample list in the above screenshot, the system will first try reaching the contact using the regular phone number. When that fails, the system will try again using first GSM and then ntel AFTER. In case a call ends with success, refused or quota reached, the system will stop trying entirely.
Each time the system derives the contact (so when it switches from the regular phone number to GSM, and when it switches from GSM to ntel) the next attempt will be done 1 hour after the last call.
The derivation can also be accessed (and manipulated) using the callback script using the [Contact.Derivation] field. Note that the [CallHistory.*] variables contain the call history within the current derivation, while the [FullCallHistory.*] variables contain all the calls. The same difference applies to [Contact.CallCount] and [Contact.FullCallCount].