Distincion de Cortes en freePBX

may 12

Distincion de Cortes en freePBX
Soy usuario de freePBX desde hace ya unos años, y lo conocí cuando hice las primeras implementaciones con trixbox 1.2.2 (A.K.A. Asterisk@Home), siempre me ha molestado el hecho de que en freePBX cuando una llamada no puede ser cursada aparece un mensaje “No hay Lineas Disponibles” o algun otro mensaje que nada tiene que ver con la real causa de la no comunicación, esto puede ser exponencialmente mas molesto cuando esta implementación se encuentra en un callcenter. Es por eso que hice una pequela modificacion a la macro de marcado de freePBX para que no me envíe a la grabación por defecto cada vez que no me puedo comunicar si no que me entregue grabaciones predefinidas para cada tipo de error.
Probablemente haga de esto un modulo para freePBX quizá no, el procedimiento que aqui entrego es relativamente peligroso, si eres principiante respalda todos los archivos que vayas a modificar, si no eres tan principiante me imagino que no es necesario recordartelo :)
La teoría dice que cada vez que tu llamada no puede ser cursada, esta emite un codigo de error (similar a los números en HTTP, recuerdan 404?), este codigo corresponde a un codigo isdn y está muy documentado (Voip-Info, ISDN Cause Codes, Cisco).
Si estan en chile Telefonica reemplaza el tono de ocupado por un mensaje “El número que está llamando no tiene teléfono”, este es un claro ejemplo de una implementacion de “Cause Codes”.
Lo que me pidieron en un CallCenter fue cambiar el odioso mensaje de freePBX “No hay lineas disponibles” a su respectiva razón de no comunicación, ya que esta información era parte de su operación diaria. Lo primero que hice fue agrupar codigos de causa en algunos grupos que parezcan lógicos entre sí, de esta forma me quedó lo siguiente

No Existe: 1
No Disponible: 2, 3, 6, 31, 38, 41, 42, 43, 21
Ocupado: 17, 34, 44
No Contesta: 18, 19
Cambiado: 22
Ya no Existe: 27
Incorrecto: 28, 88, 95
Error en La red: 102, 111, 127

