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.
Componentes del Modelo ECA
Section titled “Componentes del Modelo ECA”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?"]
1. Disparadores (Triggers)
Section titled “1. Disparadores (Triggers)”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 aAND) yany(al menos una debe cumplirse, equivalente aOR). - 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: truecondefault_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 conallow_negative: false, violación de llaves foráneas o un registro requerido no encontrado), PostgreSQL ejecuta automáticamente unROLLBACKcompleto. 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 defecto5000ms) para abortar la transacción si se detecta un bloqueo prolongado en la base de datos.
Comparativa: Motor v1 vs. Motor v2
Section titled “Comparativa: Motor v1 vs. Motor v2”| Característica | Motor v1 (Especializado) | Motor v2 (Declarativo ECA) |
|---|---|---|
| Paradigma | Flujos rígidos por tipo específico (type). | Evento-Condición-Acción desacoplado y modular. |
| Despachador | Invocación individual por tipo. | Despachador unificado main_automation_trigger(). |
| Pipeline de Acciones | Una única operación principal por regla. | Múltiples acciones atómicas encadenadas (insert, adjust, update, etc.). |
| Detección de Cambios | Sin soporte nativo de estados previos. | Operadores delta nativos (changed, changed_to, changed_from). |
| Resolución de Datos | Mapeo directo columna a columna. | Polimórfico: campo origen (field), literal (literal) y metadatos (meta). |
| Garantía Transaccional | Parcial / dependiente de la función. | Atomicidad total en PostgreSQL con rollback ante cualquier error. |
| Diseñador Visual | Edició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:
| Campo | Tipo de Dato | Descripción |
|---|---|---|
Nombre (name) | Texto | Nombre descriptivo de la automatización. |
Descripción (description) | Texto | Explicación funcional de la regla para el equipo de administración. |
Versión del Motor (engine_version) | Entero | Identifica el motor ejecutor: 1 para tipos clásicos/especializados o 2 para el motor declarativo ECA. |
Tipo (type) | Texto | Identificador del tipo en el motor v1 (ej. kardex, inventory_sync) o eca_v2 en el motor v2. |
Tabla Origen (source_table) | Texto | Nombre físico de la tabla que monitorea el disparador. |
Evento Disparador (trigger_event) | Texto | Mutación que activa la regla: INSERT, UPDATE o DELETE. |
Reglas (rules) | JSON | Diccionario JSON con la configuración detallada (estructura clásica o esquema declarativo v2). |
Activo (is_active) | Booleano | Permite 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:
- Captura Kardex (kardex): Captura masiva de movimientos en lote con cálculo de saldo resultante (snapshot) inmutable por partida, asistente de stock en vivo, atajos de teclado y consolidación automática.
- Sincronización de Inventario (inventory_sync): Permite sumar o restar stock en una tabla destino a partir de una sola fila de origen que define su dirección (+/-).
- Transferencia de Inventario (inventory_transfer): Mueve cantidades entre un origen y un destino de forma simultánea (movimiento bidireccional).
- Transferencia en Secuencia (sequence_transfer): Traspasa piezas o mercancías entre nodos y operaciones consecutivas en un flujo lineal u ordenado.
- Movimiento de Inventario (inventory_movement): Registra movimientos de stock unidireccionales (solo entradas o solo salidas) con soporte avanzado para ubicaciones e inserciones relacionales automáticas (
object_list_sync). - Edición de Tabla Externa (edit_table): Edita o elimina automáticamente un registro en otra tabla al guardar el registro actual.
- Solicitud de Movimiento (request-movement): Crea flujos de aprobación entre nodos para transferencias o entradas de stock antes de que impacten físicamente el inventario.
- Edición Pasiva Condicional (passive-conditional-edit): Calcula y edita de forma condicional campos dentro de la misma fila antes de guardarse, resolviendo sumatorias, fórmulas matemáticas y consultas complejas en tiempo real.
- Botones de Automatización: Botones interactivos que se añaden a las barras de herramientas de las vistas para desencadenar flujos masivos (como
relation_batch_createo apertura de formularios de creación).
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ística | kardex | inventory_sync | inventory_transfer | inventory_movement |
|---|---|---|---|---|
| Captura | Lote multi-producto (hoja de cálculo). | Registro individual o lote simple. | Registro individual bidireccional. | Registro individual unidireccional. |
| Dirección | Mapeada por concepto (+/-). | Entrada o salida en columna de fila. | Bidireccional (origen y destino en la misma fila). | Unidireccional (configurada fija in u out). |
| Saldo Resultante | Sí (Snapshot inmutable) en cada fila. | No (solo delta de cantidad). | No (solo delta de cantidad). | No (solo delta de cantidad). |
| Asistente de Stock | En vivo con filtro en salidas (stock_selector). | No nativo en formulario. | No nativo en formulario. | Validación estándar. |
| Uso Ideal | Almacenes 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). |
¿Cuándo usar cada tipo de inventario?
Section titled “¿Cuándo usar cada tipo de inventario?”- Usa
kardexsi 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_syncsi 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_transfersi 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_movementsi 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.