OpenSIPs 3.1 y el modulo RATE_CACHER

Este nuevo modulo, presente en la versión 3.1 de OpenSIPs, permitirá, aunque todavía de manera un poco espartana, facturar las llamadas realizadas sin apoyarnos a sistemas de facturación externo tipo CGRATES. El modulo se basa en 3 tablas que se utilizan para la definición de clientes, proveedores y tablas que contendrás las tarifas. Por cada cliente es posible indicar dos tipos de tarifas, una al detalle y otra al por mayor. De esta forma será posible aplicar al cliente la tarifa mas adecuada según el tipo de trafico que está generando. La estructura de la tabla clientes es la siguiente:

en client_id se asigna un código/nombre que luego permita identificar de manera univoca el cliente, en wholesale_rate y retail_rate se asigna el ID que luego estará presente en la tabla rc_ratesheets. La tabla de los proveedores es un poco distinta:

en vendor_id se define un nombre/código que permita identificar de manera univoca el proveedor y en vendor_rate un numero que corresponda al ID que luego se creará en la tabla rc_ratesheets cuya estructura es:

En esta tabla se indica un id que luego se utilizará en la tabla rc_clients o rc_vendors y el nombre de la tabla que contendrá todas las tarifas para este especifico ID. Vamos con un ejemplo:

El cliente 1000 utilizará como tarifas aquellas contenidas en la ID 1 (para detalle y al por mayor) de la tabla rc_ratesheets. En esa tabla se indicará como id 1, el nombre de la tabla que contendrá las tarifas, ejemplo tar_colombia1 y el tipo de moneda utilizado, por ejemplo, USD. Luego utilizando la misma estructura de la tabla rc_demo_ratesheet:

se creará una tabla idéntica con nombre tar_colombia1 donde se insertarán todas las tarifas. Un ejemplo de entrada:

  • id – numero progresivo incrementado automáticamente por cada entrada

  • prefix – prefijo a que aplica la tarifa, ejemplo 57318

  • destination – nombre del destino; en este caso Colombia Movistar

  • price – el costo por minuto de la llamada, ejemplo 0.02 dólares/minuto

  • minumum – el numero mínimo de segundos que se cobrarán aunque la llamada tuvo una duración inferior, ejemplo 60

  • increment – el incremento, en segundos para la facturación de la llamada, ejemplo 60

En este caso la llamada se facturará por minuto 60/60; en el caso que se quiera facturar por segundo, minumum = 1 y increment = 1.

Ahora se configura un proveedor en la tabla rc_vendors con estos valores:

  • vendor_id = voztovoice

  • vendor_rate = 2.

Ahora hay que crear otra entrada en la tabla cc_ratesheets con los siguientes valores:

  • id = 2 (el ID indicado en la tabla rc_vendors para el proveedor voztovoice)

  • ratesheet_table = voztovoice_colombia (por ejemplo)

  • currency = USD

Para continuar se crea otra tabla siguiendo siempre la estructura de la tabla rc_demo_ratesheet y se nombra esta tabla voztovoice_colombia. Ahí se añade la siguiente entrada:

  • id – numero progresivo incrementado automáticamente por cada entrada

  • prefix – prefijo a que aplica la tarifa, ejemplo 57318

  • destination – nombre del destino; en este caso Colombia Movistar

  • price – el costo por minuto de la llamada, ejemplo 0.01 dólares/minuto

  • minumum – el numero mínimo de segundos que se cobrarán aunque la llamada tuvo una duración menor, ejemplo 30

  • increment – el incremento, en segundos para la facturación de la llamada, ejemplo 30

En este caso el precio del proveedor es de 0.01 dólares/minuto mientras el precio de venta, si recuerdan, es de 0.02 dólares/minuto. La facturación del proveedor será por intervalos de 30 segundos.

Con esta configuración mínima ya podemos realizar las primeras pruebas; en el script de OpenSIPs, primero se carga el modulo y se configuran los parámetros requeridos:

##### RATE_CACHER MODULE

loadmodule "rate_cacher.so"

modparam("rate_cacher","rates_db_url","mysql://root@localhost/opensips")

modparam("rate_cacher","clients_db_url","mysql://root@localhost/opensips")

modparam("rate_cacher","vendors_db_url","mysql://root@localhost/opensips")

