Capítulo 6. Fórmulas en Lenguaje JavaScript

Como se mencionó anteriormente, las fórmulas de tipo JavaScript tienen una serie de bondades y restricciones, además de ciertas diferencias conceptuales con en lenguaje STORM en términos del manejo para cada tipo de fórmula.
Fundamentalmente, para el manejo básico de cadenas, números, arreglos, etc.; se pueden utilizar las funciones que son permitidas por JavaScript, así como sentencias condicionales, bucles, sentencias switch, manejo de expresiones regulares, entre otras. Adicionalmente, se activó el objeto CurrentContext con una serie de propiedades y métodos propios que permiten acceder y trabajar los datos reportados de diferentes maneras en tiempo de ejecución.
El ámbito de las variables es algo que también debe tenerse en cuenta. Para STORM, cuando se declara una variable con la palabra reservada var, se está haciendo referencia a una variable que solo será utilizada en el contexto local de ejecución de dicha fórmula y no a una celda del formulario.
Es importante resaltar que el manejo de cada tipo de fórmula en JavaScript se transforma de la siguiente manera:
  • Asignaciones: Es conceptual. La fórmula puede hacer cualquier operación en este punto. Ya no es requerido usar la variable COMODIN, ejemplo al calcular totales. A diferencia de las fórmulas tipo STORM, la fórmula puede asignar varias celdas en su ejecución, disminuyendo el número de formulas para los formularios que tienen muchas columnas calculadas.
  • Validaciones: Es conceptual. La fórmula puede hacer cualquier operación en este punto. A diferencia de las fórmulas tipo STORM, la fórmula puede validar varias situaciones reportando un error por cada situación encontrada hasta llegar al final de la fórmula. Para esto se usa la función INCORRECTO (MENSAJE DE ERROR).
  • Alertas: Las asignaciones o validaciones a celdas ya no aplican en este punto, pues al llegar aquí, ya fue procesado OK el archivo.
Teniendo en cuenta lo anterior, a continuación se presentan ejemplos de formulación en JavaScript para cada tipo de fórmula.

6.1. Asignaciones

Una asignación en lenguaje JavaScript puede realizarse de manera directa utilizando como insumo lo que está siendo diligenciado en el formulario. Uno de los ejemplos más sencillos es asignar un valor fijo a una celda de un formulario, cuya fórmula sería:
Primer caso de asignación en JavaScript

Figura 6.1. Primer caso de asignación en JavaScript


Se recomienda que las asignaciones se realicen a celdas no editables del formulario, para evitar que el usuario que está diligenciando modifique dicha información. Otro caso que puede presentarse es que el cliente quiera tener dentro de la información que reporten sus usuarios, el código o el NIT de cada entidad; por lo que esa fórmula podría definirse así:

Segundo caso de asignación en JavaScript

Figura 6.2. Segundo caso de asignación en JavaScript


Para el caso anterior, la propiedad nit del objeto CurrentContext asigna de manera dinámica a la celda del formulario el código o NIT del respectivo usuario que se encuentre diligenciando el formulario en STORM User.
Se pueden presentar casos de asignación más complejos, como por ejemplo, para la premisa:
CONCATENAR NOMBRES Y APELLIDOS
El cliente requería asignar el resultado de concatenar los nombres y los apellidos a una celda no editable del formulario, teniendo en cuenta que los campos PRIMER NOMBRE y PRIMER APELLIDO eran de obligatorio diligenciamiento, y los campos SEGUNDO NOMBRE y SEGUNDO APELLIDO no. La fórmula definida para este caso fue:
Tercer caso de asignación en JavaScript

Figura 6.3. Tercer caso de asignación en JavaScript


En esta situación, se realiza una concatenación de cadenas (nombres y apellidos) que se ven condicionados por los diligenciamientos anteriormente mencionados. Adicionalmente, a modo de comentario, se pueden observar una serie de impresiones que le permiten al diseñador de las fórmulas verificar el comportamiento que tiene la fórmula al ejecutarse. 

6.2. Validaciones

