Skip to content

Visión General del Motor de Automatizaciones

El Motor de Automatizaciones es el núcleo de Axol Systems encargado de ejecutar reglas de negocio de manera reactiva ante cambios en los datos. Esto permite automatizar flujos operativos complejos (como movimientos y traspasos de stock, sincronizaciones multi-tabla, auditorías y alertas) directamente en la capa de datos sin necesidad de modificar el código fuente de la aplicación cliente.


Arquitectura y Despachador Universal en PostgreSQL

Section titled “Arquitectura y Despachador Universal en PostgreSQL”

Las automatizaciones en Axol Systems operan bajo un despachador universal implementado a nivel de base de datos mediante la función trigger main_automation_trigger().

Esta función intercepta las mutaciones de datos (INSERT, UPDATE, DELETE) o invocaciones manuales y determina dinámicamente qué motor de ejecución debe procesar la regla mediante el parámetro engine_version:

  • engine_version: 1 (Motor Especializado / Clásico): Despacha la ejecución hacia flujos imperativos predefinidos (kardex, inventory_sync, inventory_transfer, sequence_transfer, edit_table, etc.). Diseñado para operaciones operativas específicas de almacén y edición directa.
  • engine_version: 2 (Motor Declarativo ECA): Despacha la ejecución hacia el motor extensible Evento-Condición-Acción (ECA), evaluando árboles lógicos de condiciones (incluyendo cambios delta) y ejecutando un pipeline secuencial de acciones atómicas.
flowchart TD
    E["Mutación en Base de Datos<br>(INSERT / UPDATE / DELETE / Manual)"] --> T["Despachador Universal<br>main_automation_trigger()"]
    
    T -->|"engine_version: 1"| M1["Motor v1: Tipos Especializados<br>(kardex, inventory_sync, transfer, etc.)"]
    T -->|"engine_version: 2"| M2["Motor v2: Declarativo ECA"]
    
    M2 --> TR["1. Trigger<br>(on_record_create, update, delete, manual)"]
    TR --> CD{"2. Conditions<br>(all / any, operadores relacionales y delta)"}
    
    CD -->|"Cumplidas"| AC["3. Actions Pipeline<br>(insert, update, adjust, delete, set, for_each)"]
    CD -->|"No cumplidas"| STOP["Fin Silencioso<br>(sin error ni modificaciones)"]
    
    AC --> TX{"Garantía Atómica<br>(atomic: true)"}
    TX -->|"Éxito"| COM["COMMIT<br>Transacción confirmada"]
    TX -->|"Fallo o Inconsistencia"| RB["ROLLBACK<br>Reversión automática de todo el lote"]

Motor de Automatizaciones v2 (ECA: Event-Condition-Action)

Section titled “Motor de Automatizaciones v2 (ECA: Event-Condition-Action)”

El Motor v2 implementa un paradigma declarativo modular que otorga flexibilidad total para componer procesos de negocio complejos.

El modelo se estructura en tres componentes clave:

flowchart LR
    A["Trigger (Disparador)<br>¿Cuándo se ejecuta?"] --> B["Conditions (Condiciones)<br>¿Debe ejecutarse?"]
    B --> C["Actions (Acciones)<br>¿Qué debe realizarse?"]

Definen el evento origen y la tabla que inician la evaluación de la regla:

  • on_record_create: Se activa inmediatamente tras la inserción de un nuevo registro.
  • on_record_update: Se activa ante la modificación de uno o más campos de una fila existente.
  • on_record_delete: Se activa justo antes o durante la eliminación de un registro.
  • on_manual_execution: Se dispara a petición explícita del usuario mediante botones de automatización en la interfaz.

2. Evaluación de Condiciones (Conditions) y Detección Delta

Section titled “2. Evaluación de Condiciones (Conditions) y Detección Delta”

Antes de alterar los datos, el motor evalúa un árbol condicional. Si la premisa no se cumple, la automatización finaliza limpiamente sin registrar errores:

  • Estructuras lógicas anidadas: Admite bloques agrupadores all (todas deben cumplirse, equivalente a AND) y any (al menos una debe cumplirse, equivalente a OR).
  • Operadores relacionales tipados: Comparaciones directas sobre los valores del registro (eq, neq, gt, gte, lt, lte, in, is_null).
  • Operadores Delta (detección de cambios): Esenciales para eventos de actualización (on_record_update):
    • changed: Verifica si una columna específica cambió de valor respecto a su estado anterior en la transacción.
    • changed_to: Verifica si la columna cambió y su nuevo valor coincide con el valor esperado (por ejemplo, transicionar a "APROBADO").
    • changed_from: Verifica si la columna cambió proviniendo de un estado específico (por ejemplo, transicionar desde "PENDIENTE").

3. Pipeline de Acciones Atómicas (Actions)

Section titled “3. Pipeline de Acciones Atómicas (Actions)”

Representa una lista secuencial de operaciones atómicas ejecutadas en orden estricto sobre las tablas destino:

  • insert_record: Inserta filas en tablas destino resolviendo campos polimórficamente: por columna origen (field), valor constante (literal) o metadatos de sesión (meta: {user.name}, {user.id}, {now}).
  • update_record: Actualiza registros destino que coincidan con criterios de búsqueda relacional (match).
  • adjust_field: Incrementa o decrementa columnas numéricas de forma atómica aplicando bloqueo concurrente de fila (FOR UPDATE), control de saldo no negativo (allow_negative: false) y auto-creación del registro destino si aún no existe (auto_create_if_missing: true con default_values).
  • delete_record: Elimina filas coincidentes en tablas destino.
  • set_field: Modifica en caliente columnas del propio registro origen dentro del ciclo de vida del evento.
  • for_each_child: Itera de manera secuencial sobre colecciones de registros dependientes o listas de objetos (objList).