Esta agrupación se hizo en conjunto con las personas del CallCenter y la agrupación se realizó en la base de lo que era lógico para ellos y su operación. Estos grupos pueden cambiar y no significa que se use de esta forma.
Luego de tener los grupos, se le pidió a una operadora del callcenter que hiciera una serie de grabaciones indicando el error para cada uno de los grupos, de esta forma logramos reducir 23 de los 127 errores más frecuentes a tan sólo 8 grabaciones.
A partir de freePBX 2.3 existe el archivo extensions_override_freepbx.conf, en este archivo copié la macro que realiza el discado (la que efectivamente ejecuta el comando Dial) y la pegué en este archivo (para versiones anteriores a la 2.3, esta macro se encuentra en extensions.conf y este archivo no es sobreescrito en cada reload)
[macro-dialout-trunk]
include => macro-dialout-trunk-custom
exten => s,1,Set(DIAL_TRUNK=${ARG1})
exten => s,n,ExecIf($[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]],Authenticate,${ARG3})
exten => s,n,GotoIf($["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]?disabletrunk,1)
exten => s,n,Set(DIAL_NUMBER=${ARG2})
exten => s,n,Set(DIAL_TRUNK_OPTIONS=${DIAL_OPTIONS})
exten => s,n,Set(GROUP()=OUT_${DIAL_TRUNK})
exten => s,n,GotoIf($["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]?nomax)
exten => s,n,GotoIf($[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} > ${OUTMAXCHANS_${DIAL_TRUNK}} ]?chanfull)
exten => s,n(nomax),GotoIf($["${INTRACOMPANYROUTE}" = "YES"]?skipoutcid)
exten => s,n,Set(DIAL_TRUNK_OPTIONS=${TRUNK_OPTIONS})
exten => s,n,Macro(outbound-callerid,${DIAL_TRUNK})
exten => s,n(skipoutcid),AGI(fixlocalprefix)
exten => s,n,Set(OUTNUM=${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER})
exten => s,n,Set(custom=${CUT(OUT_${DIAL_TRUNK},:,1)})
exten => s,n,GotoIf($[$["${MOHCLASS}" = "default"] | $["foo${MOHCLASS}" = "foo"]]?gocall)
exten => s,n,Set(DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS})
exten => s,n(gocall),Macro(dialout-trunk-predial-hook,)
exten => s,n,GotoIf($["${PREDIAL_HOOK_RET}" = "BYPASS"]?bypass,1)
exten => s,n,GotoIf($["${custom}" = "AMP"]?customtrunk)
exten => s,n,Dial(${OUT_${DIAL_TRUNK}}/${OUTNUM},300,${DIAL_TRUNK_OPTIONS})
exten => s,n,Goto(s-${HANGUPCAUSE},1) ; Modificacion de Mario
;exten => s,n,Goto(s-${DIALSTATUS},1) ; Linea Original freePBX
exten => s,n(customtrunk),Set(pre_num=${CUT(OUT_${DIAL_TRUNK},$,1)})
exten => s,n,Set(the_num=${CUT(OUT_${DIAL_TRUNK},$,2)})
exten => s,n,Set(post_num=${CUT(OUT_${DIAL_TRUNK},$,3)})
exten => s,n,GotoIf($["${the_num}" = "OUTNUM"]?outnum:skipoutnum)
exten => s,n(outnum),Set(the_num=${OUTNUM})
exten => s,n(skipoutnum),Dial(${pre_num:4}${the_num}${post_num},300,${DIAL_TRUNK_OPTIONS})
exten => s,n,Goto(s-${DIALSTATUS},1)
exten => s,n(chanfull),Noop(max channels used up)
; INICIO MODIFICACIONES MARIO

; NUMERO NO EXISTE
exten => s-1,1,NoOp(Mario Dice: Numero No Existe)
exten => s-1,n,Playback(custom/numero-no-existe,noanswer)
exten => s-1,n,Busy(20)

;NUMERO NO ESTA DISPONIBLE
exten => s-2,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-2,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-2,n,Busy(20)

exten => s-3,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-3,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-3,n,Busy(20)

exten => s-6,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-6,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-6,n,Busy(20)

exten => s-31,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-31,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-31,n,Busy(20)

exten => s-38,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-38,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-38,n,Busy(20)

exten => s-41,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-41,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-41,n,Busy(20)

exten => s-42,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-42,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-42,n,Busy(20)

exten => s-43,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-43,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-43,n,Busy(20)

exten => s-21,1,NoOp(Mario Dice: Numero No Esta Disponible)
exten => s-21,n,Playback(custom/numero-no-disponible,noanswer)
exten => s-21,n,Busy(20)

; NUMERO OCUPADO
exten => s-17,1,NoOp(Mario Dice: Numero Ocupado)
exten => s-17,n,Playback(custom/numero-ocupado,noanswer)
exten => s-17,n,Busy(20)

exten => s-34,1,NoOp(Mario Dice: Numero Ocupado)
exten => s-34,n,Playback(custom/numero-ocupado,noanswer)
exten => s-34,n,Busy(20)

exten => s-44,1,NoOp(Mario Dice: Numero Ocupado)
exten => s-44,n,Playback(custom/numero-ocupado,noanswer)
exten => s-44,n,Busy(20)

; NUMERO NO CONTESTA
exten => s-18,1,NoOp(Mario Dice: Numero No Contesta)
exten => s-18,n,Playback(custom/numero-no-contesta,noanswer)
exten => s-18,n,Playback(pls-try-call-later,noanswer)
exten => s-18,n,Busy(20)

exten => s-19,1,NoOp(Mario Dice: Numero No Contesta)
exten => s-19,n,Playback(custom/numero-no-contesta,noanswer)
exten => s-19,n,Busy(20)

;NUMERO CAMBIADO
exten => s-22,1,NoOp(Mario Dice: Numero Cambiado)
exten => s-22,n,Playback(custom/numero-cambiado,noanswer)
exten => s-22,n,Busy(20)

; NUMERO YA NO EXISTE
exten => s-27,1,NoOp(Mario Dice: Numero Ya no existe)
exten => s-27,n,Playback(custom/numero-ya-no-existe,noanswer)
exten => s-27,n,Busy(20)

; NUMERO INCORRECTO
exten => s-28,1,NoOp(Mario Dice: Numero Incorrecto)
exten => s-28,n,Playback(custom/numero-incorrecto,noanswer)
exten => s-28,n,Busy(20)

exten => s-88,1,NoOp(Mario Dice: Numero Incorrecto)
exten => s-88,n,Playback(custom/numero-incorrecto,noanswer)
exten => s-88,n,Busy(20)

exten => s-95,1,NoOp(Mario Dice: Numero Incorrecto)
exten => s-95,n,Playback(custom/numero-incorrecto,noanswer)
exten => s-95,n,Busy(20)

; ERROR EN LA RED
exten => s-102,1,NoOp(Mario Dice: Error en la red)
exten => s-102,n,Playback(custom/error-red,noanswer)
exten => s-102,n,Busy(20)

exten => s-111,1,NoOp(Mario Dice: Error en la red)
exten => s-111,n,Playback(custom/error-red,noanswer)
exten => s-111,n,Busy(20)

exten => s-127,1,NoOp(Mario Dice: Error en la red)
exten => s-127,n,Playback(custom/error-red,noanswer)
exten => s-127,n,Busy(20)

; FIN MODIFICACIONES MARIO
exten => s-BUSY,1,Noop(Dial failed due to trunk reporting BUSY - giving up)
exten => s-BUSY,n,Playtones(busy)
exten => s-BUSY,n,Busy(20)
exten => s-NOANSWER,1,Noop(Dial failed due to trunk reporting NOANSWER - giving up)
exten => s-NOANSWER,n,Playtones(congestion)
exten => s-NOANSWER,n,Congestion(20)
exten => s-CANCEL,1,Noop(Dial failed due to trunk reporting CANCEL - giving up)
exten => s-CANCEL,n,Playtones(congestion)
exten => _s-.,1,GotoIf($["x${OUTFAIL_${ARG1}}" = "x"]?noreport)
exten => _s-.,n,AGI(${OUTFAIL_${ARG1}})
exten => _s-.,n(noreport),Noop(TRUNK Dial failed due to ${DIALSTATUS} - failing through to other trunks)
exten => disabletrunk,1,Noop(TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk)
exten => bypass,1,Noop(TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-trunk-predial-hook)
exten => h,1,Macro(hangupcall,)
Cabe destacar que esta modificación no es muy aplicable si utilizas más de un trunk para una Ruta de Salida (Outbound Route), el comando Playblack tiene como primer parametro la grabación y como segundo parametro el disposition, para que nuestro CDR no tome estas llamadas al momento de hacer sus reportes.

3 comments

  1. mariofix /

    Martin, lo que hice fue copiar y pegar el contexto “macro-dialout-trunk”, que en esa fecha tenia ese contenido, no se si se habrá actualizado con las nuevas versiones.

    FreePBX tiene un archivo el cual no se reescribe cada vez que lo actualizas y se ejeuta al final, puse el mismo contexto en ese archivo para que sobreescribiera al anterior.

    Sobre los canales, no encontré una forma de poder aplicar esto a más de un troncal de salida (ya que distintos troncales podrian entregar distintos hangupcause), es la razon de por que no he escrito el mantenedor :) esta solucion es para versiones antiguas de freepbx (la escribi para la 2.5) asi que probablemente haya que actualizarla a versiones más nuevas, pero la logica es la misma.

  2. martin constante /

    Hola! Es super interesante lo que has hecho. Solo tengo un par de dudas.. yo utilizo el freepbx para administrar mi asterisk, si hago estas modificaciones… luego cuando el freepbx sobrescriba algun cambio, conserva los cambios hechos a mano?
    tu dices al final de la nota que no aconsejas para mas de un trunk de salida.. porque? Hay forma de hacerlo para mas de un trunk?
    Muchas gracias y un cordial saludo
    Martin Constante
    martin@bairescat.com

  3. Anonymous /

    Buenísma y superútil la explicación!!!

    Ya lo tengo en marcha.

    Muchas Gracias,

Leave a Reply