Flujos de Campañas
Salientes
Desde Agente con hardphone
${OUTGUID}: GUID de la llamada que se genera.
${OUTAGENT}: Nombre del agente que realiza la llamada.
${OUTQUEUE}: Nombre de la campaña por la que sale la llamada.
${OUTDID}: DID número callerid para usar al salir, corresponde al de la campaña.
${OUDIDALED}: Número marcado.
Con teléfono Webrtc
La llamada se realiza directamente. El nombre de la campaña, GUID y DID se pueden obtener desde un SIP Header, el resto de las variables son obtenidas directamente desde donde corresponden.
${SIP_HEADER(OUTGUID)}: GUID de la llamada que se genera.
${CDR(accountcode)}: Nombre del agente que realiza la llamada.
${SIP_HEADER(OUTQUEUE)}: Nombre de la campaña.
${SIP_HEADER(OUTDID)}: DID número callerid para usar al salir corresponde al de la campaña.
${EXTEN}: Número marcado.
Ejemplo completo de ambos casos
Podemos ver las variables que se ejecutan y como se toman en cuenta las que llegan, dependiendo del modo en el que se ejecute el agente.
Es importante usar __Ani para poder buscar en Logs.
El QueueUpdate en el Hangup es fundamenta por temas de estadísticas de campañas salientes.
En Hangup también agregar Set(CDR(userfield)=${userfield}) para marcar la grabación.
Es posible ejecutar en el Dial un Macro para enviar datos al cliente una vez la llamada es atendida.
exten=> _9XXXXXXX.,1,Set(VOLUME(TX)=2)
exten=> _9XXXXXXX.,2,Set(VOLUME(RX)=2)
exten=> _9XXXXXXX.,3,GotoIf($[${EXTEN:0:3}= 900]?62:4)
exten=> _9XXXXXXX.,4,GotoIf($["${OUTQUEUE}"= ""]?47:5)
exten=> _9XXXXXXX.,5,Set(__OUTQUEUE=${OUTQUEUE})
exten=> _9XXXXXXX.,6,Set(__DIALED=${OUTDIALED})
exten=> _9XXXXXXX.,7,Set(__AGENT=${OUTAGENT})
exten=> _9XXXXXXX.,8,Set(CALLERID(num)=${OUTDID})
exten=> _9XXXXXXX.,9,Set(CALLERID(name-pres)=allowed_passed_screen)
exten=> _9XXXXXXX.,10,Set(HASH(Result)=${ODBC_Data(select did\,name\,dialstring from queues where name in (select queue_name from queue_members where membername = '${CHANNEL(accountcode)}') and direction = 'Outbound' and name ='${OUTQUEUE}')})
exten=> _9XXXXXXX.,11,Set(CALLERID(name)=${OUTQUEUE})
exten=> _9XXXXXXX.,12,Set(event=${ODBC_Data(select event from queue_log where agent = '${AGENT}' and queuename= '${OUTQUEUE}' and event in ('PAUSE', 'UNPAUSE') ORDER BY id DESC LIMIT 1)})
exten=> _9XXXXXXX.,13,GotoIf($["${event}" = "PAUSE"]?45:14)
exten=> _9XXXXXXX.,14,GotoIf($["${OUTGUID}" = ""]?40:15)
exten=> _9XXXXXXX.,15,Set(__guid=${OUTGUID})
exten=> _9XXXXXXX.,16,Set(CDR(guid)=${guid})
exten=> _9XXXXXXX.,17,Set(CDR(type)=record)
exten=> _9XXXXXXX.,18,MixMonitor(${guid}.gsm,b,)
exten=> _9XXXXXXX.,19,Set(CDR(campaign)=${OUTQUEUE})
exten=> _9XXXXXXX.,20,Set(CHANNEL(accountcode)=${AGENT})
exten=> _9XXXXXXX.,21,Set(__idLlamada=${guid})
exten=> _9XXXXXXX.,22,Set(__REALDIALED=${EXTEN:1})
exten=> _9XXXXXXX.,23,Set(existeNum=${ODBC_Data(SELECT COUNT(*) FROM black_list WHERE (campaign like '${OUTQUEUE}%' || campaign ='*') AND phone ='${EXTEN}')})
exten=> _9XXXXXXX.,24,GotoIf($["${existeNum}"!= "0"]?37:25)
exten=> _9XXXXXXX.,25,Dial(${HASH(Result,dialstring)}/${EXTEN:1},180,TKkc,)
exten=> _9XXXXXXX.,26,Set(CDR(causecode)=${HANGUPCAUSE})
exten=> _9XXXXXXX.,27,NoOp(${DIALSTATUS} - ${HANGUPCAUSE})
exten=> _9XXXXXXX.,28,GotoIf($["${DIALSTATUS}" = "BUSY"]?35:29)
exten=> _9XXXXXXX.,29,GotoIf($["${DIALSTATUS}" = "CONGESTION"]?35:30)
exten=> _9XXXXXXX.,30,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL"]?33:31)
exten=> _9XXXXXXX.,31,GotoIf($["${DIALSTATUS}" = "CANCEL"]?33:32)
exten=> _9XXXXXXX.,32,Hangup()
exten=> _9XXXXXXX.,33,Playback(outofservice,)
exten=> _9XXXXXXX.,34,Goto(agentes,${EXTEN},32)
exten=> _9XXXXXXX.,35,Playback(busy,)
exten=> _9XXXXXXX.,36,Goto(agentes,${EXTEN},32)
exten=> _9XXXXXXX.,37,Set(dummy=${ODBC_Repo(INSERT INTO black_list_history(calldate\,src\,dst) VALUES (now()\,'${AGENT}'\,'${EXTEN}'))})
exten=> _9XXXXXXX.,38,Playback(DNCRaudio,)
exten=> _9XXXXXXX.,39,Goto(agentes,${EXTEN},32)
exten=> _9XXXXXXX.,40,GotoIf($["${SIP_HEADER(OUTGUID)}" = ""]?43:41)
exten=> _9XXXXXXX.,41,Set(__guid=${SIP_HEADER(OUTGUID)})
exten=> _9XXXXXXX.,42,Goto(agentes,${EXTEN},16)
exten=> _9XXXXXXX.,43,GUID(__guid)
exten=> _9XXXXXXX.,44,Goto(agentes,${EXTEN},16)
exten=> _9XXXXXXX.,45,Playback(pausaerror,)
exten=> _9XXXXXXX.,46,Hangup()
exten=> _9XXXXXXX.,47,GotoIf($[$["${SIP_HEADER(OUTQUEUE)}"= ""]|$["${SIP_HEADER(OUTQUEUE)}"= "null"]]?53:48)
exten=> _9XXXXXXX.,48,Set(__AGENT=${CHANNEL(accountcode)})
exten=> _9XXXXXXX.,49,Set(__DIALED=${EXTEN})
exten=> _9XXXXXXX.,50,Set(__OUTQUEUE=${SIP_HEADER(OUTQUEUE)})
exten=> _9XXXXXXX.,51,Set(CALLERID(num)=${SIP_HEADER(OUTDID)})
exten=> _9XXXXXXX.,52,Goto(agentes,${EXTEN},9)
exten=> _9XXXXXXX.,53,Set(HASH(Result)=${ODBC_Data(select did\,name\,dialstring from queues where name in (select queue_name from queue_members where membername = '${CHANNEL(accountcode)}') and direction = 'Outbound')})
exten=> _9XXXXXXX.,54,GotoIf($["${HASH(Result,name)}"= ""]?60:55)
exten=> _9XXXXXXX.,55,Set(__AGENT=${CHANNEL(accountcode)})
exten=> _9XXXXXXX.,56,Set(__DIALED=${EXTEN})
exten=> _9XXXXXXX.,57,Set(__OUTQUEUE=${HASH(Result,name)})
exten=> _9XXXXXXX.,58,Set(CALLERID(num)=${HASH(Result,did)})
exten=> _9XXXXXXX.,59,Goto(agentes,${EXTEN},9)
exten=> _9XXXXXXX.,60,Background(llamadasincola,,,)
exten=> _9XXXXXXX.,61,Hangup()
exten=> _9XXXXXXX.,62,Set(inter-var=${DB(${CALLERID(num)}/INTER)})
exten=> _9XXXXXXX.,63,GotoIf($["${inter-var}" = "TRUE"]?4:64)
exten=> _9XXXXXXX.,64,Playback(disabled-INTER,)
exten=> _9XXXXXXX.,65,Hangup()
exten=> h,1,Set(HASH(rates)=${ODBC_Data(select rates.gateway\, rates.rate\, rates.cost\, rates.note FROM rates LEFT JOIN provider ON provider.name=rates.gateway WHERE provider.status = 'true' AND substring( '${EXTEN}'\, 1\, length( prefix_regexp ) ) REGEXP prefix_regexp ORDER BY length(prefix_regexp) DESC\,rates.rate ASC)})
exten=> h,2,Set(talkedminutes=${MATH(${CDR(billsec)} / 60,f)})
exten=> h,3,Set(talkedminutes=$[CEIL(${talkedminutes})])
exten=> h,4,Set(chargedbalance=${MATH(${talkedminutes} * ${HASH(rates,rate)},f)})
exten=> h,5,Set(realbalance=${MATH(${talkedminutes} * ${HASH(rates,cost)},f)})
exten=> h,6,Set(CDR(charged_balance)=${chargedbalance})
exten=> h,7,Set(CDR(real_balance)=${realbalance})
exten=> h,8,Set(CDR(note)=${HASH(rates,note)})
exten=> h,9,Set(CDR(carrier)=${HASH(rates,gateway)})
exten=> h,10,Set(CDR(userfield)=${userfield})
exten=> h,11,Set(CDR(direction)=outgoing)
exten=> h,12,Set(CDR(causecode)=${HANGUPCAUSE})
exten=> h,13,QueueUpdate(${OUTQUEUE},${UNIQUEID},${AGENT},${DIALSTATUS},${ANSWEREDTIME},${DIALEDTIME}|${DIALED}|${idLlamada})
En la creación de campañas se define el Form o la URL que hay que desplegar al hacer clic en el botón de formularios de esta.
Opción 1: uContact Form: Solo nombre del form, Nombre del form y | true (para desplegar la cruz del form y poder cerrarlo).
Ejemplos: Códigos | true
Códigos
Opcion 2: uContact URL: URL bien formada y | nombre a mostrar en Tab o URL bien formada | nombre del tab | true (esto para desplegar la cruz del form y poder cerrarlo)
Ejemplos: http://www.observador.com.uy | Observa
http://www.observador.com.uy | Observa | true
Entrantes
Podemos ver el workflow de ejecución.
Es fundamental utilizar __Ani para poder buscar en Logs.
Ya no empleamos más MACRO para pasar datos de CTI, sino SIP HEADER. Esta se persiste durante toda la llamada, si es una transferencia también debería pasar los datos, también es posible eliminar el HEADER.
Ejemplo:
exten=> _XXXXXXXX,1,Set(HASH(queue)=${ODBC_Data(SELECT welcome\, schedule \, name \, form \, interactions FROM queues WHERE did= '${EXTEN}' AND direction = 'inbound')})
exten=> _XXXXXXXX,2,Set(CHANNEL(Language)=es)
exten=> _XXXXXXXX,3,Set(__Ani=${CALLERID(num)})
exten=> _XXXXXXXX,4,Set(CDR(campaign)=${HASH(queue,name)})
exten=> _XXXXXXXX,5,Answer(0)
exten=> _XXXXXXXX,6,Set(sound=${ODBC_Data(select sound from holidays WHERE day = '${STRFTIME(${EPOCH},,%d)}' AND month = '${STRFTIME(${EPOCH},,%m)}' AND (year = '${STRFTIME(${EPOCH},,%Y)}' OR year = '*') AND substring(timerange,1,5) <= '${STRFTIME(${EPOCH},,%R)}' AND substring(timerange,7) >= '${STRFTIME(${EPOCH},,%R)}' AND (campaign ='*' OR campaign ='${CDR(campaign)}'))})
exten=> _XXXXXXXX,7,GotoIf($["${sound}"=""]?11:8)
exten=> _XXXXXXXX,8,Playback(${sound},)
exten=> _XXXXXXXX,9,VoiceMail(1000@voicemail,)
exten=> _XXXXXXXX,10,Hangup()
exten=> _XXXXXXXX,11,Set(__DID=${EXTEN})
exten=> _XXXXXXXX,12,Set(__VirtualHold=${HASH(queue,interactions)})
exten=> _XXXXXXXX,13,Set(welcome=${HASH(queue,welcome)})
exten=> _XXXXXXXX,14,Set(Bienvenida=${CUT(welcome,\;,1)})
exten=> _XXXXXXXX,15,Set(FueraDeHora=${CUT(welcome,\;,2)})
exten=> _XXXXXXXX,16,Set(schedule=${HASH(queue,schedule)})
exten=> _XXXXXXXX,17,Set(cantidad=${FIELDQTY(schedule,&)})
exten=> _XXXXXXXX,18,Set(dentroDeHora=0)
exten=> _XXXXXXXX,19,While($[${cantidad} >0 && ${dentroDeHora} = 0])
exten=> _XXXXXXXX,20,Set(date=${CUT(schedule,\&,${cantidad})})
exten=> _XXXXXXXX,21,Set(hourrange=${CUT(date,\;,2)})
exten=> _XXXXXXXX,22,Set(dayrange=${CUT(date,\;,1)})
exten=> _XXXXXXXX,23,Set(cantidad=${MATH(${cantidad} - 1,i)})
exten=> _XXXXXXXX,24,GotoIfTime(${hourrange},${dayrange},,?,${EXTEN},42)
exten=> _XXXXXXXX,25,EndWhile()
exten=> _XXXXXXXX,26,GotoIf($[${dentroDeHora}=1]?29:27)
exten=> _XXXXXXXX,27,Playback(${FueraDeHora},)
exten=> _XXXXXXXX,28,Goto(entrantes,${EXTEN},9)
exten=> _XXXXXXXX,29,Playback(${Bienvenida},)
exten=> _XXXXXXXX,30,GUID(__guid)
exten=> _XXXXXXXX,31,Set(CDR(guid)=${guid})
exten=> _XXXXXXXX,32,Set(CDR(type)=record)
exten=> _XXXXXXXX,33,Set(MONITOR_FILENAME=${guid})
exten=> _XXXXXXXX,34,Set(CALLERID(name)=${HASH(queue,name)})
exten=> _XXXXXXXX,35,SipAddHeader(CTI: {"Guid": "${guid}" , "Screen": "FALSE" , "Form": "${HASH(queue,form)}" , "Campaign" : "${CDR(campaign)}" , "Callerid" : "${CALLERID(num)}" , "ParAndValues" : "par1=val1:par2=val2:par3=val3" , "Beep" : "FALSE" , "Answer" : "FALSE"})
exten=> _XXXXXXXX,36,SipAddHeader(VIDEO : ${SIP_HEADER(VIDEO)})
exten=> _XXXXXXXX,37,Queue(${CDR(campaign)},tTkKc,,,600,,,,,)
exten=> _XXXXXXXX,38,Read(__customerfeedback,feedback,2,,2,10)
exten=> _XXXXXXXX,39,GotoIf($["${customerfeedback}"=""]?41:40)
exten=> _XXXXXXXX,40,Set(customerfeedback=${ODBC_Repo(INSERT INTO customer_feedback(`datetime`\,agent\,campaign\,guid\,interaction\,qualification\,comment\,`from`) VALUES (NOW()\,'${CDR(accountcode)}'\,'${CDR(campaign)}'\,'${guid}'\,'call'\,'${customerfeedback}'\,''\,'${CALLERID(num)}'))})
exten=> _XXXXXXXX,41,Hangup()
exten=> _XXXXXXXX,42,Set(dentroDeHora=1)
exten=> _XXXXXXXX,43,Goto(entrantes,${EXTEN},25)
exten=> h,1,Set(CHANNEL(accountcode)=${MEMBERNAME})
exten=> h,2,Set(CDR(userfield)=${userfield})
exten=> h,3,Set(CDR(direction)=incoming)
exten=> h,4,Set(CDR(causecode)=${HANGUPCAUSE})
exten=> h,5,NoOp()
exten=> h,6,GotoIf($["${customerfeedback}"=""]?8:7)
exten=> h,7,Set(dummy=${ODBC_Repo(UPDATE customer_feedback set agent = '${CDR(accountcode)}' WHERE guid = '${guid}')})
exten=> h,8,GotoIf($["${ABANDONED}" == "TRUE" & "${VirtualHold}" == "VirtualHold" ]?10:9)
exten=> h,9,Hangup()
exten=> h,10,VirtualHold(Local/${CDR(campaign)}@virtualhold/n,${UNIQUEID},virtualhold,${Ani},1,${CDR(campaign)},)
exten=> h,11,Goto(entrantes,${EXTEN},9)
Si se quiere autoanswer para hardphones, setear el SIP Header: P-Auto-Answer: normal.
En el SIPAddHeader setear form o URL que hay que desplegar al entrar una llamada.
Opción 1: uContact Form: Solo nombre del Form, Nombre del Form y | true (para desplegar la cruz del form y poder cerrarlo).
Ejemplos: Códigos
Códigos | true
exten=> _XXXXXXXX,34,SipAddHeader(CTI: {"Guid": "${guid}" , "Screen": "FALSE" , "Form": "Codigos" , "Campaign" : "${CDR(campaign)}" , "Callerid" : "${CALLERID(num)}" , "ParAndValues" : "par1=val1-par2=val2-par3=val3" , "Beep" : "TRUE" , "Answer" : "FALSE"})
exten=> _XXXXXXXX,34,SipAddHeader(CTI: {"Guid": "${guid}" , "Screen": "FALSE" , "Form": "Codigos | true" , "Campaign" : "${CDR(campaign)}" , "Callerid" : "${CALLERID(num)}" , "ParAndValues" : "par1=val1-par2=val2-par3=val3" , "Beep" : "TRUE" , "Answer" : "FALSE"})
Opcion 2: uContact URL: URL bien formada y | nombre a mostrar en tab o URL bien formada | nombre del tab | true (para desplegar la cruz del form y poder cerrarlo).
Ejemplos: http://www.observador.com.uy | Observa
http://www.observador.com.uy | Observa | true
exten=> _XXXXXXXX,34,SipAddHeader(CTI: {"Guid": "${guid}" , "Screen": "FALSE" , "Form": " http://www.observador.com.uy | Observa" , "Campaign" : "${CDR(campaign)}" , "Callerid" : "${CALLERID(num)}" , "ParAndValues" : "par1=val1-par2=val2-par3=val3" , "Beep" : "TRUE" , "Answer" : "FALSE"})
exten=> _XXXXXXXX,34,SipAddHeader(CTI: {"Guid": "${guid}" , "Screen": "FALSE" , "Form": " http://www.observador.com.uy | Observa | true" , "Campaign" : "${CDR(campaign)}" , "Callerid" : "${CALLERID(num)}" , "ParAndValues" : "par1=val1-par2=val2-par3=val3" , "Beep" : "TRUE" , "Answer" : "FALSE"})
Avanzadas
Ir primero a un agente
Setear en los agentes diferentes números de penalización (número de teléfono del agente).
Setear en la campaña la estrategia wrandom.
En el workflow setear las variables con el mismo número (el de la penalización del agente por el que se quiere comenzar), y en el workflow en la actividad de campaña setear la regla que se quiera o sea la que está entre [] en el archivo queuerules.conf.
QUEUE_MIN_PENALTY y QUEUE_MAX_PENALTY
En /etc/asterisk/queuerules.conf agregar una regla que después de X tiempo si no lo pudo contactar comience a saltar por los agentes disponibles.
[regla]
penaltychange => 30,+1000,-1000
Significa:
Después de 30 segundos, ajustar las variables QUEUE_MAX_PENALTY en +1000 y ajustar QUEUE_MIN_PENALTY en -1000.
Esto hace que luego de este tiempo ya salte entre otros agentes.
Ejemplo
exten=> _XXXXXX,1,Set(VOLUME(TX)=2)
exten=> _XXXXXX,2,Set(VOLUME(RX)=2)
exten=> _XXXXXX,3,Set(CHANNEL(Language)=es)
exten=> _XXXXXX,4,Set(__Ani=${CALLERID(num)})
exten=> _XXXXXX,5,Set(CDR(campaign)=CobrosG10->)
exten=> _XXXXXX,6,Answer(0)
exten=> _XXXXXX,7,Read(extension,MenuOpciones,4,,2,5)
exten=> _XXXXXX,8,Set(QUEUE_MAX_PENALTY=${extension:0:4})
exten=> _XXXXXX,9,Set(QUEUE_MIN_PENALTY=${extension:0:4})
exten=> _XXXXXX,10,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)
exten=> _XXXXXX,11,GotoIfTime(08:00-23:00,mon-fri,,?,${EXTEN},19)
exten=> _XXXXXX,12,GotoIfTime(08:00-12:00,sat-sat,,?,${EXTEN},16)
exten=> _XXXXXX,13,Playback(exceltecFuerahorario,)
exten=> _XXXXXX,14,VoiceMail(1000@voicemail,)
exten=> _XXXXXX,15,Hangup()
exten=> _XXXXXX,16,Set(CALLERID(num)=40322386)
exten=> _XXXXXX,17,Dial(SIP/tigo/25872587,60,tT,)
exten=> _XXXXXX,18,Hangup()
exten=> _XXXXXX,19,GUID(__guid)
exten=> _XXXXXX,20,Set(__idLlamada=${guid})
exten=> _XXXXXX,21,Set(CDR(guid)=${guid})
exten=> _XXXXXX,22,Set(CDR(type)=record)
exten=> _XXXXXX,23,Set(MONITOR_FILENAME=${guid})
exten=> _XXXXXX,24,Set(CALLERID(name)=Ventas_Inbbd_2)
exten=> _XXXXXX,25,Queue(Ventas_Inbbd_2<-,tTkK,,,400,,CTI,,regla,)
exten=> _XXXXXX,26,Hangup()