El log de cambios (Parte 2)

En la primera entrega de este “especial” log de cambios conocimos la funcionalidad del log de cambios, como podemos activarla y cómo podemos configurarla para monitorizar los cambios que se producen en cualquier registro.

En esta segunda entrega, nos vamos a centrar en cómo funciona el log de cambios de forma interna. Conociendo cómo funciona, podremos tener la base para desarrollar funcionalidades que afecten a toda la aplicación como gestiones de aprobaciones de cambios, alertas, sincronización con otros sistemas, etc.

Si vemos la codeunit 423 (Change Log Management) vemos que hay una función un tanto curiosa. La función GetTableTriggerMask devuelve un valor entero en función de la configuración de monitorización que tengamos en log de cambios. El entero se incrementa en 1 si se controlan las inserciones, 10 si se controlan las modificaciones y 4 si se controlan las eliminaciones. Si no se hace ningún tipo de control el valor del entero se queda en 0 (cero). Si pensamos en todas las combinaciones posibles, no hay ninguna combinación que repita una valor entero igual:

Inserción Modificación Eliminación Total
I+M+E 1 10 4 15
I+M 1 10   11 
I+E 1   4
I 1     1
M+E   10 4 14
M   10   10
E     4 4
(nada)       0

OK, todo esto está muy bien pero ¿para que sirve este número?
A nosotros no nos sirve para nada, pero NAV incorpora en su codeunit 1 una función que le dice a NAV si debe disparar 3 eventos especiales. En la codeunit 1 existe la función GetGlobalTriggerMask que precisamente llama a la función que acabamos de ver. Lo que hace esta función es devolverle al sistema que tiene que hacer (devolviendo el valor de la tabla que hemos visto antes).

De acuerdo, supongamos que tenemos una tabla en la que controlamos todo. Esta función devolverá a NAV el valor 15. ¿que hace ahora NAV?. Internamente llama a las funciones (también de la codeunit 1) OnGlobalInsert, OnGlobalModify, OnGlobalDelete y OnGlobalRename.

Estas funciones se ejecutan con el parámetro de la referencia del registro, que podemos recoger y usar a nuestro antojo. En el caso del log de cambios, estas funciones vuelven a llamar a la codeunit 423 que se encarga de guardar los posibles cambios que ha sufrido el registro.

El log de cambios (Parte 1)

En NAV existe ya desde hace unas cuantas versiones un sistema para el control de cambios que hacen los usuarios. El administrador puede, de una forma más o menos sencilla configurar las acciones (insertar, editar y eliminar) y los campos de las tablas que quiere monitorizar.

En este post voy a tratar el log de cambios desde el punto de vista funcional mostrando como se configura y como se guarda el log de los datos que se han modificado.

Lo primero que tenemos que hacer al utilizar el log de cambios es saber si lo tenemos configurado en licencia y lo siguiente es activarlo. En la pantalla de configuración del log de cambios existe una única opción que sirve para activar el log:

Ahora ya podemos pasar a configurar las tablas que queremos monitorizar. En la parte inferior de la anterior pantalla tenemos el acceso a esta pantalla:

En esta pantalla podremos ver todas las tablas que existan en la base de datos. Tan sólo hay que indicar si queremos monitorizar todos los campos o algunos de ellos dentro de las columnas de inserción, modificación y eliminación. Si nos decantamos por decidir monitorizar sólamente algunos de ellos tendremos que indicar cuáles. Para ello pulsaremos sobre el assist button dentro de la celda correspondiente y accederemos a una pantalla que muestra todos los campos de la tabla. Fijaos que los campos de tipo flowfield no aparecen pues propiamente no cambian por órden del usuario sino que son cambiados a través de otras tablas:

En este ejemplo he decidido que quiero establecer un control sobre algunos campos de la tabla términos de pago ya que últimamente alguien se está dedicando a cambiar algunos valores y quiero averiguar quien es.

Lo siguiente que voy a hacer es comprobar que mi configuración es correcta, así que cierro NAV, vuelvo a entrar y modifico algunos valores de unos de los registros de la tabla. El resultado es el siguiente:

Como podemos ver, en el último registro ha quedado guardado el cambio que he hecho, pero, no solo eso, también puedo ver como los cambios que he hecho en la propia configuración del log de cambios también queda guardada de forma que la misma persona que está modificando los términos de pago intenta modificar la configuración del log de cambios, también quedará registrado independientemente de que yo haya configurado la propia tabla de log de cambio para que esté dentro del grupo de tablas monitorizadas.

En el siguiente post veremos cómo está estructurada la funcionalidad y que puntos del programa intervienen dentro de su funcionamiento.

Trabajando con recordRefs y fieldRefs

El uso de los tipos recordRef y fieldRef no es muy común en el código de NAV y su uso se reduce prácticamente a funcionalidades que afectan de forma muy globalizada en todo el sistema como por ejemplo la funcionalidad de Log de Cambios.

A mi, personalmente, me gusta utilizarlas cuando veo que una sección de código puede ser útil en varias entidades distintas de la base de datos. Recuerdo un desarrollo que hice ya hace un tiempo en que una función construía el XML necesario para la exportación de facturas, albaranes, abonos, etc. Enseguida detecté que la mayoría de campos eran los mismos y que estaba a punto de cuadriplicar mucho código que realmente hacía lo mismo. En este caso utilicé fieldRefs y recordRefs para apuntar a los registros y campos necesarios dado que estas tablas comparten prácticamente los mismos campos y que, además, están dispuestos con el mismo ID (núm. de campo) fue muy rápido y muy sencillo.

En el siguiente ejemplo os voy a mostrar un ejemplo documentado de una función que utiliza este tipo de variables para hacer de otra forma el acceso a las dimensiones que hace NAV desde los distintos documentos de venta:

Si os fijáis bien, en el Form 132, 130, 134, etc. se utiliza un valor constante en la propiedad RunFormLink del botón dimensiones indicando el número de la tabla asociada. A su vez, en el caso de las líneas, existe una función copiada y pegada que muestra las dimensiones relacionadas.

En este caso vamos a utilizar una función para la visualización de las dimensiones asociadas a documentos de forma que pueda ser invocada sin prestar atención al número de la tabla. Esta función podría incorporarse a la Codeunit 408 y sería ella misma la que determinaría el tipo de dato que la llama y pasaría los datos al formulario. Veréis que esta forma no es mejor y quizás no sea necesario el uso de recordRefs y fieldRefs pero pienso que es un ejemplo bastante didáctico para entender correctamente el uso de este tipo de variables. La función necesaria tendría este aspecto:

Una vez hecho esto procederemos a modificar la función ShowDimensions de la tabla 111, de forma que apunte a la nueva función que acabamos de desarrollar en el anterior punto:

Después de esto, modificaremos el Form 130 dónde añadiremos una nueva opción para mostrar las dimensiones del documento asociadas a la cabecera a través de nuestro nuevo método:

En su interior, escribiremos el siguiente código:

Como podemos ver, tanto el acceso desde las líneas como desde la cabecera funciona correctamente. Ahora sólo queda hacer lo mismo con el resto de documentos de venta:

Espero que os haga gustado y que os sirva de mucha ayuda. Podéis descargar este ejemplo a través del siguiente enlace: Descarga (Cuidado: la importación de éste objeto puede sobreescribir desarrollos. Se recomienda importar en una base de datos de pruebas).