Como se puede ver es posible indicar una base de datos distinta para tarifas, clientes y proveedores respectivamente. Luego en la parte del script donde se procesan los INVITE:

$avp(dialled_no) = "573181234567";

$avp(client_id) = "1000";

$avp(is_wholesale) = 1;

$avp(vendor_id) = "voztovoice";

if (get_client_price($avp(client_id),$avp(is_wholesale),$avp(dialled_no),$avp(prefix),$avp(dst),$avp(price),$avp(min),$avp(inc))) {

xlog("RATING: we've matched $avp(prefix) ($avp(dst)) with a price per min of $avp(price) , $avp(min) , $avp(inc) \n");

}

if (get_vendor_price($avp(vendor_id),$avp(dialled_no),$avp(vprefix),$avp(vdst),$avp(vprice),$avp(vmin),$avp(vinc))) {

xlog("RATING: we've matched vendor $avp(vprefix) ($avp(vdst)) with a price per min of $avp(vprice) , $avp(vmin) , $avp(vinc) \n");

}

En las primeras cuatros variables se almacenas los datos, que se necesitarán luego, al momento de utilizar las dos funciones:

  • get_client_price

  • get_vendor_price

activadas por el modulo RATE_CACHER. Estos datos son respectivamente: numero marcado, cliente a quien facturar la llamada, id de la tabla utilizada para buscar las tarifas para ese cliente y nombre del proveedor. Esos datos podrían ser parte de otra tabla de base de datos donde se asigna a cada usuario un numero de cliente y un proveedor o utilizar otro tipo de lógica. El resultado final será que tendremos el precio de compra y de venta de la llamada que luego utilizaremos en el bloque donde se procesarán los BYE para poder facturar correctamente la llamada. Para eso nos apoyaremos al modulo MATHOPS y utilizaremos unas variables creadas anteriormente. Para el costo de la llamada, lado cliente, sería:

if (is_method("BYE")) {

if ($DLG_lifetime > $dlg_val(client_min)) {

# we are above minimum, round to nearest increment

math_ceil("$DLG_lifetime / $dlg_val(client_inc)",$avp(total_inc));

math_eval("$avp(total_inc) * $dlg_val(client_inc) * $dlg_val(client_price) / 60",$avp(client_price));

} else {

# below minimum, rate at minimum seconds

math_eval("$dlg_val(client_min) * $dlg_val(client_price) / 60",$avp(client_price));

}

xlog("RATING: Client price per call is $avp(client_price) \n");

}

Algunas explicaciones:

  • la variable $DLG_lifetime contiene la duración de la llamada desde que ha sido contestada

  • si el resultado de la operación es mayor del valor del incremento mínimo para la tarifa utilizada, como indicado en la tabla de las tarifas del cliente, se continua con las lineas que siguen

  • con la función math_ceil, activada por el modulo MATHOPS, se redondea al entero superior el resultado de la operación $DLG_lifetime / $dlg_val(client_inc) y se asigna el resultado a la variable $avp(total_inc)

  • con la función math_eval, activada por el modulo MATHOPS, se saca el costo de la llamada multiplicando el resultado de la operación anterior por el valor contenido en el campo increment de la tarifas utilizada por el valor al minuto de la llamada. El resultado se divide por 60 y se asigna a la variable $avp(client_price) que contendrá el costo final de la llamada y que se podrá guardar, configurando oportunamente el modulo ACC en la tabla CDR de la base de datos de OpenSIPs

  • Si la duración de la llamada ha sido inferior al mínimo indicado en el campo minimum de las tarifas, el calculo se realizará de manera diferente

Si se quiere guardar en la tabla CDR también el costo de la llamada lado servidor, nada más repetir el mismo bloque utilizando los valores del proveedor configurado.

Otra cosa interesante del modulo, es que hay dos funciones más activadas por el modulo RATE_CACHER que permiten realizar las siguientes operaciones:

  • no utilizar un proveedor si el precio de compra es más alto que el precio de venta. Esto se realizar utilizando la función cost_based_filtering

  • si se indica más de un proveedor para una determinada llamada, escoger el más económico. Esto se realiza utilizando la función cost_based_ordering

Encuentran más información en la entrada del Blog de OpenSIPs y en la pagina del modulo.