Motor ECA v2 y Diseñador Visual de Automatizaciones
Axol Systems incorpora el Motor de Automatizaciones v2, un entorno declarativo y extensible basado en el paradigma Evento-Condición-Acción (ECA).
Este motor opera de forma nativa a nivel transaccional en PostgreSQL, garantizando atomicidad absoluta (ROLLBACK automático si alguna acción o regla de integridad falla) y permitiendo componer de forma modular disparadores, filtros lógicos y pipelines de acciones atómicas.
Para simplificar su adopción sin necesidad de escribir JSON manualmente, se incluye el Diseñador Visual de Automatizaciones en el módulo de Ajustes (AutomationsConfigView).
Acceso al Diseñador Visual (AutomationsConfigView)
Section titled “Acceso al Diseñador Visual (AutomationsConfigView)”Para acceder al diseñador:
- Ve a la barra de navegación principal y pulsa en Configuración (icono de engranaje).
- En el menú lateral de ajustes, selecciona Automatizaciones (
AutomationsConfigView).
flowchart LR
A["Ajustes > Automatizaciones"] --> B["Catálogo de Reglas"]
B --> C["Tarjeta de Disparador (Trigger)"]
C --> D["Tarjeta de Condiciones (Conditions)"]
D --> E["Pipeline de Acciones (Actions)"]
E --> F["Guardar y Ejecución Transaccional"]
Características de la Pantalla de Gestión:
Section titled “Características de la Pantalla de Gestión:”- Catálogo Centralizado: Lista todas las reglas registradas con su estado (activa/inactiva), entidad o tabla de origen y descripción técnica.
- Filtros por Tabla: Permite visualizar rápidamente las automatizaciones asociadas a una tabla específica del sistema.
- Alternancia Visual / Código JSON: Puedes alternar en un solo clic entre el diseñador visual asistido y el editor de código directo (
JsonCodeEditor).
Flujo de Construcción Visual en Tres Pasos
Section titled “Flujo de Construcción Visual en Tres Pasos”El diseñador organiza la configuración de cada regla en tres tarjetas secuenciales:
Paso 1: Configurar el Disparador (Trigger Card)
Section titled “Paso 1: Configurar el Disparador (Trigger Card)”El disparador define el evento del sistema que pondrá en marcha la automatización.
- Tipo de Disparador (
type):on_record_create: Se activa inmediatamente después de insertar un nuevo registro en la tabla.on_record_update: Se activa cuando se actualizan campos en un registro existente.on_record_delete: Se activa al eliminar un registro.on_manual_execution: Se activa a demanda mediante un botón de acción en la interfaz (automation_buttons_config).
- Tabla de Origen (
source_table): La tabla de PostgreSQL que emitirá el evento (por ejemplo,table_traspasosotable_facturas). - Descripción: Texto explicativo que documenta el propósito de la regla (ej. “Actualizar stock y kardex al confirmar traspaso”).
Paso 2: Agregar Condiciones Lógicas (Conditions Card)
Section titled “Paso 2: Agregar Condiciones Lógicas (Conditions Card)”Las condiciones actúan como compuertas de seguridad. Si el registro no cumple con todas las condiciones especificadas, la automatización se detiene limpiamente de inmediato sin generar errores ni cambios colaterales.
- Agrupación Lógica: Soporte para bloques conjuntivos (
all/AND) y disyuntivos (any/OR). - Operadores Relacionales: Comparan el valor actual del campo:
eq(igual),neq(diferente),gt(mayor que),gte(mayor o igual que).lt(menor que),lte(menor o igual que),in(dentro de una lista),is_null(es nulo/vacío).
- Operadores de Detección Delta (Mutación de Estado): Ideales para disparadores
on_record_update:changed: Se cumple si el valor del campo cambió respecto a su estado anterior.changed_to: Se cumple si el campo fue modificado y su nuevo valor coincide con el valor esperado (ej.{ "field": "t20c3", "op": "changed_to", "value": "APROBADO" }).changed_from: Se cumple si el campo cambió y su valor anterior coincidía con el indicado.
Paso 3: Configurar el Pipeline de Acciones (Actions Pipeline)
Section titled “Paso 3: Configurar el Pipeline de Acciones (Actions Pipeline)”El pipeline reúne las operaciones atómicas que se ejecutarán en secuencia estricta. Cada tipo de acción cuenta con un formulario asistido especializado:
1. Modificar Valor Numérico (adjust_field)
Section titled “1. Modificar Valor Numérico (adjust_field)”Especializado en operaciones de existencias, saldos y contadores:
- Operación:
increment(sumar) odecrement(restar). - Monto (
amount): Puede provenir de un campo del registro origen (field) o de una constante (literal). - Coincidencia (
match): Mapeo de columnas para localizar la fila exacta en la tabla destino (ej. coincidirid_productoyid_almacen). - Protección contra Negativos (
allow_negative: false): Utiliza bloqueos de fila (SELECT ... FOR UPDATE) en PostgreSQL. Si la resta resulta en un saldo menor a cero, cancela la transacción evitando inconsistencias. - Auto-creación de Registro Faltante (
auto_create_if_missing: true): Si la fila destino no existe aún (por ejemplo, el producto no tenía registro de inventario en ese almacén), la inserta automáticamente con los valores predeterminados dedefault_values.
2. Insertar Registro Destino (insert_record)
Section titled “2. Insertar Registro Destino (insert_record)”Genera filas en tablas complementarias (como partidas de kardex o registros de auditoría):
- Tabla Destino: Tabla donde se insertará la nueva fila.
- Resolución Polimórfica de Valores:
field: Toma el valor de una columna del registro origen.literal: Asigna un valor fijo (ej."SALIDA_TRASPASO").meta: Inyecta metadatos contextuales (user.name,user.id,now,today).
3. Actualizar Registro Destino (update_record)
Section titled “3. Actualizar Registro Destino (update_record)”Modifica columnas específicas en una tabla destino bajo una condición de búsqueda (match).
4. Asignar Campo Local (set_field)
Section titled “4. Asignar Campo Local (set_field)”Modifica el valor de una columna en el propio registro origen que disparó el evento (por ejemplo, estampar un folio consecutivo o cambiar su estatus a "PROCESADO").
5. Eliminar Registro (delete_record)
Section titled “5. Eliminar Registro (delete_record)”Elimina una fila en la tabla destino coincidente con las claves provistas.
6. Iterar sobre Sub-tablas (for_each_child)
Section titled “6. Iterar sobre Sub-tablas (for_each_child)”Itera sobre colecciones dependientes o listas de objetos (objList), ejecutando un sub-pipeline de acciones para cada partida hija (por ejemplo, actualizar el stock de cada renglón de una orden de compra).
Editor de Código JSON y Pantalla Completa
Section titled “Editor de Código JSON y Pantalla Completa”En cualquier momento puedes alternar entre el diseñador visual y el editor de código directo (JsonCodeEditor):
- Sincronización Bidireccional: Los cambios realizados visualmente se reflejan al instante en la estructura JSON, y viceversa.
- Indicador de Sintaxis: Monitorea la validez estructural en tiempo real con alertas de línea y diagnóstico de errores.
- Botón de Auto-formateo: Ordena y embellece el árbol JSON.
- Expansión a Pantalla Completa: Permite maximizar el editor sobre toda la pantalla para trabajar con comodidad en reglas complejas o con pipelines de múltiples acciones.
Ejemplos Completos de Reglas Prácticas
Section titled “Ejemplos Completos de Reglas Prácticas”Ejemplo 1: Traspaso de Inventario entre Almacenes con Control de Existencias
Section titled “Ejemplo 1: Traspaso de Inventario entre Almacenes con Control de Existencias”Esta regla se dispara al dar de alta un registro de traspaso (table20) en estatus "APROBADO". Realiza una salida de kardex (table15), descuenta las existencias del almacén origen (bloqueando saldos negativos) e incrementa las existencias en el almacén destino (con auto-creación):
{ "version": 2, "trigger": { "type": "on_record_create", "source_table": "table20", "description": "Al registrar un traspaso autorizado" }, "conditions": [ { "field": "t20c3", "op": "eq", "value": "APROBADO" }, { "field": "t20c4", "op": "gt", "value": 0 } ], "actions": [ { "id": "kardex_salida", "type": "insert_record", "target_table": "table15", "fields": { "t15c1": { "type": "field", "source": "t20c1" }, "t15c2": { "type": "field", "source": "t20c2" }, "t15c3": { "type": "literal", "value": "SALIDA_TRASPASO" }, "t15c4": { "type": "field", "source": "t20c4" }, "t15c5": { "type": "meta", "source": "user.name" }, "t15c6": { "type": "meta", "source": "now" } } }, { "id": "stock_origen", "type": "adjust_field", "target_table": "table10", "match": [ { "target": "t10c1", "source": "t20c1" }, { "target": "t10c2", "source": "t20c2" } ], "operation": "decrement", "field": "t10c3", "amount": { "type": "field", "source": "t20c4" }, "allow_negative": false }, { "id": "stock_destino", "type": "adjust_field", "target_table": "table10", "match": [ { "target": "t10c1", "source": "t20c1" }, { "target": "t10c2", "source": "t20c5" } ], "operation": "increment", "field": "t10c3", "amount": { "type": "field", "source": "t20c4" }, "auto_create_if_missing": true, "default_values": { "t10c1": { "type": "field", "source": "t20c1" }, "t10c2": { "type": "field", "source": "t20c5" }, "t10c3": { "type": "literal", "value": 0 } } } ]}Ejemplo 2: Transición de Estado de Factura a Pagada
Section titled “Ejemplo 2: Transición de Estado de Factura a Pagada”Esta regla reacciona a la edición de una factura (table_facturas) únicamente cuando el campo de estatus (t5c4) cambia al valor "PAGADA", actualizando la fecha de liquidación en el registro y cancelando el saldo pendiente en cuentas por cobrar:
{ "version": 2, "trigger": { "type": "on_record_update", "source_table": "table_facturas", "description": "Al liquidar una factura" }, "conditions": [ { "field": "t5c4", "op": "changed_to", "value": "PAGADA" } ], "actions": [ { "id": "marcar_fecha_pago", "type": "set_field", "field": "t5c8", "value": { "type": "meta", "source": "now" } }, { "id": "saldar_cxc", "type": "update_record", "target_table": "table_cxc", "match": [ { "target": "cxc_folio", "source": "t5c1" } ], "fields": { "cxc_saldo": { "type": "literal", "value": 0 }, "cxc_estado": { "type": "literal", "value": "LIQUIDADO" } } } ]}Consideraciones de Rendimiento y Seguridad
Section titled “Consideraciones de Rendimiento y Seguridad”[!IMPORTANT] Transaccionalidad Atómica: Por defecto, todas las reglas del Motor v2 ejecutan sus acciones dentro de una transacción única en PostgreSQL. Si una acción de tipo
adjust_fielddetecta saldo insuficiente conallow_negative: false, el motor revierte todas las acciones previas de la regla y el registro original no se modifica.
[!TIP] Condiciones Delta: Utiliza siempre
changed_toen lugar deeqpara disparadores de actualización (on_record_update). Esto evita que la regla se dispare innecesariamente cuando se editen otros campos no relacionados del mismo registro.