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.

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).