Saltar al contenido principal

Comportamientos de Acciones y Recargas de CGRateS

Esta guía explica cómo funcionan las Acciones de CGRateS dentro de OmniCRM, enfocándose específicamente en la gestión de saldos, comportamientos de recarga y cómo diferentes tipos de acciones afectan a los productos adicionales.

Resumen​

En el Sistema de Carga en Línea (CGRateS) de OmniCRM, Acciones son el mecanismo para agregar, modificar o eliminar saldos en las cuentas de los clientes.

Cuando provisionas un producto adicional o de recarga, en realidad estás ejecutando una Acción de CGRateS que manipula los saldos de la cuenta. (También puedes tomar otros enfoques, como agregar saldos a cuentas manualmente desde Playbooks. Este es solo un patrón común que usamos para mantener las cosas limpias.)

Conceptos Clave​

Acción - Un conjunto de operaciones a realizar en una cuenta (agregar saldo, deducir saldo, registrar CDR, etc.)

Saldo - Una cantidad de un recurso (datos, voz, SMS, monetario) con un tiempo de expiración y peso

ID de Saldo - Un identificador único para un tipo de saldo (por ejemplo, "Paquete de Datos", "Minutos de Voz")

Peso - Prioridad para el consumo de saldo (peso más alto consumido primero)

Tiempo de Expiración - Cuando el saldo expira (fecha absoluta o relativa como "+5 días")

Bloqueador - Una bandera especial de saldo que bloquea todo uso cuando el saldo llega a cero, incluso si existen otros saldos (ver Bloqueadores de Saldo)

Crítico: Las Acciones Deben Definirse Primero​

Antes de que puedas ejecutar una Acción en un playbook usando ExecuteAction, esa Acción ya debe estar definida en CGRateS. Este es un requisito crítico que a menudo se pasa por alto.

Cuándo se Definen las Acciones​

Las acciones se definen típicamente durante la configuración inicial del sistema o configuración del producto, NO durante el aprovisionamiento. Generalmente se crean a través de scripts de Python que configuran simultáneamente tanto el CRM como el OCS.

Cómo se Enlazan las Acciones a los Productos​

Las acciones están vinculadas a productos a través de una convención de nomenclatura:

  • Acción de CGRateS: ActionsId = "Action_50gb-data-pack"
  • Producto CRM: product_slug = "50gb-data-pack"
  • En Playbook: cgr_action_name = "Action_" + product_slug

Cuando se ejecuta el playbook, construye el nombre de la Acción a partir del product_slug y llama a ExecuteAction. Si esa Acción no existe en CGRateS, el aprovisionamiento falla.

Dónde Definir Acciones​

Las acciones deben definirse en tus scripts de configuración de productos, típicamente:

  1. Durante la Configuración Inicial - Al configurar tu sistema por primera vez
  2. Al Crear Nuevos Productos - Define la Acción antes de crear el producto
  3. A través de Scripts de Configuración - Scripts de Python que configuran tanto OCS como CRM

Ejemplo: Definiendo una Acción antes de crear el producto

import cgrateshttpapi

OCS_Obj = cgrateshttpapi.CGRateS("ocs.example.com", "2080")
tenant = "tu_tenant"

# Paso 1: Define la Acción en CGRateS PRIMERO
Action_50GB_Data_Pack = {
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_50gb-data-pack",
"Tenant": tenant,
"Actions": [
{
"Identifier": "*topup",
"BalanceType": "*data",
"Units": 50 * 1024 * 1024 * 1024,
"ExpiryTime": "+720h",
"Weight": 10
}
]
}]
}

result = OCS_Obj.SendData(Action_50GB_Data_Pack)
assert result['error'] is None or result['error'] == "EXISTS"

# Paso 2: Ahora crea el producto en CRM
# (product_slug = "50gb-data-pack" se vinculará a Action_50gb-data-pack)

Qué Sucede Si la Acción No Existe:

# En playbook
- name: Ejecutar Acción
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "APIerSv1.ExecuteAction",
"params": [{
"ActionsId": "Action_50gb-data-pack"
}]
}
register: response

# Resultado si la Acción no está definida:
# response.json.error = "SERVER_ERROR: Acción no encontrada"
# El aprovisionamiento falla, el cliente no recibe saldo

Para obtener detalles completos sobre cómo definir Acciones y vincularlas a productos, consulta Definición de Productos.

Independencia de Saldo​

Por defecto, los productos adicionales crean saldos independientes que funcionan por separado entre sí. Esto significa:

  • Puedes tener múltiples addons activos simultáneamente
  • Cada addon mantiene su propio saldo y expiración
  • Los saldos se consumen según las reglas de peso y expiración

Ejemplo: Múltiples Addons Independientes​

# El cliente tiene estos saldos activos:
Saldo 1:
ID: "Data_5GB_5days_uuid_abc123"
Tipo: *data
Valor: 5368709120 # 5GB en bytes
Expiración: 2024-12-29
Peso: 10

Saldo 2:
ID: "Data_10GB_30days_uuid_def456"
Tipo: *data
Valor: 10737418240 # 10GB en bytes
Expiración: 2025-01-24
Peso: 10

# Ambos saldos coexisten de manera independiente
# El sistema consume según el peso; si el peso es igual, el orden no está garantizado

Cuando los saldos tienen el mismo peso y coinciden con el mismo destino, CGRateS no garantiza el orden de consumo basado en la expiración; el orden depende de cómo se almacenan y recuperan los saldos. Usa diferentes pesos para controlar el orden de consumo.

Tipos de Acción: *topup vs *topup_reset​

El tipo de acción determina cómo los nuevos saldos interactúan con los saldos existentes del mismo ID.

*topup - Comportamiento Aditivo​

La acción *topup agrega a los saldos existentes con el mismo ID de Saldo y extiende el tiempo de expiración.

Comportamiento:

  • Encuentra saldo existente con ID coincidente
  • Agrega nuevo valor al valor existente
  • Actualiza la expiración al nuevo tiempo de expiración
  • Preserva el saldo existente (rollover)

Ejemplo:

# Estado inicial:
Saldo:
ID: "Data_Package__5368709120"
Valor: 1073741824 # 1GB restante
Expiración: 2024-12-24 (1 día restante)

# Ejecutar acción *topup con:
Acción:
Identifier: "*topup"
Saldo:
ID: "Data_Package__5368709120" # Mismo ID - activa el rollover
Valor: 5368709120 # 5GB
ExpiryTime: "+5d"

# Resultado después de *topup:
Saldo:
ID: "Data_Package__5368709120"
Valor: 6442450944 # 6GB (1GB + 5GB rollover)
Valor_original: 5368709120 # Sigue mostrando los 5GB originales
Valor_hr: "6 GB"
Valor_original_hr: "5 GB"
Restante_hr: "6 GB de 5 GB (1 GB rollover)"
Expiración: 2024-12-29 (5 días a partir de ahora)

Casos de Uso:

  • Recompensas de lealtad (agregar datos adicionales al paquete existente)
  • Créditos de compensación (agregar al saldo del cliente)
  • Paquetes de datos rollover
  • Extensiones de período de gracia

*topup_reset - Comportamiento de Reinicio​

La acción *topup_reset reemplaza los saldos existentes con el mismo ID de Saldo.

Comportamiento:

  • Encuentra saldo existente con ID coincidente
  • Desecha el valor antiguo (sin rollover)
  • Establece el saldo al nuevo valor solamente
  • Actualiza la expiración al nuevo tiempo de expiración

Ejemplo:

# Estado inicial:
Saldo:
ID: "Data_Package__5368709120"
Valor: 1073741824 # 1GB restante
Expiración: 2024-12-24 (1 día restante)

# Ejecutar acción *topup_reset con:
Acción:
Identifier: "*topup_reset"
Saldo:
ID: "Data_Package__5368709120" # Mismo ID - activa el reinicio
Valor: 5368709120 # 5GB
ExpiryTime: "+5d"

# Resultado después de *topup_reset:
Saldo:
ID: "Data_Package__5368709120"
Valor: 5368709120 # 5GB (se descartó el antiguo 1GB)
Valor_original: 5368709120
Valor_hr: "5 GB"
Restante_hr: "5 GB de 5 GB"
PorcentajeUsado: 0
Expiración: 2024-12-29 (5 días a partir de ahora)

Casos de Uso:

  • Paquetes recurrentes mensuales (reiniciar a la cantidad total cada mes)
  • Recargas de tamaño fijo (siempre recibir la cantidad exacta)
  • Cambios de plan (reemplazar el saldo del plan antiguo con el nuevo plan)
  • Prevenir abusos (no se pueden apilar addons ilimitados)

Controlando el Comportamiento del Saldo con IDs de Saldo​

El ID de Saldo es crucial para determinar si los saldos son independientes o interactúan entre sí.

Convención de Nomenclatura de ID de Saldo y Vistas Legibles por Humanos​

OmniCRM utiliza una convención de nomenclatura específica para los IDs de Saldo que codifica tanto el nombre descriptivo como el tamaño original. Esto permite que la API genere automáticamente campos legibles por humanos para la interfaz web.

Patrón de ID de Saldo:

{NombreDescriptivo}__{TamañoOriginalEnUnidadesBase}

Ejemplos de IDs de Saldo:

