Skip to main content

Sistema de Validación

El sistema de validación de Paso Rápido ejecuta automáticamente 4 tipos de validación para detectar fraudes, duplicados y errores en los cargos de peaje. Esta sección explica en detalle cómo funciona cada validación.

Visión General del Proceso

1

Activación Automática

Las validaciones se ejecutan automáticamente cuando:
  • Se importan nuevos cargos de peaje
  • Se solicita validación manual desde la interfaz
  • Se ejecuta un proceso programado (cron job)
El sistema puede procesar miles de cargos simultáneamente con alta eficiencia.
2

Preparación de Datos

Antes de validar, el sistema:
  • Sincroniza datos GPS desde ERM Karma API
  • Identifica asignaciones de tags vigentes
  • Consulta tarifas oficiales de estaciones
  • Prepara contexto completo para cada cargo
La preparación garantiza que las validaciones tengan toda la información necesaria.
3

Ejecución en Paralelo

Las 4 validaciones se ejecutan simultáneamente:
  • Validación GPS: Confirma ubicación del vehículo
  • Detección de Duplicados: Identifica cargos repetidos
  • Validación de Categoría: Verifica montos correctos
  • Verificación de Tags: Confirma estado activo
El orden de ejecución no afecta los resultados, pero todas deben completarse.
4

Consolidación de Resultados

El sistema consolida los resultados:
  • Asigna estado final a cada cargo
  • Genera recomendaciones de acción
  • Documenta evidencia para auditoría
  • Actualiza métricas y estadísticas
Los resultados se almacenan permanentemente para análisis histórico.

1. Validación GPS

Objetivo

Confirmar que el vehículo asociado al tag realmente estuvo presente en la estación de peaje en el momento del cargo. Validación GPS mostrando ubicación del vehículo vs estación de peaje

Algoritmo Detallado

  • Fase 1: Búsqueda Temporal
  • Fase 2: Cálculo de Distancia
  • Fase 3: Validación de Coherencia
  • Fase 4: Clasificación Final
Objetivo: Encontrar datos GPS contemporáneos al cargo
# Pseudocódigo simplificado
def buscar_datos_gps(cargo):
    ventana_inicial = 1  # minuto
    ventana_maxima = 5   # minutos
    
    for ventana in range(ventana_inicial, ventana_maxima + 1):
        inicio = cargo.fecha - timedelta(minutes=ventana)
        fin = cargo.fecha + timedelta(minutes=ventana)
        
        mensajes_gps = consultar_gps(
            car_id=cargo.vehiculo.car_id,
            desde=inicio,
            hasta=fin
        )
        
        if mensajes_gps:
            return mensajes_gps
    
    return None  # Sin telemetría
Criterios de búsqueda:
  • Ventana inicial: ±1 minuto del cargo
  • Expansión progresiva hasta ±5 minutos
  • Filtrado por vehículo específico
  • Ordenamiento por proximidad temporal

Casos Especiales

Problema: Pérdida temporal de señal GPS en túneles largos o zonas remotas.Solución implementada:
  • Extrapolación de ruta basada en último punto conocido
  • Tolerancia aumentada en zonas identificadas como problemáticas
  • Validación cruzada con cargos anteriores/posteriores del mismo vehículo
Estaciones afectadas: Túneles urbanos, pasos montañosos, zonas rurales remotas
Problema: Vehículo detenido en cola puede estar lejos de la cabina de cobro.Solución implementada:
  • Radio de tolerancia expandido en horas pico
  • Análisis de velocidad promedio en la zona
  • Consideración de tiempo de espera en cola
Horarios críticos: 7-9 AM, 12-2 PM, 5-7 PM en días laborales
Problema: Varias estaciones de peaje muy próximas pueden generar ambigüedad.Solución implementada:
  • Análisis de dirección de viaje basado en secuencia GPS
  • Correlación con cargos anteriores y posteriores
  • Validación cruzada con datos de tráfico
Ejemplos: Complejos de peaje con múltiples cabinas, bifurcaciones de autopistas

2. Detección de Duplicados

Objetivo

Identificar cargos duplicados que podrían resultar en doble facturación por el mismo paso de peaje.

Algoritmo de Detección

  • Criterios de Matching
  • Tipos de Duplicados
  • Resolución de Duplicados