Garantías Transaccionales y Rollback Automático

Section titled “Garantías Transaccionales y Rollback Automático”

El Motor v2 ejecuta sus operaciones de forma nativa dentro de la misma transacción física de PostgreSQL que originó el cambio:

  • Atomicidad Estricta (atomic: true): Si cualquiera de las acciones del pipeline falla (por ejemplo, saldo insuficiente al decrementar con allow_negative: false, violación de llaves foráneas o un registro requerido no encontrado), PostgreSQL ejecuta automáticamente un ROLLBACK completo. Ninguna fila intermedia ni el registro disparador quedarán persistidos, protegiendo la base de datos contra inconsistencias o estados parciales.
  • Control de Concurrencia y Bloqueo: En operaciones como adjust_field, el motor utiliza bloqueos a nivel de fila (SELECT ... FOR UPDATE) para evitar condiciones de carrera (race conditions) en entornos con múltiples operarios capturando simultáneamente.
  • Tiempo Límite Transaccional (timeout_ms): Permite configurar un límite máximo de ejecución (por defecto 5000 ms) para abortar la transacción si se detecta un bloqueo prolongado en la base de datos.

CaracterísticaMotor v1 (Especializado)Motor v2 (Declarativo ECA)
ParadigmaFlujos rígidos por tipo específico (type).Evento-Condición-Acción desacoplado y modular.
DespachadorInvocación individual por tipo.Despachador unificado main_automation_trigger().
Pipeline de AccionesUna única operación principal por regla.Múltiples acciones atómicas encadenadas (insert, adjust, update, etc.).
Detección de CambiosSin soporte nativo de estados previos.Operadores delta nativos (changed, changed_to, changed_from).
Resolución de DatosMapeo directo columna a columna.Polimórfico: campo origen (field), literal (literal) y metadatos (meta).
Garantía TransaccionalParcial / dependiente de la función.Atomicidad total en PostgreSQL con rollback ante cualquier error.
Diseñador VisualEdición directa de JSON.Asistente visual paso a paso en Ajustes (AutomationsConfigView) y editor JSON con validación en vivo.

Configuración y Registro de Automatizaciones

Section titled “Configuración y Registro de Automatizaciones”

Cada automatización se registra en la tabla del sistema definiendo los siguientes campos principales:

CampoTipo de DatoDescripción
Nombre (name)TextoNombre descriptivo de la automatización.
Descripción (description)TextoExplicación funcional de la regla para el equipo de administración.
Versión del Motor (engine_version)EnteroIdentifica el motor ejecutor: 1 para tipos clásicos/especializados o 2 para el motor declarativo ECA.
Tipo (type)TextoIdentificador del tipo en el motor v1 (ej. kardex, inventory_sync) o eca_v2 en el motor v2.
Tabla Origen (source_table)TextoNombre físico de la tabla que monitorea el disparador.
Evento Disparador (trigger_event)TextoMutación que activa la regla: INSERT, UPDATE o DELETE.
Reglas (rules)JSONDiccionario JSON con la configuración detallada (estructura clásica o esquema declarativo v2).
Activo (is_active)BooleanoPermite habilitar o inhabilitar la regla de forma inmediata.

Tipos de Automatizaciones Especializadas (Motor v1)

Section titled “Tipos de Automatizaciones Especializadas (Motor v1)”

Para flujos estándar y operaciones de captura masiva, el sistema mantiene soporte nativo para los siguientes tipos del motor v1:


Comparación entre Automatizaciones de Inventario (Motor v1)

Section titled “Comparación entre Automatizaciones de Inventario (Motor v1)”

El sistema cuenta con cuatro tipos nativos para gestionar stock. Es importante seleccionar el adecuado según el flujo físico de tu operación:

Característicakardexinventory_syncinventory_transferinventory_movement
CapturaLote multi-producto (hoja de cálculo).Registro individual o lote simple.Registro individual bidireccional.Registro individual unidireccional.
DirecciónMapeada por concepto (+/-).Entrada o salida en columna de fila.Bidireccional (origen y destino en la misma fila).Unidireccional (configurada fija in u out).
Saldo ResultanteSí (Snapshot inmutable) en cada fila.No (solo delta de cantidad).No (solo delta de cantidad).No (solo delta de cantidad).
Asistente de StockEn vivo con filtro en salidas (stock_selector).No nativo en formulario.No nativo en formulario.Validación estándar.
Uso IdealAlmacenes de alta rotación, recepciones de compras y despachos donde se requiere historial estricto con balance por partida.Sincronizaciones masivas simples o integraciones externas con tipo explícito.Traspasos entre almacenes donde un único registro representa todo el traslado.Auditoría independiente de entradas o salidas (mermas, recepciones específicas).

  • Usa kardex si necesitas que los operarios capturen múltiples productos en una misma sesión rápida con teclado, validando el stock disponible en tiempo real y grabando el saldo final que quedó tras la operación en cada fila del historial.
  • Usa inventory_sync si tienes un catálogo de movimientos simple donde cada registro dice "entrada" o "salida" en la misma columna y no te interesa registrar saldos resultantes en esa tabla.
  • Usa inventory_transfer si tu operación física requiere que al registrar un traspaso se descuente inmediatamente del origen y se sume al destino, asegurando que el saldo neto general no cambie y se eviten discrepancias.
  • Usa inventory_movement si deseas controlar cada dirección por separado (por ejemplo, reglas distintas para mermas vs. recepciones), o cuando solo te interese registrar un lado de la operación.