# Saldo de datos: 100GB
"AU_Data_Domestic__107374182400"
# Se descompone en:
# - Parte descriptiva: "AU_Data_Domestic" (QUÉ es - tipo/destino)
# - Separador: "__" (doble guion bajo)
# - Tamaño original: "107374182400" (100GB en bytes)
# - La UI muestra: "AU Data Domestic - 100 GB"

# Saldo de voz: 3000 minutos
"AU_Voice_Domestic__180000000000000"
# - Parte descriptiva: "AU_Voice_Domestic" (NO "AU_Voice_Domestic_3000min")
# - Tamaño original: "180000000000000" (3000 minutos en nanosegundos)
# - La UI muestra: "AU Voice Domestic - 3000 min"

# Saldo de SMS: 3000 mensajes
"AU_SMS_Domestic__3000"
# - Parte descriptiva: "AU_SMS_Domestic"
# - Tamaño original: "3000" (conteo)
# - La UI muestra: "AU SMS Domestic - 3000 msgs"

Importante: No incluyas información de tamaño en la parte descriptiva. Es redundante ya que el tamaño está codificado después de __ y la API lo convierte automáticamente a formato legible por humanos.

Cómo la API Crea Vistas Legibles por Humanos:

Cuando la API de OmniCRM recupera datos de saldo de CGRateS, automáticamente analiza el ID de Saldo y genera campos _hr (legibles por humanos):

{
"BalanceMap": {
"*data": [
{
"ID": "AU_Data_Domestic__107374182400",
"Value": 53687091200,
"ExpiryTime": "2025-01-25T23:59:59Z",
"Weight": 1200,

// Campos legibles por humanos generados automáticamente:
"ID_hr": "AU Data Domestic",
"OriginalValue": 107374182400,
"OriginalValue_hr": "100 GB",
"Value_hr": "50 GB",
"Remaining_hr": "50 GB de 100 GB",
"PercentUsed": 50,
"ExpiryTime_hr": "25 Ene 2025 (22 días)"
}
]
}
}

Lógica de Procesamiento de la API:

  1. Analizar ID de Saldo:

    balance_id = "AU_Data_Domestic__107374182400"
    parts = balance_id.split("__")

    descriptive_name = parts[0] # "AU_Data_Domestic"
    original_size = int(parts[1]) if len(parts) > 1 else None # 107374182400
  2. Generar Nombre Descriptivo Legible por Humanos:

    # Reemplazar guiones bajos por espacios
    id_hr = descriptive_name.replace("_", " ") # "AU Data Domestic"
  3. Convertir Tamaño Original a Unidades Humanas:

    # Para saldos de datos (bytes)
    if balance_type == "*data":
    original_value_hr = convert_bytes_to_gb(original_size) # "100 GB"

    # Para saldos de voz (nanosegundos)
    elif balance_type == "*voice":
    original_value_hr = convert_ns_to_minutes(original_size) # "3000 min"

    # Para saldos de SMS (conteo)
    elif balance_type == "*sms":
    original_value_hr = f"{original_size} msgs" # "3000 msgs"
  4. Calcular Porcentaje de Uso:

    if original_size and original_size > 0:
    percent_used = ((original_size - current_value) / original_size) * 100
  5. Formatear Visualización Restante:

    remaining_hr = f"{current_value_hr} de {original_value_hr}"
    # "50 GB de 100 GB"

Visualización en la Interfaz Web:

El frontend utiliza estos campos _hr para mostrar información de saldo amigable para el usuario:

// En lugar de mostrar valores en bruto:
// ID: "AU_Data_Domestic__107374182400"
// Valor: 53687091200

// Mostrar legible por humanos:
<BalanceCard>
<Title>{balance.ID_hr}</Title> {/* "AU Data Domestic" */}
<Progress value={balance.PercentUsed}> {/* 50% */}
{balance.Remaining_hr} {/* "50 GB de 100 GB" */}
</Progress>
<Expiry>{balance.ExpiryTime_hr}</Expiry> {/* "25 Ene 2025 (22 días)" */}
</BalanceCard>

Por Qué Esto Importa:

  1. Seguimiento del Tamaño Original - Incluso cuando los saldos están parcialmente consumidos, la UI puede mostrar "50 GB de 100 GB" en lugar de solo "50 GB restantes"

  2. Visualización del Progreso - Los cálculos de porcentaje permiten barras de progreso precisas

  3. Nomenclatura Consistente - Los nombres descriptivos extraídos de los IDs de Saldo aseguran consistencia entre el backend y el frontend

  4. Visualización de Rollover - Al usar *topup (rollover), si un cliente tiene 70 GB restantes y recarga 100 GB:

    • El ID de Saldo permanece: "AU_Data_Domestic__107374182400" (original 100 GB)
    • El valor actual se convierte en: 170 GB
    • La UI muestra: "170 GB (70 GB rollover + 100 GB nuevo)"

Mejor Práctica - Creación de IDs de Saldo:

Siempre incluye el tamaño original después de __ para una visualización adecuada en la UI. No dupliques la información de tamaño en el nombre descriptivo:

# Bueno - nombre descriptivo + tamaño en unidades base
Action_Data_100GB = {
"Actions": [
{
"BalanceId": f"AU_Data_Domestic__{100 * 1024 * 1024 * 1024}",
"Units": 100 * 1024 * 1024 * 1024
}
]
}

# Malo - tamaño redundante en el nombre descriptivo
Action_Data_100GB = {
"Actions": [
{
"BalanceId": f"AU_Data_Domestic_100GB__{100 * 1024 * 1024 * 1024}", # ¡Redundante!
"Units": 100 * 1024 * 1024 * 1024
}
]
}

# Malo - sin información de tamaño (la UI no puede calcular porcentaje)
Action_Data_100GB = {
"Actions": [
{
"BalanceId": "AU_Data_Domestic", # Falta __tamaño
"Units": 100 * 1024 * 1024 * 1024
}
]
}

Caso Especial - Saldos Monetarios:

Los saldos monetarios no suelen incluir tamaño original ya que pueden recargarse a cualquier cantidad:

# Saldo monetario sin codificación de tamaño
{
"BalanceId": "PAYG_Monetary_Balance",
"BalanceType": "*monetary",
"Units": 5000 # $50.00
}

# La UI simplemente muestra el saldo actual sin porcentaje
# "Saldo: $50.00"

Estrategia 1: IDs Únicos (Saldos Independientes)​

Usa IDs únicos (por ejemplo, con UUIDs) para crear saldos completamente independientes que nunca interactúan.

Ejemplo de Implementación:

- name: Generar identificador de saldo único
set_fact:
uuid: "{{ 99999999 | random | to_uuid }}"
balance_id: "Data_5days__5368709120_{{ uuid[0:8] }}"

- name: Agregar saldo independiente con *topup
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "{{ balance_id }}",
"Value": 5368709120,
"ExpiryTime": "+5d",
"Weight": 10
}
}]
}

Resultado: Cada addon crea un nuevo saldo separado incluso si el cliente compra el mismo addon varias veces.

# El cliente compra "addon de datos de 5 días" tres veces:
Saldo 1:
ID: "Data_5days__5368709120_a1b2c3d4"
Valor: 5368709120
Valor_hr: "5 GB"
Valor_original_hr: "5 GB"
Restante_hr: "5 GB de 5 GB"
Expiración: 2024-12-29

Saldo 2:
ID: "Data_5days__5368709120_e5f6g7h8"
Valor: 5368709120
Valor_hr: "5 GB"
Restante_hr: "5 GB de 5 GB"
Expiración: 2024-12-30

Saldo 3:
ID: "Data_5days__5368709120_i9j0k1l2"
Valor: 5368709120
Valor_hr: "5 GB"
Restante_hr: "5 GB de 5 GB"
Expiración: 2024-12-31

# Total disponible: 15GB en tres saldos separados
# Cada uno se muestra individualmente en la UI como "Datos 5 días - 5 GB de 5 GB"

Estrategia 2: IDs Compartidos con *topup (Rollover)​

Usa el mismo ID de Saldo con la acción *topup para permitir el rollover de saldo y la extensión de la expiración.

Ejemplo de Implementación:

- name: Establecer ID de saldo fijo
set_fact:
balance_id: "Data_5days__5368709120"

- name: Agregar saldo con *topup (rollover)
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "Data_5days__5368709120",
"Value": 5368709120,
"ExpiryTime": "+5d",
"Weight": 10
}
}]
}

Resultado: Compras posteriores se suman al saldo existente y extienden la expiración.

# Día 1: El cliente compra "addon de datos de 5 días":
Saldo:
ID: "Data_5days__5368709120"
Valor: 5368709120
Valor_hr: "5 GB"
Restante_hr: "5 GB de 5 GB"
PorcentajeUsado: 0
Expiración: 2024-12-29

# Día 3: El cliente usó 1GB, luego compra el mismo addon nuevamente:
Saldo:
ID: "Data_5days__5368709120"
Valor: 9663676416 # 4GB restantes + 5GB nuevos
Valor_hr: "9 GB"
Valor_original_hr: "5 GB"
Restante_hr: "9 GB (4 GB rollover + 5 GB nuevos)"
PorcentajeUsado: -80 # Negativo indica rollover
Expiración: 2024-12-27 (nuevos +5 días a partir de hoy)

Estrategia 3: IDs Compartidos con *topup_reset (Cantidad Fija)​