Campos principales para identificar duplicados:
tag_number
INTEGER
required
Número del tag - debe ser exactamente igual
station_name
TEXT
required
Nombre de la estación - debe coincidir exactamente
charge_date
TIMESTAMP
required
Fecha y hora del cargo - tolerancia de ±10 minutos
amount
DECIMAL
Monto cobrado - tolerancia de ±5% o ±$500 (lo que sea menor)
Algoritmo de scoring:
def calcular_score_duplicado(cargo1, cargo2):
    score = 0
    
    # Tag exacto (+40 puntos)
    if cargo1.tag == cargo2.tag:
        score += 40
    
    # Estación exacta (+30 puntos)
    if cargo1.station == cargo2.station:
        score += 30
    
    # Tiempo similar (+20 puntos)
    diff_minutos = abs((cargo1.fecha - cargo2.fecha).total_seconds() / 60)
    if diff_minutos <= 10:
        score += 20 * (1 - diff_minutos/10)  # Score decreciente
    
    # Monto similar (+10 puntos)
    diff_monto = abs(cargo1.amount - cargo2.amount)
    if diff_monto <= max(500, cargo1.amount * 0.05):
        score += 10 * (1 - diff_monto/max(500, cargo1.amount * 0.05))
    
    return score

# Umbral de duplicado: 70 puntos o más

Patrones de Fraude Detectados

La detección de duplicados también identifica patrones sospechosos que pueden indicar fraude sistemático.
Patrón: El mismo tag genera cargos en estaciones distantes en tiempos imposibles de recorrer.Ejemplo: Tag #123456 cobra en “Peaje Norte Km 45” a las 14:30 y en “Peaje Sur Km 80” a las 14:35.Implicación: Posible clonación del tag o error en el sistema.Acción: Inhabilitación temporal del tag e investigación.
Patrón: Un tag genera cargos muy frecuentes en la misma estación.Ejemplo: 15 cargos en la misma estación en un día (normal: 2-4 máximo).Implicación: Posible mal funcionamiento del tag o fraude.Acción: Análisis de ruta GPS para confirmar legitimidad.
Patrón: El mismo tag genera cargos con montos muy variables en la misma estación.Ejemplo: Alternancia entre categoría 1 (5,000)ycategorıˊa4(5,000) y categoría 4 (16,000) sin justificación.Implicación: Posible manipulación manual o error sistemático.Acción: Revisión de asignaciones de categoría del vehículo.

3. Validación de Categoría

Objetivo

Verificar que el monto cobrado corresponde a la categoría correcta del vehículo según las tarifas oficiales. Análisis de validación de categorías y montos

Proceso de Validación

  • Determinación de Categoría
  • Consulta de Tarifas
  • Comparación y Clasificación
Paso 1: Identificar el vehículo asociado al cargo
def obtener_vehiculo_por_tag(tag_number, fecha_cargo, org_id):
    # Buscar asignación vigente en la fecha del cargo
    asignacion = db.query("""
        SELECT car_id, category 
        FROM tag_assignments 
        WHERE tag_number = %s 
        AND org_id = %s
        AND date <= %s 
        AND (expires_at IS NULL OR expires_at >= %s)
        AND status = 'Valido'
        ORDER BY date DESC 
        LIMIT 1
    """, [tag_number, org_id, fecha_cargo, fecha_cargo])
    
    if not asignacion:
        return None, "Tag sin asignación válida"
    
    vehiculo = db.get_car(asignacion.car_id)
    return vehiculo, asignacion.category
Paso 2: Determinar categoría esperada

Categoría 1

Vehículos:
  • Automóvil
  • Motocicleta
  • SUV pequeño
Identificación:
  • car_type: “Automóvil”, “Motocicleta”
  • sub_type: “Sedán”, “Hatchback”

Categoría 2

Vehículos:
  • Camioneta
  • SUV grande
  • Furgoneta
Identificación:
  • car_type: “Camioneta”
  • sub_type: “Pickup”, “SUV”

Categoría 3

Vehículos:
  • Bus
  • Camión 2 ejes
  • Furgón grande
Identificación:
  • car_type: “Bus”, “Camión”
  • Ejes: 2

Categoría 4

Vehículos:
  • Camión 3+ ejes
  • Tractomula sencilla
Identificación:
  • car_type: “Camión”
  • Ejes: 3 o más

Categoría 5

Vehículos:
  • Tractomula + remolque
  • Vehículos especiales