Cuando una premisa o una condición establecida por el cliente presente un grado de complejidad que no permita diseñar la fórmula en lenguaje STORM, o se pueda optimizar para presentar diferentes tipos de mensajes teniendo en cuenta la información que está siendo diligenciada en el formulario, se podría utilizar JavaScript para resolverse.
En el siguiente caso, el cliente solicita que es necesario validar y parametrizar mensajes de error para los números de documento que se ingresen en un campo del formulario, dependiendo de un tipo documental que se seleccione de una lista. Si bien este escenario puede controlarse por medio de varias fórmulas en lenguaje STORM (una por cada parámetro de la lista 'Tipo de documento'), a continuación se muestra un ejemplo de cómo podría diseñarse utilizando JavaScript:
Primer caso de validación en lenguaje JavaScript

Figura 6.4. Primer caso de validación en lenguaje JavaScript


En esta fórmula se pueden observar algunas bondades que permite la formulación en JavaScript:
  • La función CurrentContext.println() permite visualizar impresiones de mensaje y/o variables en la consola de STORM User o STORM Server.
  • Para el caso anterior se generan dos (2) impresiones, a la variable local doc se le asigna NUM_DOC, la cual se encuentra mapeada a la celda del formulario en el que se diligencia y mostraría el valor de la celda diligenciada; mientras que la otra impresión presenta el número de caracteres que tiene la variable doc.
  • Se inicializa una variable reg que contiene una expresión regular. Dada la naturaleza de algunos tipos documentales (algunos eran compuestos de números y letras como el Pasaporte y el Carné Diplomático), fue necesario validar que el número de documento para esos tipos documentales cumplieran dicha condición utilizando el método test().
  • Se define una condición para cada tipo documental con su respectivo mensaje de error, dependiendo de lo que diligencie el usuario.
Para el caso anterior, el cliente no solicitó validar que el número de documento para tipos documentales que se componen únicamente de números, tuviera dicha estructura; sin embargo, es posible hacerlo de la siguiente manera haciendo uso de dos (2) expresiones regulares:
Segundo caso de validación en lenguaje JavaScript

Figura 6.5. Segundo caso de validación en lenguaje JavaScript


Para este caso se valida que si el número de documento ingresado corresponde a un tipo de documento diferente a Pasaporte (parámetro 5), evalúe su estructura contra una expresión regular reg que únicamente permite números; si es Pasaporte, lo evalúe contra una expresión regular patt que solo permite números y letras.
Así como es posible utilizar fórmulas en JavaScript para personalizar mensajes de error y para optimizar el número de fórmulas en lenguaje STORM, también es posible usarlas para realizar operaciones que validen la veracidad de lo que el usuario se encuentra diligenciando. Se presentó un caso de un cliente que solicitaba que para un tipo específico de actores de un contrato, se sumara un porcentaje y si este no resultaba 100, rechazara la información. La premisa dada por el cliente era:
SI UN CONTRATO DILIGENCIA SI EN ¿ESTE CONTRATO TIENE CONTRATISTAS INTEGRANTES?, EL PORCENTAJE DE PARTICIPACIÓN DE LOS CONTRATISTAS INTEGRANTES DE ESE CONTRATO DEBE SUMAR 100
Esta situación no es posible controlarla por medio de una única fórmula en lenguaje STORM, teniendo en cuenta que:
  • El registro de los contratos se hacía en un formulario diferente al registro de los actores de cada contrato.
  • Existe una condición dentro del contrato que ejecuta el cálculo del porcentaje.
  • Los actores de un contrato pueden tener un rol diferente a CONTRATISTAS INTEGRANTES, y un solo actor con este rol para un contrato no puede tener el cien porciento de la participación.
  • Si se selecciona SI en ¿ESTE CONTRATO TIENE CONTRATISTAS INTEGRANTES?, debe existir información de los actores de dicho contrato en el formulario respectivo (en el mismo envío).
  • Un usuario puede registrar n contratos, y para cada contrato puede registrar n actores con n roles, por lo que es necesario acumular y sumar agrupando por roles de actores en el contrato, según lo establecido en los puntos anteriores.
Teniendo en cuenta estas condiciones, se planteó la siguiente fórmula en JavaScript que satisface las condiciones del cliente:
Tercer caso de validación en lenguaje JavaScript