Usa el mismo ID de Saldo con la acción *topup_reset para restablecer siempre a una cantidad fija.

Ejemplo de Implementación:

- name: Establecer ID de saldo fijo
set_fact:
balance_id: "Monthly_Plan__32212254720"

- name: Agregar saldo con *topup_reset (sin rollover)
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_Reset_Monthly_Plan",
"Actions": [{
"Identifier": "*topup_reset",
"BalanceType": "*data",
"Units": 32212254720, # 30GB
"ExpiryTime": "*monthly",
"DestinationIds": "*any",
"BalanceId": "Monthly_Plan__32212254720",
"Weight": 10
}]
}]
}

Resultado: Cada mes, el saldo se restablece exactamente a 30GB independientemente de cuánto se haya utilizado.

# Mes 1, Día 1:
Saldo:
ID: "Monthly_Plan__32212254720"
Valor: 32212254720
Valor_hr: "30 GB"
Restante_hr: "30 GB de 30 GB"
PorcentajeUsado: 0
Expiración: 2024-12-31

# Mes 1, Día 25: El cliente usó 28GB
Saldo:
ID: "Monthly_Plan__32212254720"
Valor: 2147483648
Valor_hr: "2 GB"
Restante_hr: "2 GB de 30 GB"
PorcentajeUsado: 93
Expiración: 2024-12-31

# Mes 2, Día 1: El ActionPlan ejecuta *topup_reset
Saldo:
ID: "Monthly_Plan__32212254720"
Valor: 32212254720 # Restablecido a completo, se pierden 2GB no utilizados
Valor_hr: "30 GB"
Restante_hr: "30 GB de 30 GB"
PorcentajeUsado: 0
Expiración: 2025-01-31

Bloqueadores de Saldo​

Los Bloqueadores de Saldo son una poderosa característica de CGRateS que te permite bloquear o limitar el uso incluso cuando existen saldos. Un saldo bloqueador detiene el consumo cuando llega a cero, impidiendo un uso adicional independientemente de otros saldos disponibles.

Cómo Funcionan los Bloqueadores​

Cuando un saldo tiene Blocker: true:

  1. Mientras el bloqueador tenga valor → Se permite el uso hasta la cantidad del bloqueador
  2. Cuando el bloqueador llega a cero → Se detiene todo uso, incluso si existen otros saldos
  3. Error devuelto → INSUFFICIENT_CREDIT_BALANCE_BLOCKER previene la sesión

Características Clave:

  • Los saldos bloqueadores son verificados incluso cuando el valor es cero (a diferencia de los saldos normales que se omiten)
  • Cuando se encuentra un bloqueador con uso restante solicitado, CGRateS detiene el procesamiento y devuelve un error
  • Los bloqueadores funcionan con todos los tipos de saldo: *voice, *data, *sms, *monetary

Casos de Uso para Bloqueadores​

1. Suspensión de Cuenta​

Bloquear todo uso cuando una cuenta está suspendida (por ejemplo, fallo de pago):

Action_Suspend_Account = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_suspend-account",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
# Agregar bloqueador de valor cero para prevenir todo uso
{
"Identifier": "*topup",
"BalanceId": "Suspension_Blocker",
"BalanceType": "*monetary",
"DestinationIDs": "*any",
"Units": 0, # Valor cero
"BalanceWeight": 9999, # Mayor prioridad - verificado primero
"Blocker": True, # Bloquear todo uso
"Weight": 10
}
]
}]
}

result = OCS_Obj.SendData(Action_Suspend_Account)

Resultado: Todas las llamadas/datos/SMS bloqueados independientemente de otros saldos.

2. Límites de Gastos​

Limitar el gasto máximo para prevenir sorpresas en la factura:

Action_Monthly_Plan_With_Cap = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_monthly-with-cap",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
# 10GB de datos incluidos
{
"Identifier": "*topup_reset",
"BalanceId": f"Included_Data__{10 * 1024 * 1024 * 1024}",
"BalanceType": "*data",
"DestinationIDs": "Dest_PLMN_OnNet",
"Units": 10 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1200, # Consumido primero
"Weight": 95
},
# Límite de exceso de $50 (bloqueador)
{
"Identifier": "*topup_reset",
"BalanceId": "Overage_Cap",
"BalanceType": "*monetary",
"DestinationIDs": "*any",
"Units": 5000, # $50.00 máximo de exceso
"ExpiryTime": "*month",
"BalanceWeight": 1000, # Consumido después de lo incluido
"Blocker": True, # Detener cuando se gaste $50
"Weight": 90
}
]
}]
}

Flujo:

  1. El cliente usa 10GB incluidos → GRATIS (de Included_Data_10GB)
  2. El cliente usa 5GB adicionales → Cargado de Overage_Cap (tarifas PAYG)
  3. Cuando Overage_Cap llega a $0 → Todo uso bloqueado (límite de gasto alcanzado)

3. Prueba Gratuita Limitada en el Tiempo​

Proporcionar uso gratuito limitado para cuentas de prueba:

Action_Trial_Account = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_trial-100-minutes",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
# 100 minutos gratuitos (bloqueador - se detiene cuando se agota)
{
"Identifier": "*topup",
"BalanceId": f"Trial_Voice__{100 * 60 * 1000000000}",
"BalanceType": "*voice",
"DestinationIDs": "Dest_Domestic_All",
"Units": 100 * 60 * 1000000000, # 100 minutos
"ExpiryTime": "+720h", # 30 días
"BalanceWeight": 1200,
"Blocker": True, # Sin uso después de 100 minutos
"Weight": 10
}
]
}]
}

Resultado: El cliente obtiene exactamente 100 minutos gratis. Después de eso, todas las llamadas están bloqueadas (sin cargos automáticos).

4. Bloqueo Específico por Destino​

Bloquear destinos específicos mientras se permiten otros:

Action_Block_Premium_Numbers = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_block-premium",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
# Uso regular permitido
{
"Identifier": "*topup_reset",
"BalanceId": "Regular_Usage",
"BalanceType": "*monetary",
"DestinationIDs": "Dest_Domestic_All",
"Units": 10000, # $100
"ExpiryTime": "*month",
"BalanceWeight": 1000,
"Weight": 20
},
# Bloquear números premium (0900, etc.)
{
"Identifier": "*topup",
"BalanceId": "Premium_Blocker",
"BalanceType": "*monetary",
"DestinationIDs": "Dest_Domestic_Premium",
"Units": 0, # Valor cero
"BalanceWeight": 2000, # Peso más alto - revisado primero para premium
"Blocker": True,
"Weight": 10
}
]
}]
}

Flujo:

  • Llamadas nacionales → Usa el saldo Regular_Usage
  • Llamadas a números premium → Coincide con Premium_Blocker (peso 2000 > 1000) → BLOQUEADO

Bloqueador vs Saldos Desactivados​

No confundir Blocker con Disabled:

CaracterísticaBloqueadorDesactivado
PropósitoDetener el uso cuando el saldo se agotaPausar temporalmente un saldo
Cuando el valor > 0El saldo se puede usar normalmenteEl saldo se omite/ignora
Cuando el valor = 0Bloquea todo uso posteriorEl saldo se omite (se prueba el siguiente saldo)
Caso de UsoLímites de gasto, topes, límites de pruebaSuspender temporalmente un saldo específico
# Bloqueador: Permite 10GB, luego bloquea todo
{
"BalanceId": f"Data_Cap__{10 * 1024 * 1024 * 1024}",
"Units": 10 * 1024 * 1024 * 1024,
"Blocker": True # Detiene el uso a 10GB
}

# Desactivado: Ignora este saldo por completo (pausado temporalmente)
{
"BalanceId": f"Bonus_Data__{5 * 1024 * 1024 * 1024}",
"Units": 5 * 1024 * 1024 * 1024,
"Disabled": True # Este saldo no se usará en absoluto
}

Ejemplo Práctico: Plan Híbrido con Tope de Seguridad​

Combinar saldos unitarios, desbordamiento monetario y un tope bloqueador:

Action_Safe_Hybrid_Plan = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_safe-hybrid-plan",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
{
"Identifier": "*reset_account",
"Weight": 700
},
# 500 minutos nacionales incluidos
{
"Identifier": "*topup_reset",
"BalanceId": f"Domestic_Voice__{500 * 60 * 1000000000}",
"BalanceType": "*voice",
"DestinationIDs": "Dest_Domestic_All",
"Units": 500 * 60 * 1000000000,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 95
},
# $20 de límite de exceso
{
"Identifier": "*topup_reset",
"BalanceId": "Overage_Allowance",
"BalanceType": "*monetary",
"DestinationIDs": "*any",
"Units": 2000, # $20.00
"ExpiryTime": "*month",
"BalanceWeight": 1000,
"Weight": 90
},
# LÍMITE DURO DE $50 (bloqueador)
{
"Identifier": "*topup_reset",
"BalanceId": "Hard_Spending_Cap",
"BalanceType": "*monetary",
"DestinationIDs": "*any",
"Units": 5000, # $50.00 máximo absoluto
"ExpiryTime": "*month",
"BalanceWeight": 500, # Menor que el exceso - usado al final
"Blocker": True, # DETENER cuando se alcance el tope
"Weight": 85
}
]
}]
}