Identificación:
  • car_type: “Tractomula”
  • sub_type: “Con remolque”

Casos Especiales de Categoría

Situación: Concesionarias aplican descuentos temporales o promociones especiales.Detección: Múltiples vehículos de la misma categoría cobrados con monto menor en fechas específicas.Manejo:
  • Se marca como “Cobro Menor” inicialmente
  • Sistema aprende patrones de promociones
  • Administrador puede configurar períodos de promoción conocidos
  • Se ajustan tolerancias automáticamente durante promociones
Situación: Vehículos que no encajan perfectamente en las 5 categorías estándar.Ejemplos:
  • Buses articulados (¿categoría 3 o 4?)
  • Camiones con equipos especiales
  • Vehículos de emergencia
Manejo:
  • Asignación manual de categoría por parte del administrador
  • Documentación de la decisión para casos similares
  • Creación de reglas específicas para tipos especiales
Situación: Un vehículo cambia temporalmente de categoría (ej: camión descargado vs. cargado).Detección: El mismo vehículo genera cargos con diferentes categorías en períodos cortos.Manejo:
  • Análisis de patrones temporales
  • Validación cruzada con datos de peso (si disponibles)
  • Configuración de categorías variables para vehículos específicos

4. Verificación de Estado de Tags

Objetivo

Confirmar que el tag utilizado estaba en estado “Válido” en el momento del cargo, detectando uso de tags inhabilitados.

Algoritmo de Verificación

  • Consulta de Estado Histórico
  • Detección de Patrones Sospechosos
  • Validación Cruzada
Proceso: Determinar el estado del tag en la fecha específica del cargo
def verificar_estado_tag(tag_number, fecha_cargo, org_id):
    # Buscar el estado del tag en la fecha del cargo
    estado_historico = db.query("""
        SELECT status, date, expires_at, car_id
        FROM tag_assignments 
        WHERE tag_number = %s 
        AND org_id = %s
        AND date <= %s
        ORDER BY date DESC, updated_at DESC
        LIMIT 1
    """, [tag_number, org_id, fecha_cargo])
    
    if not estado_historico:
        return {
            'status': 'TAG_NO_ENCONTRADO',
            'detalle': 'No existe asignación para este tag',
            'accion': 'Verificar número de tag'
        }
    
    # Verificar si el tag había expirado
    if estado_historico.expires_at and estado_historico.expires_at < fecha_cargo:
        return {
            'status': 'TAG_EXPIRADO',
            'detalle': f'Tag expiró el {estado_historico.expires_at}',
            'accion': 'Verificar renovación'
        }
    
    # Verificar estado en la fecha
    if estado_historico.status == 'Valido':
        return {
            'status': 'VALIDO',
            'detalle': 'Tag estaba activo',
            'accion': 'Ninguna'
        }
    else:
        return {
            'status': 'INHABILITADO',
            'detalle': f'Tag inhabilitado desde {estado_historico.date}',
            'accion': 'Investigar uso no autorizado'
        }

Estados de Validación de Tags

Válido

Descripción: Tag estaba activo en la fecha del cargoCriterios:
  • Estado = “Valido” en fecha del cargo
  • No había expirado
  • Asignación vigente
Indicador: 🟢 VerdeAcción: Ninguna

Inhabilitado

Descripción: Tag estaba desactivado cuando se generó el cargoCriterios:
  • Estado = “Inhabilitado” antes de la fecha del cargo
  • Uso posterior a inhabilitación confirmada
Indicador: 🔴 RojoAcción: Investigar fraude potencial

No Encontrado

Descripción: No existe registro del tag en el sistemaCriterios:
  • Tag nunca fue asignado
  • Número de tag incorrecto
  • Datos de importación incompletos
Indicador: ⚪ GrisAcción: Verificar datos de importación

Consolidación de Resultados

Algoritmo de Clasificación Final