Figura 6.6. Tercer caso de validación en lenguaje JavaScript


NOTALa fórmula se define como Heredable para el formulario en el que se registran los contratos, con el fin de poder extraer con mayor facilidad los parámetros y condiciones principales que se necesitan (llave que identifica al contrato, SI en MÚLTIPLES CONTRATISTAS) de cada registro.
En este caso se inicia validando que para un contrato que diligencie SI en ¿ESTE CONTRATO TIENE CONTRATISTAS INTEGRANTES?, se ejecute la fórmula. Luego de eso se encierra la ejecución de las operaciones en dos prints que indican el inicio y el fin de la ejecución del script, lo que permite verificar en la consola de forma más fácil que está haciendo la fórmula.
Posterior, se utiliza el método getMatriz() para llamar la matriz de datos del formulario en el que se registran los actores del contrato y se inicializa la variable suma que guardará el acumulado de los porcentajes.
Se valida que la matriz contenga datos, de lo contrario se genera el mensaje de error de la línea 34; si contiene datos se inicializa una variable con las filas que contiene la matriz del formulario cargado y se extraen una serie de datos de cada fila: llave que identifica el contrato en el formulario de actores del contrato (CodEnt, AnnioSus y ConsInt), el rol asociado a ese registro, y el porcentaje.
Para extraer esta información se utiliza el método getCell(<fila>,<columna>), que recibe como argumentos la fila y la columna en la que se ubica el dato.
Luego se valida que la llave que identifica el contrato en ambos formularios coincida, y que el rol del actor del contrato corresponda a CONTRATISTA INTEGRANTE (Parámetro 8); si se cumplen todas estas condiciones se empieza a acumular el porcentaje en la variable suma. Una vez se recorre toda la matriz de datos, se verifica que el valor acumulado de la variable suma corresponda al cien porciento, de lo contrario se genera error. 

6.3. Alarmas

  • Eventos
Los eventos en lenguaje JavaScript funcionan de la misma forma que en lenguaje STORM (bloqueo/desbloqueo de celdas y cargue de listas), sin embargo, en este punto se pueden ejecutar asignaciones automáticas a celdas que pueden depender del diligenciamiento de la información o que simplemente muestren una información apenas se despliegue el formulario en STORM User sin necesidad de utilizar los botones de asignación. Esta funcionalidad puede ser particularmente útil si el cliente solicita que la información se muestre al usuario de manera inmediata y no tener que esperar a diligenciar todo y ejecutar asignaciones.
La estructura de estos eventos de cargue automático de información es bastante simple, pues usualmente se formulan como una asignación. A continuación, un ejemplo basado en la siguiente premisa:
REALIZAR EL CARGUE AUTOMÁTICO DEL CÓDIGO DE LA ENTIDAD EN LA CELDA DEL FORMULARIO
Su fórmula correspondiente sería:
Evento de asignación automática en lenguaje JavaScript

Figura 6.7. Evento de asignación automática en lenguaje JavaScript


La variable COD_ENT se mapea a la celda del formulario donde se quiere cargar el dato, y se utiliza la propiedad CurrentContext.nit para llamar el código de la entidad de cada usuario que se encuentre diligenciando la información.
NOTAAl igual que con las fórmulas de asignación, se sugiere que este tipo de eventos se asocien a celdas no editables.
  • Alertas
En general, las alertas que se pueden formular en JavaScript siguen la misma lógica y estructura de aquellas que se formulan en lenguaje STORM (es decir, se debe utilizar la palabra clave ALERTA). Para un caso particular que vale la pena resaltar, un cliente requería conocer cuando se generara un salto o gap en la numeración para la identificación de registros en un formulario por medio de un consecutivo que el usuario registraba en una celda; sin embargo, no quería que esta condición fuera bloqueante a la hora de realizar el envío. Para este caso, se planteó la siguiente fórmula:
Primer caso de alertas en lenguaje JavaScript

Figura 6.8. Primer caso de alertas en lenguaje JavaScript