Viaje del Cliente:

  1. 0-500 minutos: Usa Domestic_Voice_500min (GRATIS)
  2. 500-700 minutos: Usa Overage_Allowance a $0.10/min = $20 (200 min)
  3. 700-1200 minutos: Usa Hard_Spending_Cap a $0.10/min = $50 (500 min)
  4. A 1200 minutos: Hard_Spending_Cap agotado → TODO USO BLOQUEADO

El cliente obtiene un total de 1200 minutos, con un gasto limitado a un máximo de $50 en exceso.

Mejores Prácticas con Bloqueadores​

  1. Usar Alto Peso para Bloqueadores

    "BalanceWeight": 9999  # Asegurar que el bloqueador sea revisado primero
  2. Bloqueadores de Valor Cero para Bloqueo Inmediato

    "Units": 0,  # Bloquear inmediatamente
    "Blocker": True
  3. Notificar a los Clientes Antes de la Agotamiento del Bloqueador

    • Usar ActionTriggers para enviar notificaciones al 80%, 90%, 100% del uso del bloqueador
    • Dar a los clientes la opción de aumentar el tope antes de que ocurra el bloqueo
  4. Eliminar Bloqueadores al Desuspender

    # Usar *remove_balance para eliminar el bloqueador
    {
    "Identifier": "*remove_balance",
    "BalanceId": "Suspension_Blocker"
    }
  5. Probar el Comportamiento del Bloqueador

    • Verificar que el bloqueador devuelve el error INSUFFICIENT_CREDIT_BALANCE_BLOCKER
    • Confirmar que los CDRs muestran costo = -1.0 cuando está bloqueado
    • Probar que otros saldos NO se usan después del agotamiento del bloqueador

Solución de Problemas de Bloqueadores​

Problema: Uso no bloqueado a pesar de que el bloqueador está en cero

Causas Posibles:

  1. Peso del bloqueador demasiado bajo (otros saldos revisados primero)
  2. DestinationIDs no coinciden con el destino de uso
  3. Campo de bloqueador no configurado en True

Solución:

# Verificar la configuración del bloqueador
OCS_Obj.SendData({
'method': 'ApierV2.GetAccount',
'params': [{"Tenant": tenant, "Account": "service_uuid"}]
})

# Comprobar:
# - Blocker: true
# - BalanceWeight es el más alto (por ejemplo, 9999)
# - DestinationIDs incluye el destino de uso
# - Valor = 0

Problema: Uso bloqueado inesperadamente

Causa Posible: Bloqueador creado involuntariamente con un valor bajo

Solución: Verificar todos los saldos para Blocker: true y verificar que sus valores sean apropiados para su caso de uso.

Reglas de Consumo de Saldos​

Regla 1: Prioridad de Precisión de Destino​

Los saldos con mayor precisión de destino (coincidencia de destino más específica) se consumen primero. Esto se determina por la longitud de coincidencia de prefijo.

# El cliente llama a +44-20-1234-5678 (Londres, Reino Unido)

Saldo 1:
DestinationIDs: "Dest_UK_London" # Prefijo: "4420" (precisión: 4)
Valor: 100 minutos
Peso: 10

Saldo 2:
DestinationIDs: "Dest_UK_All" # Prefijo: "44" (precisión: 2)
Valor: 200 minutos
Peso: 10

# El saldo 1 se consume primero (precisión 4 > precisión 2)
# La coincidencia de destino más específica gana

Caso de Uso: Los saldos específicos de la ciudad o región tienen prioridad sobre los saldos a nivel nacional.

Regla 2: Prioridad de Peso (Misma Precisión)​

Cuando la precisión de destino es igual, los saldos con mayor peso se consumen primero.

Saldo 1:
ID: "Premium_Data"
Valor: 5GB
Peso: 20

Saldo 2:
ID: "Standard_Data"
Valor: 10GB
Peso: 10

# El saldo 1 se consume primero (peso 20 > peso 10)
# A pesar de que el saldo 2 tiene más datos

Caso de Uso: Los saldos prioritarios (datos adicionales consumidos antes que los datos regulares).

Regla 3: Primero el Más Antiguo​

Cuando el peso coincide, se usa primero el saldo más antiguo.

Saldo 1:
ID: "Data_Package_A"
Valor: 5GB
Expiración: 2024-12-25
Peso: 10

Saldo 2:
ID: "Data_Package_B"
Valor: 10GB
Expiración: 2025-01-15
Peso: 10

Para controlar el orden de consumo, use diferentes pesos:

# Enfoque correcto: Use peso para priorizar saldos que están a punto de expirar
Saldo 1:
ID: "Data_Package_A"
Valor: 5GB
Expiración: 2024-12-25
Peso: 11 # Peso más alto = consumido primero

Saldo 2:
ID: "Data_Package_B"
Valor: 10GB
Expiración: 2025-01-15
Peso: 10 # Peso más bajo = consumido segundo

# El saldo 1 se consume primero (peso 11 > peso 10)

Mejor Práctica: Si desea asegurarse de que los saldos que están a punto de expirar se consuman primero, asígneles pesos más altos al crearlos.

Ejemplos Prácticos​

Ejemplo 1: Complemento de Datos Simple (Independiente)​

Escenario: El cliente puede comprar un complemento de "5GB 5 días" varias veces, cada uno creando un saldo separado.

Implementación:

- name: Generar UUID para saldo único
set_fact:
uuid: "{{ 99999999 | random | to_uuid }}"

- name: Agregar saldo independiente de 5GB
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Categories": "*any",
"Balance": {
"ID": "Data_5GB_{{ uuid[0:8] }}",
"Value": 5368709120,
"ExpiryTime": "+120h", # 5 días
"Weight": 10
}
}]
}

Experiencia del Cliente:

  • Compra el complemento el 24 de diciembre → Obtiene 5GB que expiran el 29 de diciembre
  • Compra el complemento el 25 de diciembre → Obtiene 5GB que expiran el 30 de diciembre
  • Ambos saldos coexisten; el orden de consumo depende de los pesos de los saldos (ambos tienen peso 10, por lo que el orden no está garantizado)

Ejemplo 2: Paquete de Datos de Rollover​

Escenario: "Plan mensual de 50GB" donde los datos no utilizados se transfieren cuando el cliente recarga temprano.

Implementación:

- name: Agregar saldo de datos de rollover
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "Rollover_Monthly_50GB",
"Value": 53687091200, # 50GB
"ExpiryTime": "+720h", # 30 días
"Weight": 10
}
}]
}

Tipo de Acción: Usa el comportamiento predeterminado de *topup (rollover habilitado)

Experiencia del Cliente:

  • Día 1: Obtiene 50GB que expiran en 30 días
  • Día 20: Usó 30GB, tiene 20GB restantes
  • Día 20: Recarga nuevamente → Obtiene 70GB en total (20GB + 50GB), la expiración se extiende a +30 días desde el día 20

Ejemplo 3: Plan Mensual Fijo (Sin Rollover)​

Escenario: Plan "Ilimitado de 100GB mensual" que se restablece exactamente a 100GB cada mes, sin rollover.

Implementación:

- name: Crear acción de reinicio mensual
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_Monthly_100GB_Reset",
"Overwrite": true,
"Actions": [{
"Identifier": "*topup_reset",
"BalanceType": "*data",
"Units": 107374182400, # 100GB
"ExpiryTime": "*monthly",
"BalanceId": "Monthly_Plan__107374182400",
"Weight": 10
}]
}]
}

- name: Crear Plan de Acción mensual
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.SetActionPlan",
"params": [{
"Id": "ActionPlan_Monthly_100GB",
"ActionPlan": [{
"ActionsId": "Action_Monthly_100GB_Reset",
"Time": "*monthly",
"Weight": 10
}],
"Overwrite": true,
"ReloadScheduler": true
}]
}

- name: Asignar Plan de Acción a la cuenta
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV2.SetAccount",
"params": [{
"Account": "{{ service_uuid }}",
"ActionPlanIds": ["ActionPlan_Monthly_100GB"],
"ReloadScheduler": true
}]
}

Experiencia del Cliente:

  • Mes 1: Obtiene 100GB, usa 95GB, tiene 5GB restantes
  • Mes 2: El saldo se restablece a 100GB (se pierde 5GB de datos no utilizados)
  • Mes 2: Usa 20GB, tiene 80GB restantes
  • Mes 3: El saldo se restablece a 100GB (se pierden 80GB de datos no utilizados)

Ejemplo 4: Saldos de Múltiples Niveles con Prioridad de Peso​

Escenario: El cliente tiene "Datos Adicionales" (alta prioridad) y "Datos Regulares" (baja prioridad). Los datos adicionales se consumen primero.

Implementación:

# Agregar datos adicionales con alto peso
- name: Agregar saldo de datos adicionales
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "Bonus_Data",
"Value": 5368709120, # 5GB
"ExpiryTime": "+240h", # 10 días
"Weight": 20 # Mayor prioridad
}
}]
}

# Agregar datos regulares con peso normal
- name: Agregar saldo de datos regulares
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "Regular_Data",
"Value": 53687091200, # 50GB
"ExpiryTime": "+720h", # 30 días
"Weight": 10 # Prioridad normal
}
}]
}