Una vez completadas las 4 validaciones, el sistema consolida los resultados:
def clasificar_cargo_final(cargo, resultados_validaciones):
    """
    Determina el estado final del cargo basado en todas las validaciones
    """
    gps = resultados_validaciones['gps']
    duplicado = resultados_validaciones['duplicado']
    categoria = resultados_validaciones['categoria']
    tag = resultados_validaciones['tag']
    
    # Clasificación por prioridad de severidad
    if tag['status'] == 'INHABILITADO':
        return {
            'estado_final': 'FRAUDULENTO',
            'prioridad': 'CRITICA',
            'razon_principal': 'Tag inhabilitado',
            'accion_recomendada': 'Rechazar cargo e investigar'
        }
    
    if duplicado['is_duplicate']:
        return {
            'estado_final': 'DUPLICADO',
            'prioridad': 'ALTA',
            'razon_principal': 'Cargo duplicado detectado',
            'accion_recomendada': 'Eliminar duplicado'
        }
    
    if gps['status'] == 'UBICACION_INVALIDA':
        return {
            'estado_final': 'GPS_INVALIDO',
            'prioridad': 'ALTA',
            'razon_principal': 'Vehículo no estaba en la ubicación',
            'accion_recomendada': 'Rechazar cargo'
        }
    
    if categoria['status'] == 'COBRO_MAYOR':
        return {
            'estado_final': 'SOBRECARGO',
            'prioridad': 'MEDIA',
            'razon_principal': f'Cobro excesivo por ${categoria["diferencia"]}',
            'accion_recomendada': 'Solicitar reembolso'
        }
    
    if gps['status'] == 'SIN_TELEMETRIA':
        return {
            'estado_final': 'SIN_VALIDAR_GPS',
            'prioridad': 'BAJA',
            'razon_principal': 'No hay datos GPS para validar',
            'accion_recomendada': 'Aceptar condicionalmente'
        }
    
    # Si todas las validaciones pasan
    return {
        'estado_final': 'VALIDO',
        'prioridad': 'NINGUNA',
        'razon_principal': 'Todas las validaciones exitosas',
        'accion_recomendada': 'Aprobar cargo'
    }

Métricas y Estadísticas

Análisis GPS detallado con mapas El sistema genera métricas automáticas para monitoreo:
  • Métricas de Validación
  • Impacto Financiero
  • Calidad de Datos
Por tipo de validación:
  • GPS: % de cargos con ubicación válida
  • Duplicados: Número de duplicados detectados por período
  • Categoría: % de cargos con monto correcto
  • Tags: % de tags válidos vs. inhabilitados
Tendencias temporales:
  • Evolución de tasas de fraude por mes
  • Patrones estacionales de errores
  • Efectividad de las validaciones implementadas

Configuración y Personalización

Parámetros Configurables

time_window_minutes
integer
default:"1"
Ventana de tiempo inicial para buscar datos GPS (±minutos)
max_time_window_minutes
integer
default:"5"
Ventana máxima de tiempo si no se encuentran datos inicialmente
distance_threshold_meters
integer
default:"500"
Distancia máxima permitida entre vehículo y estación
urban_distance_threshold
integer
default:"200"
Distancia reducida para zonas urbanas densas
rural_distance_threshold
integer
default:"1000"
Distancia aumentada para zonas rurales
duplicate_time_threshold_minutes
integer
default:"10"
Tiempo máximo entre cargos para considerarlos duplicados
amount_tolerance_percentage
decimal
default:"5.0"
Tolerancia porcentual para diferencias en montos
amount_tolerance_absolute
integer
default:"500"
Tolerancia absoluta en pesos para diferencias en montos
duplicate_score_threshold
integer
default:"70"
Score mínimo para considerar un cargo como duplicado
category_tolerance_percentage
decimal
default:"5.0"
Tolerancia porcentual para variaciones de tarifa
category_tolerance_absolute
integer
default:"500"
Tolerancia absoluta para variaciones de tarifa
promotion_detection_enabled
boolean
default:"true"
Habilitar detección automática de promociones
tag_expiration_grace_days
integer
default:"7"
Días de gracia después de expiración antes de marcar como inválido
frequent_status_change_threshold
integer
default:"3"
Número máximo de cambios de estado en 90 días

Personalización por Organización

Cada organización puede tener configuraciones específicas:
  • Perfiles de Validación
  • Reglas Específicas
Perfil Estricto:
  • Tolerancias mínimas
  • Validación GPS obligatoria
  • Revisión manual de todos los casos sospechosos
Perfil Balanceado (por defecto):
  • Tolerancias moderadas
  • Automatización inteligente
  • Revisión manual solo de casos críticos
Perfil Permisivo:
  • Tolerancias amplias
  • Máxima automatización
  • Mínima intervención manual

Próximos Pasos