Como se puede observar, se hace uso del método CurrentContext.executeQuery() que recibe la respectiva consulta SQL y sus argumentos, que en este caso corresponden a información diligenciada en el formulario. Esta consulta se asigna a la variable num para poder acceder a los resultados de la misma. Se valida que la consulta genere resultados utilizando el método num.size() para poder continuar con la verificación del gap. Para este caso, como se definió un esquema propio en la base de datos que guarda la información de los formularios (de acuerdo a la estructura de los mismos, en este caso en la tabla STRGT.CONTRATOS), se tuvo que realizar un left join con la tabla STR_CTL_CODIGO_TXS (tabla propia del modelo de STORM que contiene el registro de los envíos de información) para poder sacar la fecha de corte del envío respectivo y poderlo agregar al mensaje de alerta; adicionalmente, se organizaron los registros por consecutivo de manera ascendente, garantizando que la verificación del gap que se realiza más adelante sea correcta. Para acceder a los valores en la lista de arreglos que trae el método CurrentContext.executeQuery() se utiliza el método num.get(<fila>)[<columna>] de acuerdo a la siguiente imagen:
Vista de resultado de la consulta

Figura 6.9. Vista de resultado de la consulta


Así, se itera sobre la cantidad de filas que resultan de la consulta restando el valor del consecutivo de la fila actual con el consecutivo de la fila anterior, si el resultado es diferente de 1 implica que se ha generado un gap en la numeración. La parametrización del mensaje realizado en la fórmula se mostraría de la siguiente manera:
Mensaje de alerta generado por la fórmula

Figura 6.10. Mensaje de alerta generado por la fórmula


 

6.4. Asignaciones a BD

Utilizar JavaScript para diseñar fórmulas de asignación en base de datos es algo que resulta muy raro y eventual, ya que la mayoría de requerimientos de los clientes se pueden satisfacer utilizando formulaciones en lenguajes STORM. Sin embargo, existen casos excepcionales en donde no basta con utilizar fórmulas en STORM (bien sea por la complejidad de lo solicitado o porque definitivamente el lenguaje STORM no soporta las acciones que se le solicitan).
Para el siguiente ejemplo, el cliente requería actualizar los registros de la tabla de actores que debía funcionar como un maestro para todas las entidades (es decir, esta tabla iba a contener la información de todos los actores que reportarán todas las entidades requeridas) y esta no podía contener duplicados (porque es posible que un actor contrate con diferentes entidades y sea registrado de diferentes maneras por las mismas, he ahí la necesidad de que se actualizarán los registros).
Inicialmente, la lógica pensada era utilizar una fórmula en lenguaje STORM con ASIGNAR_OCURRENCIAS() que iterara sobre la identificación de cada actor y verificara que si existe más de una vez en la base de datos, actualice con la información del registro respectivo del formulario (se define heredable para que busque por cada registro); sin embargo, como el procesamiento que realiza STORM Server cuando recibe un archivo:
  1. Ejecuta las asignaciones.
  2. Ejecuta las validaciones.
  3. Si valida correctamente, inserta en la base de datos.
  4. Ejecuta las alarmas.
  5. Ejecuta las asignaciones a base de datos.
  6. Ejecuta los indicadores.
Cuando corría la función ASIGNAR_OCURRENCIAS(), iba a encontrar dos (2) registros de actores con la misma identificación (para el caso en que ya estuviera previamente creado en la base de datos, porque en el paso 3 el sistema insertó el envío) y se generaba un error. Esto implica que una actualización con la función ASIGNAR_OCURRENCIAS() en la misma tabla no es posible.
Para solucionar esta situación, se optó por crear una nueva tabla de actores que contenga los registros únicos actualizados de la tabla original (siendo la original la que se encuentra mapeada directamente al formulario) y se diseña una fórmula en JavaScript utilizando CurrentContext.executeQuery() para obtener la información de la tabla y CurrentContext.executeUpdate() para insertar según sea el caso.
La fórmula definida fue:
Esta fórmula se define como heredable para que itere por cada registro del formulario, es decir, por cada actor ingresado.
En esencia, lo que hace la fórmula es verificar si la llave que identifica al actor existe en la tabla: si no existe, debe crear el registro con la información que trae el formulario; si existe, ejecuta un UPDATE al registro existente con la información que trae el formulario.