Experiencia del Cliente:

  • Tiene 5GB de datos adicionales (peso 20) + 50GB de datos regulares (peso 10)
  • Consume primero todos los 5GB de datos adicionales
  • Luego consume del pool de 50GB de datos regulares
  • Los datos regulares se preservan por más tiempo

Identificadores de Acción Comunes​

CGRateS admite múltiples identificadores de acción para diferentes operaciones:

Manipulación de Saldos​

*topup - Agregar al saldo existente (rollover) *topup_reset - Restablecer saldo a nuevo valor (sin rollover) *debit - Restar del saldo *debit_reset - Establecer saldo a valor negativo *reset_account - Eliminar todos los saldos

Diseño de Productos Adicionales​

Al diseñar productos adicionales en OmniCRM, considere estas preguntas:

Pregunta 1: ¿Deben apilarse los saldos?​

Sí (Independiente) → Use ID de Saldo únicos (con UUID) No (Reemplazar) → Use ID de Saldo fijo con *topup_reset Sí (Rollover) → Use ID de Saldo fijo con *topup

Pregunta 2: ¿Qué pasa con el saldo no utilizado?​

Rollover → Use acción *topup Perdido → Use acción *topup_reset Pools separados → Use ID de Saldo únicos

Pregunta 3: ¿Cómo deben consumirse los saldos?​

Primero el más antiguo → Use diferentes pesos (asigne un peso más alto a los saldos más antiguos/próximos a expirar) Primero el premium → Diferentes pesos (peso más alto = mayor prioridad) Orden específico → Use pesos: 30 (premium), 20 (bonus), 10 (regular) Aleatorio/Sin preferencia → Use el mismo peso (el orden de consumo no está garantizado)

Pregunta 4: ¿Cuál es la estrategia de expiración?​

Duración fija → Use expiración relativa (+720h para 30 días) Fin de mes → Use *monthly en ActionPlan Nunca expira → Use *unlimited o duración muy larga

Estructura de Acción de CGRateS en Playbooks​

Aquí está la estructura completa para crear una Acción:

- name: Crear Acción de CGRateS
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_Name_Here",
"Overwrite": true, # Reemplazar si existe
"Actions": [
{
"Identifier": "*topup", # o *topup_reset
"BalanceType": "*data", # *data, *voice, *sms, *monetary
"Units": 5368709120, # Monto a agregar
"ExpiryTime": "+120h", # +Xh, *unlimited, *monthly
"DestinationIds": "*any", # Usualmente *any
"BalanceId": "Balance_Name", # Único o compartido
"Weight": 10, # Prioridad (más alto = consumido primero)
"Blocker": false, # Si es verdadero, evitar saldo negativo
"Disabled": false, # Si es verdadero, el saldo está desactivado
"SharedGroups": "" # Grupo de saldo compartido (opcional)
},
{
"Identifier": "*cdrlog", # Registrar esta acción como CDR
"BalanceType": "*generic",
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"Addon Name\"}"
}
]
}]
}

Descripciones de Campos​

ActionsId - Identificador único para este conjunto de acciones

Identifier - El tipo de operación (*topup, *topup_reset, *cdrlog, etc.)

BalanceType - Tipo de saldo:

  • *data - Saldos de datos (bytes)
  • *voice - Saldos de voz (segundos)
  • *sms - Saldos de SMS (conteo)
  • *monetary - Saldos monetarios (unidades de moneda)
  • *generic - Saldos genéricos

Units - Monto a agregar/restar (en unidades base: bytes para datos, segundos para voz)

ExpiryTime - Cuándo expira el saldo:

  • +Xh - Relativo (por ejemplo, +720h = 30 días)
  • *unlimited - Nunca expira
  • *monthly - Fin de mes
  • 2024-12-31T23:59:59Z - Marca de tiempo absoluta

BalanceId - Identificador para este saldo (ID compartido = interactúa, ID único = independiente)

Weight - Prioridad (número más alto = mayor prioridad, consumido primero)

Blocker - Si es verdadero, evita que la cuenta se vuelva negativa

Disabled - Si es verdadero, el saldo existe pero no se puede usar

Definiendo Acciones a través de Python (Configuración Inicial)​

Las acciones se definen típicamente durante la configuración inicial del sistema utilizando scripts de Python con la biblioteca cgrateshttpapi. Estos ejemplos muestran cómo definir Acciones utilizando OCS_Obj.SendData().

Requisitos Previos​

import cgrateshttpapi
import time

OCS_Obj = cgrateshttpapi.CGRateS("ocs.example.com", "2080")
tenant = "your_tenant_name"
tpid = str(tenant) + "_" + str(int(time.time()))

Definición de Destinos​

Antes de crear Acciones, debes definir destinos que especifiquen DÓNDE se pueden usar los saldos.

Los Destinos vienen en dos tipos:

  • Destinos Geográficos - Prefijos de número para voz/SMS A lugares (por ejemplo, Dest_International_UK)
  • Destinos PLMN - Códigos de red para datos DESDE lugares (por ejemplo, Dest_PLMN_OnNet, Dest_PLMN_US_Verizon)

Regla Crítica:

  • Saldos de voz/SMS → Usa destinos geográficos (el número que se llama A)
  • Saldos de datos → Usa destinos PLMN (la red a la que está conectado el cliente DESDE)

Para la configuración completa de destinos, incluyendo:

  • Destinos geográficos (nacionales, internacionales, gratuitos, premium)
  • Destinos PLMN (en red, redes de roaming, zonas)
  • Reglas de formato PLMN y mejores prácticas
  • Solución de problemas de destinos

Consulta: Configuración de Destinos CGRateS

Cálculos de Unidades​

Entender las conversiones de unidades es crítico para definir los saldos correctamente:

# Saldos de datos (en bytes)
1_GB = 1 * 1024 * 1024 * 1024 # 1073741824 bytes
100_GB = 100 * 1024 * 1024 * 1024

# Saldos de voz (en nanosegundos)
1_minute = 60 * 1000000000 # 60 mil millones de nanosegundos
3000_minutes = 3000 * 60 * 1000000000

# Saldos de SMS (en cantidad)
3000_sms = 3000

Ejemplo 1: Plan Mensual de Múltiples Saldos (Python)​

Un plan mensual integral con saldos de datos, voz, SMS y roaming que se restablecen cada mes.

Action_AU_Premium_Plan_1 = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_au-premium-plan-1",
"Overwrite": True,
"Tenant": str(tenant),
"Actions": [
# Primero, restablecer la cuenta para limpiar saldos antiguos
{
"Identifier": "*reset_account",
"Weight": 700
},
# Agregar saldo de datos de 100GB
# IMPORTANTE: Los saldos de datos utilizan destinos PLMN (la red a la que está conectado el cliente)
# NO destinos geográficos. Usa TU PLMN en red.
{
"Identifier": "*topup_reset",
"BalanceId": "AU_Data_Domestic__" + str(100 * 1024 * 1024 * 1024),
"BalanceType": "*data",
"DestinationIDs": "Dest_PLMN_OnNet", # Tu PLMN en red (mcc505.mnc057)
"Units": 100 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 90
},
# Agregar saldo de voz de 3000 minutos
{
"Identifier": "*topup_reset",
"BalanceId": "AU_Voice_Domestic__" + str(3000 * 60 * 1000000000),
"BalanceType": "*voice",
"DestinationIDs": "Dest_AU_Mobile;Dest_AU_Fixed;Dest_AU_TollFree;",
"Units": 3000 * 60 * 1000000000,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 89
},
# Agregar saldo de 3000 SMS
{
"Identifier": "*topup_reset",
"BalanceId": "AU_SMS_Domestic__" + str(3000),
"BalanceType": "*sms",
"DestinationIDs": "Dest_AU_Mobile;",
"Units": 3000,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 88
},
# Agregar 6GB de datos de roaming
{
"Identifier": "*topup_reset",
"BalanceId": "AU_Roaming_Data__" + str(6 * 1024 * 1024 * 1024),
"BalanceType": "*data",
"DestinationIDs": "Dest_Roaming_All",
"Units": 6 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1100,
"Weight": 87
},
# Registrar esta acción como un CDR
{
"Identifier": "*cdrlog",
"BalanceId": "",
"BalanceUuid": "",
"BalanceType": "*generic",
"Directions": "*out",
"Units": 0,
"ExpiryTime": "",
"Filter": "",
"TimingTags": "",
"DestinationIds": "",
"RatingSubject": "",
"Categories": "",
"SharedGroups": "",
"BalanceWeight": 0,
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"AU Premium Plan 1\"}",
"BalanceBlocker": "false",
"BalanceDisabled": "false",
"Weight": 80
}
]
}]
}

# Enviar la definición de la acción a CGRateS
result = OCS_Obj.SendData(Action_AU_Premium_Plan_1)
assert result['error'] is None or result['error'] == "EXISTS"
print("Acción creada: Action_au-premium-plan-1")

Puntos Clave:

  • Utiliza *reset_account para limpiar saldos antiguos primero
  • Utiliza *topup_reset para asignaciones mensuales fijas (sin acumulación)
  • BalanceWeight determina el orden de consumo (nacional 1200 > roaming 1100)
  • Weight determina el orden de ejecución dentro de la Acción
  • Incluye *cdrlog para rastrear activaciones

Ejemplo 2: Complemento de Datos Simple (Python)​

Un complemento de datos simple de 20GB con acumulación desactivada.

Action_AU_Data_Addon_20GB = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_au-data-addon-20gb",
"Overwrite": True,
"Tenant": str(tenant),
"Actions": [
# Restablecer la cuenta primero
{
"Identifier": "*reset_account",
"Weight": 700
},
# Agregar 20GB de datos
# Los saldos de datos utilizan destinos PLMN (en qué red está el cliente)
{
"Identifier": "*topup_reset",
"BalanceId": "AU_Data_Domestic__" + str(20 * 1024 * 1024 * 1024),
"BalanceType": "*data",
"DestinationIDs": "Dest_PLMN_OnNet", # Tu PLMN en red (mcc505.mnc057)
"Units": 20 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 90
}
]
}]
}

result = OCS_Obj.SendData(Action_AU_Data_Addon_20GB)
assert result['error'] is None or result['error'] == "EXISTS"
print("Acción creada: Action_au-data-addon-20gb")

Ejemplo 3: Complemento de Voz Internacional (Python)​

Un complemento para minutos de llamadas internacionales.

Action_AU_International_Voice_100min = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_au-international-voice-100min",
"Overwrite": True,
"Tenant": str(tenant),
"Actions": [
{
"Identifier": "*reset_account",
"Weight": 700
},
# Agregar 100 minutos para llamadas internacionales
{
"Identifier": "*topup_reset",
"BalanceId": "AU_Voice_International__" + str(100 * 60 * 1000000000),
"BalanceType": "*voice",
"DestinationIDs": "Dest_International_All",
"Units": 100 * 60 * 1000000000,
"ExpiryTime": "*month",
"BalanceWeight": 1000,
"Weight": 90
}
]
}]
}

result = OCS_Obj.SendData(Action_AU_International_Voice_100min)
assert result['error'] is None or result['error'] == "EXISTS"
print("Acción creada: Action_au-international-voice-100min")

Nota: La voz/SMS utiliza destinos geográficos (número que se llama), mientras que los datos utilizan destinos PLMN (red a la que está conectado el cliente). Consulta Definición de Productos para la configuración de destinos.

Referencia de Campos de Acción en Python​

Campos de Definición de Acción:

  • ActionsId (requerido) - Identificador único para este conjunto de acciones (debe coincidir con la convención product_slug en CRM)
  • Overwrite - Si es verdadero, reemplaza la acción existente con el mismo ID
  • Tenant - Nombre del inquilino de CGRateS
  • Actions - Array de acciones individuales a ejecutar

Campos de Acción Individual:

  • Identifier - Tipo de acción (*topup, *topup_reset, *reset_account, *cdrlog, etc.)
  • BalanceId - Identificador único para este saldo (debe coincidir en los recargas para que la acumulación funcione)
  • BalanceType - Tipo de saldo (*data, *voice, *sms, *monetary)
  • DestinationIDs - Controla DÓNDE se puede usar el saldo:
    • Para voz/SMS: Usa destinos geográficos (por ejemplo, "Dest_AU_Mobile", "Dest_International_UK")
    • Para datos: Usa destinos PLMN (por ejemplo, "Dest_PLMN_OnNet", "Dest_PLMN_US_Verizon")
  • Units - Cantidad a agregar (bytes para datos, nanosegundos para voz, cantidad para SMS)
  • ExpiryTime - Cuándo expira el saldo (*month, +720h, 2024-12-31, etc.)
  • BalanceWeight - Prioridad de consumo (más alto = consumido primero)
  • Weight - Orden de ejecución dentro del conjunto de acciones (más alto = se ejecuta primero)
  • Blocker (opcional) - Bandera booleana; si es True, bloquea todo uso cuando este saldo llega a cero (ver Bloqueadores de Saldo)
  • Disabled (opcional) - Bandera booleana; si es True, este saldo es ignorado/saltado durante el consumo

Ejecución de Acciones​

Una vez que se crea una Acción, ejecútala en una cuenta:

- name: Ejecutar Acción en Cuenta
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "APIerSv1.ExecuteAction",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"ActionsId": "Action_Name_Here"
}]
}

Esto ejecuta todas las operaciones definidas en la Acción en la cuenta especificada.

Enfoques de Gestión de Saldos​

Hay tres enfoques principales para gestionar saldos en CGRateS, cada uno con diferentes compensaciones para la experiencia del cliente, la previsibilidad de la facturación y la complejidad operativa.

Comparación: Unitario vs Monetario vs Híbrido​

Esta tabla resume las compensaciones entre los tres enfoques de saldo:

CaracterísticaUnitarioMonetario (PAYG)Híbrido
Previsibilidad del Cliente✅ Costo mensual fijo❌ Costos variables⚠️ Mayormente predecible
Flexibilidad de Destino❌ Limitado a destinos incluidos✅ Llamar/utilizar en cualquier lugar✅ Incluido + en cualquier lugar
Manejo de Excesos❌ Corte duro✅ Uso automático✅ Desbordamiento automático
Riesgo de Shock de Factura✅ Bajo (límites duros)❌ Alto (facturación ilimitada)⚠️ Moderado (desbordamiento limitado)
Complejidad de Configuración⚠️ Moderada (muchos saldos)✅ Simple (un saldo)❌ Complejo (ambos)
Optimización de Ingresos⚠️ Menor ARPU✅ Mayor ARPU de usuarios intensivos✅ ARPU equilibrado
Satisfacción del Cliente✅ Alta (sin sorpresas)❌ Baja (shock de factura)✅ Alta (lo mejor de ambos)
Mejor ParaUsuarios predeciblesUsuarios ocasionalesLa mayoría de los clientes

Enfoque 1: Saldos Unitarios​

Concepto: Proporcionar cantidades específicas para destinos específicos. Cada saldo tiene una cantidad fija (minutos, GB, conteo de SMS) vinculada a destinos específicos. Cuando se agota, el uso se bloquea a menos que haya un respaldo monetario.

Ejemplo: Plan Nacional con Múltiples Saldos

Action_Domestic_Plan = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_domestic-plan",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
{
"Identifier": "*reset_account",
"Weight": 700
},
# 500 minutos de llamadas nacionales
{
"Identifier": "*topup_reset",
"BalanceId": f"Domestic_Voice__{500 * 60 * 1000000000}",
"BalanceType": "*voice",
"DestinationIDs": "Dest_Domestic_All", # SOLO nacional
"Units": 500 * 60 * 1000000000, # 500 minutos en nanosegundos
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 90
},
# 1000 SMS nacionales
{
"Identifier": "*topup_reset",
"BalanceId": "Domestic_SMS__1000",
"BalanceType": "*sms",
"DestinationIDs": "Dest_Domestic_All",
"Units": 1000,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 89
},
# 10GB de datos nacionales
{
"Identifier": "*topup_reset",
"BalanceId": f"Domestic_Data__{10 * 1024 * 1024 * 1024}",
"BalanceType": "*data",
"DestinationIDs": "Dest_PLMN_OnNet", # Tu PLMN en red
"Units": 10 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 88
},
{
"Identifier": "*cdrlog",
"BalanceType": "*generic",
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"Plan Nacional\"}",
"Weight": 80
}
]
}]
}

result = OCS_Obj.SendData(Action_Domestic_Plan)
assert result['error'] is None or result['error'] == "EXISTS"

Cómo Funciona Esto:

  • Llamadas nacionales (1-555-1234) → Utiliza saldo de 500 minutos
  • Llamadas internacionales (44-20-xxx) → NO hay saldo disponible, bloqueado O utiliza saldo monetario si está disponible
  • SMS nacionales → Utiliza saldo de 1000 SMS
  • Uso de datos en casa → Utiliza saldo de 10GB
  • Datos de roaming → NO hay saldo disponible (necesitaría saldo de datos de roaming separado)

Pros:

  • Costos predecibles para los clientes
  • Sin shock de factura
  • Límites claros

Contras:

  • Menos flexible - no se puede utilizar el servicio fuera de los destinos incluidos
  • Requiere múltiples saldos para diferentes casos de uso
  • El cliente puede sentirse restringido

Enfoque 2: Monetario (PAYG)​

Concepto: Proporcionar crédito monetario cobrado a tarifas específicas de destino. Un solo saldo monetario utilizado para TODOS los tipos de uso. CGRateS busca la tarifa para cada destino y deduce el costo del crédito.

Nota: PAYG requiere definir Perfiles de Tarifas para cada destino para establecer el monto en dólares por unidad. Consulta Perfiles de Tarifas para Saldos PAYG/Monetarios para la configuración completa.

Ejemplo: Crédito PAYG de $50

Action_PAYG_Credit = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_payg-50-credit",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
# Saldo monetario de $50
{
"Identifier": "*topup",
"BalanceId": "PAYG_Monetary_Balance",
"BalanceType": "*monetary",
"DestinationIDs": "*any", # Funciona para CUALQUIER destino
"Units": 5000, # $50.00 (en centavos)
"ExpiryTime": "+2160h", # 90 días
"BalanceWeight": 1000, # Menor que los saldos unitarios
"Weight": 90
},
{
"Identifier": "*cdrlog",
"BalanceType": "*generic",
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"$50 Crédito PAYG\"}",
"Weight": 80
}
]
}]
}

result = OCS_Obj.SendData(Action_PAYG_Credit)

Cómo Funciona PAYG:

Escenario 1: Llamada nacional, 10 minutos

  • Tarifa: $0.10/min
  • Cargo: 10 × $0.10 = $1.00
  • Restante: $49.00

Escenario 2: Llamada al Reino Unido, 5 minutos

  • Tarifa: $0.25/min + $0.05 de tarifa de conexión
  • Cargo: (5 × $0.25) + $0.05 = $1.30
  • Restante: $47.70

Escenario 3: Roaming en Verizon, 100MB de datos

  • Tarifa: $2.00/MB
  • Cargo: 100 × $2.00 = $200.00
  • Resultado: Fondos insuficientes → Sesión bloqueada a ~$47 de valor (~23MB)

Pros:

  • Un saldo para todo - muy flexible
  • El cliente puede utilizar el servicio en cualquier lugar donde se definan tarifas
  • Configuración simple

Contras:

  • Costos impredecibles para los clientes
  • Riesgo de shock de factura (especialmente en roaming)
  • Puede ser costoso para usuarios intensivos

Enfoque 3: Híbrido (Lo Mejor de Ambos)​

Concepto: Combinar saldos unitarios con respaldo monetario. Utilizar saldos unitarios de alto peso para el uso incluido, con un saldo monetario de bajo peso como desbordamiento. La mejor experiencia para el cliente con un costo base predecible y sobrecargas flexibles.

Ejemplo: Plan Híbrido Flexible

Action_Hybrid_Plan = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [{
"ActionsId": "Action_hybrid-flex-plan",
"Overwrite": True,
"Tenant": tenant,
"Actions": [
{
"Identifier": "*reset_account",
"Weight": 700
},

# ============= SALDOS UNITARIOS (Incluidos) =============
# 500 minutos de voz nacional
{
"Identifier": "*topup_reset",
"BalanceId": f"Domestic_Voice__{500 * 60 * 1000000000}",
"BalanceType": "*voice",
"DestinationIDs": "Dest_Domestic_All",
"Units": 500 * 60 * 1000000000,
"ExpiryTime": "*month",
"BalanceWeight": 1200, # Consumido PRIMERO para llamadas nacionales
"Weight": 95
},
# 100 minutos de voz internacional
{
"Identifier": "*topup_reset",
"BalanceId": f"International_Voice__{100 * 60 * 1000000000}",
"BalanceType": "*voice",
"DestinationIDs": "Dest_International_All",
"Units": 100 * 60 * 1000000000,
"ExpiryTime": "*month",
"BalanceWeight": 1150, # Consumido PRIMERO para internacionales
"Weight": 94
},
# 1000 SMS nacionales
{
"Identifier": "*topup_reset",
"BalanceId": "Domestic_SMS__1000",
"BalanceType": "*sms",
"DestinationIDs": "Dest_Domestic_All",
"Units": 1000,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 93
},
# 15GB de datos nacionales
{
"Identifier": "*topup_reset",
"BalanceId": f"Domestic_Data__{15 * 1024 * 1024 * 1024}",
"BalanceType": "*data",
"DestinationIDs": "Dest_PLMN_OnNet",
"Units": 15 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1200,
"Weight": 92
},
# 2GB de datos de roaming (Zona 1)
{
"Identifier": "*topup_reset",
"BalanceId": f"Roaming_Zone1_Data__{2 * 1024 * 1024 * 1024}",
"BalanceType": "*data",
"DestinationIDs": "Dest_PLMN_Zone_NorthAmerica",
"Units": 2 * 1024 * 1024 * 1024,
"ExpiryTime": "*month",
"BalanceWeight": 1100,
"Weight": 91
},

# ============= SALDO MONETARIO (Desbordamiento/PAYG) =============
# $20 para sobrecargas
{
"Identifier": "*topup",
"BalanceId": "PAYG_Overflow_Balance",
"BalanceType": "*monetary",
"DestinationIDs": "*any",
"Units": 2000, # $20.00
"ExpiryTime": "*month",
"BalanceWeight": 1000, # Consumido ÚLTIMO (respaldo)
"Weight": 90
},

{
"Identifier": "*cdrlog",
"BalanceType": "*generic",
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"Plan Híbrido Flexible\"}",
"Weight": 80
}
]
}]
}

result = OCS_Obj.SendData(Action_Hybrid_Plan)

Flujo de Consumo de Balance:

Ejemplos de Escenarios:

Escenario 1: 600 minutos nacionales utilizados

  1. Primeros 500 minutos → Usa "Domestic_Voice_500min" (peso 1200) - GRATIS
  2. Siguientes 100 minutos → "Domestic_Voice_500min" agotado, recurre a "PAYG_Overflow_Balance" (peso 1000)
  3. Cargado: 100 min × $0.10 = $10.00 del balance monetario
  4. Restante: $10.00 monetarios

Escenario 2: 150 minutos internacionales (a Reino Unido)

  1. Primeros 100 minutos → Usa "International_Voice_100min" (peso 1150) - GRATIS
  2. Siguientes 50 minutos → Recurre a "PAYG_Overflow_Balance"
  3. Cargado: (50 × $0.25) + $0.05 conexión = $12.55
  4. Restante: $7.45 monetarios (si comienza con $20)

Ventajas:

  • Costo base predecible
  • Flexibilidad para sobrecargas ocasionales
  • Mejor experiencia para el cliente
  • Sin corte abrupto - el servicio continúa

Desventajas:

  • Más complejo de configurar
  • Más complejo de explicar a los clientes
  • Requiere una gestión cuidadosa del peso del balance

Escenarios de Uso en el Mundo Real​

Estos escenarios demuestran cómo los conceptos se unen en la práctica. Cada uno muestra el flujo completo desde el evento de uso hasta la deducción o bloqueo del balance.

Escenario 1: Cliente en Casa Llama al Reino Unido​

El cliente tiene: Plan Nacional (500 min nacionales, 1000 SMS, 10GB de datos)

Acción: Llama a un número del Reino Unido (44-20-7946-0958) durante 10 minutos

Verificación de Balance:

  1. CGRateS recibe llamada a 44207946...
  2. Coincide destino: Dest_International_UK
  3. Verifica balance con DestinationIDs: "Dest_International_UK"
  4. NO se encontró balance coincidente
  5. Verifica balance monetario
  6. NO se encontró balance monetario
  7. Resultado: Llamada BLOQUEADA (saldo insuficiente)

Solución: El cliente necesita un Plan Internacional O crédito PAYG para realizar llamadas al Reino Unido

Escenario 2: Cliente en Roaming en EE. UU. Usa Datos​

El cliente tiene: Plan Nacional + complemento de Roaming en EE. UU. de 5GB

Acción: Roaming en Verizon (PLMN mcc310.mnc004), usa 2GB de datos

Verificación de Balance:

  1. CGRateS recibe sesión de datos en PLMN mcc310.mnc004
  2. Coincide destino: Dest_PLMN_US_Verizon
  3. Verifica balance de datos con DestinationIDs: "Dest_PLMN_US_All" (coincidencia más amplia)
  4. Encuentra: balance "Roaming_US_Data_5GB" (BalanceWeight: 1100)
  5. Deduce 2GB
  6. Restante: 3GB de datos de roaming

¿Qué pasa si usaron 6GB?

  1. Primeros 5GB → Usa balance de roaming (agotado)
  2. Siguiente 1GB → Verifica balance monetario
  3. NO hay balance monetario → Sesión bloqueada en 5GB

Escenario 3: Cliente con Plan Híbrido Excede Minutos Nacionales​

El cliente tiene: Plan Híbrido (500 min nacionales + $20 de sobrecarga)

Acción: Realiza 600 minutos de llamadas nacionales

Verificación de Balance:

  1. Primeros 500 minutos:
    • Usa "Domestic_Voice_500min" (BalanceWeight: 1200)
    • Sin cargo
  2. "Domestic_Voice_500min" agotado
  3. Siguientes 100 minutos:
    • Recurre a "PAYG_Overflow_Balance" (BalanceWeight: 1000)
    • Tarifa: $0.10/min
    • Cargo: 100 × $0.10 = $10.00
    • Deducido de $20 de balance monetario
    • Restante: $10.00

Facturación:

  • El cliente ve: 500 minutos incluidos + 100 minutos de sobrecarga ($10.00)

Escenario 4: Usuario de PAYG Roaming Inesperadamente​

El cliente tiene: $50 de crédito PAYG

Acción: Viaja a EE. UU., hace roaming en Verizon, usa 100MB de datos (sin saberlo)

Cálculo de Cargo:

  1. 100MB en Verizon
  2. Tarifa: $2.00/MB (de tarifas PAYG)
  3. Cargo total: 100 × $2.00 = $200.00
  4. Disponibles: $50.00
  5. Resultado: El cliente usa ~25MB antes de que el crédito se agote, sesión bloqueada
  6. ¡Shock de factura! El cliente consumió inesperadamente todo el $50

Mejor enfoque: Recomendar complemento de roaming para evitar shock de factura

Mejores Prácticas​

1. Usar IDs de Balance Descriptivos​

Buenos IDs de Balance son auto-documentados:

# Bueno
"Data_5GB_5days_{{ uuid }}"
"Voice_100min_Monthly"
"Bonus_Data_Loyalty"

# Malo
"balance1"
"data"
"temp"

2. Documentar Tu Estrategia de Peso​

Definir un esquema de peso consistente en todos los productos:

# Esquema de peso:
# 30 = Balances Premium/Promocionales
# 20 = Balances de Bonificación/Loyalty
# 10 = Balances Regulares/Comprados
# 5 = Balances de Respaldo/Fallback

3. Incluir Registro de CDR​

Siempre registra adiciones de balance para auditorías:

{
"Identifier": "*cdrlog",
"BalanceType": "*generic",
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"{{ package_name }}\"}"
}

4. Usar ActionPlans para Operaciones Recurrentes​

Para reinicios mensuales, no ejecutes la Acción manualmente. Usa ActionPlans:

# Crear ActionPlan que se ejecute mensualmente
- name: Crear ActionPlan mensual
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.SetActionPlan",
"params": [{
"Id": "ActionPlan_Monthly_Reset",
"ActionPlan": [{
"ActionsId": "Action_Monthly_Reset",
"Time": "*monthly",
"Weight": 10
}],
"ReloadScheduler": true
}]
}

5. Restablecer ActionTriggers Después de Recarga​

Después de ejecutar una acción, restablece los triggers para evitar notificaciones duplicadas:

- name: Restablecer ActionTriggers
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "APIerSv1.ResetAccountActionTriggers",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"Executed": false
}]
}

6. Establecer Pesos de Balance Apropiados​

Usar una estrategia de peso consistente en todos los productos:

# Prioridad de consumo (de mayor a menor)
BalanceWeight: 1200 # Nacional incluido (usar primero en casa)
BalanceWeight: 1150 # Internacional incluido (usar primero para intl)
BalanceWeight: 1100 # Roaming incluido (usar primero al hacer roaming)
BalanceWeight: 1000 # Respaldo monetario (usar al final)

Esto asegura un orden de consumo predecible: balances nacionales primero, luego internacionales, luego roaming, y finalmente PAYG monetario como respaldo.

7. Controlar el Uso del Balance con DestinationIDs​

Siempre usa DestinationIDs específicos para evitar usos no intencionados:

# Bueno - control de destino explícito
{
"BalanceType": "*voice",
"DestinationIDs": "Dest_International_UK", # SOLO Reino Unido
"Units": 200 * 60 * 1000000000
}

# Malo - uso no intencionado
{
"BalanceType": "*voice",
"DestinationIDs": "*any", # ¡Podría usarse para números premium!
"Units": 200 * 60 * 1000000000
}

8. Agrupar Destinos Lógicamente​

Crear grupos de destinos que tengan sentido para tu oferta de productos:

# Bueno - agrupación lógica
"Dest_International_Europe" = Todos los países de la UE (pool compartido de 500min)

# Malo - demasiado granular
"Dest_Francia", "Dest_Alemania", "Dest_Italia" (pools pequeños separados)

Consulta CGRateS Destinations para ejemplos de agrupación de destinos.

9. Incluir Respaldo Monetario en los Planes​

Para la mejor experiencia del cliente, incluye un pequeño balance monetario como sobrecarga:

# Recomendado: Siempre incluir pequeño balance monetario
{
"BalanceType": "*monetary",
"Units": 1000, # $10 de protección contra sobrecargas
"BalanceWeight": 1000 # Menor que los balances unitarios
}

Esto previene cortes de servicio abruptos y proporciona flexibilidad para sobrecargas ocasionales.

10. Usar Incrementos de Tarifa Estratégicamente​

Elegir incrementos de tarifa apropiados para diferentes tipos de servicio:

# Nacional: Amigable para el cliente por segundo
"RateIncrement": "1s"

# Internacional: Bloques estándar de 6 segundos
"RateIncrement": "6s"

# Premium: Bloques de 30 segundos para desalentar abusos
"RateIncrement": "30s"

# Datos: Por KB para precisión
"RateIncrement": "1024"

11. Establecer Tiempos de Expiración Razonables​

Ajustar los tiempos de expiración a los tipos de productos:

# Planes de suscripción mensual
"ExpiryTime": "*month"

# Recargas/complentos únicos
"ExpiryTime": "+720h" # 30 días

# Crédito PAYG (validez más larga)
"ExpiryTime": "+2160h" # 90 días

# Complementos de roaming (basados en el viaje)
"ExpiryTime": "+360h" # 15 días

Solución de Problemas​

Problema: Balance No Añadido​

Síntomas: La acción se ejecuta con éxito pero el balance no aparece

Causas Posibles:

  • UUID de cuenta incorrecto
  • Desajuste de BalanceType
  • La expiración ya ha pasado

Solución: Verifica que la cuenta exista y revisa el tiempo de expiración del balance

Problema: Balance Consumido Incorrectamente​

Síntomas: El sistema consume de un balance inesperado

Causas Posibles:

  • Configuración de peso incorrecta
  • Múltiples balances con el mismo ID

Solución: Revisa los valores de peso y asegúrate de que los IDs de Balance sean únicos si se desea independencia

Problema: Rollover No Funciona​

Síntomas: Usando *topup pero el balance antiguo no se transfiere

Causas Posibles:

  • Usando diferentes IDs de Balance (necesita el mismo ID)
  • Acción usando *topup_reset en lugar de *topup

Solución: Verifica la consistencia del ID de Balance y el tipo de acción

Problema: Balance Expira Inmediatamente​

Síntomas: Balance añadido pero muestra como expirado

Causas Posibles:

  • ExpiryTime en el pasado
  • Usando timestamp absoluto en lugar de relativo

Solución: Usa expiración relativa (+Xh) en lugar de timestamps absolutos

Problema: Balance No Está Siendo Consumido​

Síntoma: El cliente tiene balance pero aún bloqueado o cargado PAYG

Causas Posibles:

  1. Desajuste de DestinationIDs - Los destinos de balance no coinciden con el destino de uso
  2. Balance expirado
  3. Tipo de balance incorrecto para el uso

Pasos de Depuración:

# Verifica los balances de la cuenta
OCS_Obj.SendData({
'method': 'ApierV2.GetAccount',
'params': [{"Tenant": tenant, "Account": "service_uuid"}]
})

# Verifica qué se devuelve:
# - ¿El balance existe?
# - ¿DestinationIDs correctos?
# - ¿ExpiryTime en el futuro?
# - ¿Units > 0?

Solución: Verifica que el destino coincida y que el balance esté activo. Consulta Escenario 1: Cliente en Casa Llama al Reino Unido para un ejemplo.

Problema: Tarifa Incorrecta Aplicada​

Síntoma: Cliente cargado con un monto incorrecto por uso PAYG

Causas Posibles:

  1. Superposición de destinos (precedencia incorrecta en RatingPlan)
  2. Pesos de enlace del plan de tarifas incorrectos
  3. La definición de tarifa tiene valores incorrectos

Solución:

  • Asegúrate de que los destinos específicos tengan mayor peso en los enlaces del RatingPlan
  • Verifica que la coincidencia de prefijo más largo esté funcionando correctamente
  • Verifica que los valores y los incrementos de tarifas sean correctos

Consulta Perfiles de Tarifas para Balances PAYG/Monetarios para una configuración adecuada.

Problema: Balance de Roaming No Usado​

Síntoma: Cliente en roaming, tiene balance de roaming, pero cargado PAYG o bloqueado

Causas Posibles:

  1. Desajuste de destino PLMN - El balance no incluye el PLMN visitado
  2. Cliente conectado a una red incorrecta/inesperada
  3. DestinationIDs no coinciden con el PLMN real

Solución:

# Verifica en qué PLMN está el cliente (de CDRs o eventos de uso)
# Verifica que el balance incluya ese PLMN:
"DestinationIDs": "Dest_PLMN_US_All" # Debería incluir mcc310.mnc004

Consulta CGRateS Destinations para la configuración de destinos PLMN y Escenario 2: Cliente en Roaming en EE. UU. Usa Datos para un ejemplo funcional.

Problema: Plan Híbrido No Recurre a Monetario​

Síntoma: Balance unitario agotado pero no se usa el balance monetario

Causas Posibles:

  1. El balance monetario tiene restricción de DestinationIDs (debería ser *any)
  2. No se definieron tarifas PAYG para ese destino
  3. Problema de peso de balance - el peso del balance monetario no es menor que el unitario

Solución:

  • Asegúrate de que el balance monetario tenga DestinationIDs: "*any"
  • Verifica que se definan tarifas PAYG para todos los destinos que el cliente podría usar
  • Revisa los pesos de balance: el monetario debe ser el más bajo (por ejemplo, 1000)

Consulta Enfoque 3: Híbrido para una configuración híbrida adecuada.

Problema: Cargos Internacionales Inesperados​

Síntoma: Cliente llamó a un número nacional, cargado con tarifas internacionales

Causas Posibles:

  1. El número es en realidad internacional (por ejemplo, número de Canadá +1 tratado como internacional)
  2. Superposición de prefijos en las definiciones de destino
  3. Cliente marcó incorrectamente (agregó dígitos extra)

Solución:

  • Verifica los CDRs para el número marcado real
  • Verifica que las definiciones de prefijo de destino no se superpongan incorrectamente
  • Considera un destino separado para Canadá si los países NANP necesitan tarifas diferentes

Consulta CGRateS Destinations para la configuración de destinos geográficos.

Documentación Relacionada​

Conceptos Básicos​

Implementación y Operaciones​