Una idea feliz: Construir una cadena de ordenación de ficheros

En ocasiones, hacemos procesos que generan ficheros de forma masiva. Estos ficheros se acumulan en una ruta especificada y, cuando tenemos que consultarlos, no vemos la forma sencilla de ordenarlos por fecha. Es cierto que una de las propiedades de un fichero es la fecha de modificación pero en ocasiones esta no puede ser del todo fiable. Con esta función, podemos construir fácilmente una cadena que contiene AÑO MES DÍA HORA MINUTO SEGUNDO que resulta ideal para utilizar como nombre de un fichero:


FechaInversa

l_txtAnyo := FORMAT(DATE2DMY(TODAY,3));
l_txtMes := FORMAT(DATE2DMY(TODAY,2));
l_txtDia := FORMAT(DATE2DMY(TODAY,1));

l_txtHoraCompleta := FORMAT(TIME);
l_txtHora := COPYSTR(l_txtHoraCompleta,1,STRPOS(l_txtHoraCompleta,':')-1);

l_txtHoraCompleta := COPYSTR(l_txtHoraCompleta,STRPOS(l_txtHoraCompleta,':')+1);
l_txtMinuto := COPYSTR(l_txtHoraCompleta,1,STRPOS(l_txtHoraCompleta,':')-1);

l_txtHoraCompleta := COPYSTR(l_txtHoraCompleta,STRPOS(l_txtHoraCompleta,':')+1);
l_txtSegundo := l_txtHoraCompleta;

IF STRLEN(l_txtAnyo) = 2 THEN l_txtAnyo := '20'+l_txtAnyo;
IF STRLEN(l_txtMes) = 1 THEN l_txtMes := '0'+l_txtMes;
IF STRLEN(l_txtDia) = 1 THEN l_txtDia := '0'+l_txtDia;
IF STRLEN(l_txtHora) = 1 THEN l_txtHora := '0'+l_txtHora;
IF STRLEN(l_txtMinuto) = 1 THEN l_txtMinuto := '0'+l_txtMinuto;
IF STRLEN(l_txtSegundo) = 1 THEN l_txtSegundo := '0'+l_txtSegundo;

EXIT(l_txtAnyo+l_txtMes+l_txtDia+l_txtHora+l_txtMinuto+l_txtSegundo);

Espero que os sea muy útil.

Cuando NAS nos dice que las opciones posibles son Yes/No…

En este blog se ha hablado largo y tendido sobre NAS. Es posible que alguna vez os hayáis encontrado con algún tipo de problema al arrancar el servicio y que este os diga algo parecido a “Sí no es una opción. Las opciones posibles son Yes/No”. El principal problema de esto es el idioma que está utilizando NAS para entrar en NAV. Buscando un poco de información he visto que se comenta lo siguiente:

  • Copiar las carpetas de idiomas de la carpeta client a la carpeta application server.
  • Utilizar código en la codeunit 1 (evento NasHandler) que modifique el idioma que se utiliza al entrar en la base de datos. Para esto se suele utilizar GLOBALLANGUAGE.

Pero últimamente lo que me ha funcionado ha sido lo siguiente:

  • Abrir la carpeta %AppData% (se puede escribir directamente en inicio > ejecutar).
  • Buscar y borrar el archivo NaviBP.xml. Este archivo sólo contiene una lista con los breakpoints que el usuario ha marcado en el debbuger de NAV.

Puede parecer absurdo, pero en algunas ocasiones, borrar este fichero ha sido la solución al problema.

Fechas en inglés en WebServices

Quizás habéis visto que las fechas que son devueltas por un WebService de NAV en formato texto y que han sido convertidas a través de FORMAT(fecha) vienen en el formato MM/DD/YYYY en vez de DD/MM/YYYY.

La solución es muy sencilla: Abrid el cliente de roles utilizando el mismo usuario que utiliza vuestro WebService. Una vez dentro poned el idioma a español y salid. Con esto, se modificará un registro en la tabla 2000000073 (User personalization) donde queda guardado el idioma que utiliza el usuario. Después de esto, hay que reiniciar el servicio NAV Business Web Services.

Si después de esto, todavía sigue sin aparecer correctamente, hay que verificar que en la carpeta C:Program Files (xxx)Microsoft Dynamics NAV60Service no sólo tenemos el idioma ENU. Para instalar más idiomas, hay que buscar en el DVD de NAV la ruta InstallersESServer y ejecutar el instalador. Por último, como no, hay que volver a reiniciar el servicio.

ACTUALIZACIÓN: No recomiendo reiniciar los servicios de NAV. Es mejor parar los dos servicios de tercera capa y volver a arrancarlos.

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.

Item… producto!

Si os pregunto que me traduzcáis “Item” al español, os vendrá rápido rápido “Producto”. Pues eso es lo que le debió passar al traductor de NAV en españa hace ya unos cuantos años. Seguramente, harto de ver como la palabra Item se repetía por todo el excel de traducciones que tenía que hacer pensó que reemplazar “Item” por “Producto” iba a ser la idea del año.

Lástima que “Item” puede significar varias cosas… no hay más que ver el “Navigation Pane Designer”:

English:

Spanish:

PD: Ya que para no herir la sensibilidad de nadie han cambiado Country code por Country/region code en tooooodo NAV, podrían haber hecho lo propio con esto.

Actualización 06/11/2012: Tampoco tiene desperdicio la traducción que se hace del formulario 670. En inglés tenemos Job Queue Setup que se utiliza para programar trabajos. Pues por lo visto, a alguien se le ha ido la mano con el Reemplazar todo y en ESP vemos que se llama Configuración cola proyecto. Si tuvieras que adivinar para que sirve, con la traducción no lo acertarías nunca…

Debbugging

A veces, leer sobre temas que damos por sentados nos puede dar algunas sorpresas. En este artículo Mark Brummel se hace un repaso de las opciones que tiene el debbugger de NAV. A priori parece que no vayamos a aprender nada nuevo pero en mi me ha aportado:

  • Conocer para la diferencia entre el punto rojo y el círculo rojo:
    Uno es un breakpoint “normal” y el otro es un breakpoint anulado (pero no borrado). Lo podremos volver a activar después pero no olvidaremos dónde lo habíamos colocado.
  • Hacer un roll-back:
    No sé porqué no me había dado cuenta de que existía esa opción. Quizás ya me había acostumbrado a poner un error al final de un proceso que quería que terminara por no tener que volver a replicar todo el escenario que reproduce el error.

Echarle un vistazo son sólo 5 minutos y creo que vale la pena.

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.

¿Errores internos en Dataports? Pues vayamos a ciegas!

Últimamente parece que me caen expedientes X a diario. Hoy he descubierto que es posible hacer el dataport más tonto del mundo para exportar el contenido de una tabla y (sí) puedes morir en el intento:

El tema es que he creado un dataport con un dataitem de una tabla no demasiado grande (sin demasiados campos ni demasiados registros). En la pantalla de dataport fields he añadido todos los campos de la tabla. Ejecuto la exportación de los datos y me encuentro con esto:

La longitud del origen excede del tamaño del búfer de destino. Error raro y ceño fruncido. Lo había visto otras veces al trabajar con XML cuando todavía no existían los XMLPorts, pero nunca en un dataport. Lo primero que he pensado es que quizás había información en algún campo que interfería de alguna forma extraña con el dataport. Así que he quitado todos los campos de la sección dataport fields y he vuelto a ejecutar. El resultado: El mismo! 🙁

Como me estaba empezando a impacientar, he cambiado la tabla y la he cambiado por un entero. Internamente recorría los registros guardando los campos en las variables. A partir de ahí ningún problema. He conseguido exportar los datos sin problemas sin saber cual era el origen del problema.

Al crear otro dataport para importar estos datos en otra base de datos he vuelto a intentar utilizar la tabla destino asignando los campos en la sección dataport fields. Mi gran sorpresa ha sido ver una especie de error de sobrepasamiento que decía que no podía insertar la cadena en un text de 80. Lo más asombroso de todo es que en esta tabla no existe ningún campo de esa longitud y en el dataport tampoco existe ningúna variable. ¿De que se estaba quejando NAV?

La solución: He desactivado la propiedad ShowStatus y todo ha ido como la seda. ¿Que significa esto? Pues significa que en la ventana de proceso hay una barra de proceso que se basa en las líneas que tiene el fichero y luego tiene un campo de nombre registro que muestra los valores que conforman la clave. Es una pena que los boys de NAV no hayan tenido en cuenta que los valores que componen una clave pueden ocupar concatenados más de 80 caracteres!

Así que ya sabéis, si vais a hacer dataports que ataquen a tablas con muchos campos en la clave, desactivad ShowStatus o id tirando el peine a la basura.

Registrar asientos contables y tener el control

En alguna ocasión, es probable que hayamos tenido que programar un proceso que registre movimientos contables a medida que crea los registros en la línea de diario general. Si intentamos ver cómo lo hace NAV dentro de sus procesos estándar, vemos que existen 3 codeunits que intervienen en el registro de las líneas que hay un diario general (tabla 81):

  • Codeunit 11 – Gen. Jnl.-Check Line: Se utiliza para comprobar si la línea del diario es correcta.
  • Codeunit 12 – Gen. Jnl.-Post Line: Se utiliza para registrar una sola línea del diario.
  • Codeunit 13 – Gen. Jnl.-Post Batch: Se utiliza para registrar una sección entera del diario.

La madre del cordero está en la codeunit 12. Esta codeunit es llamada por la codeunit 13 cada vez que hay que registrar una línea y, a su vez utiliza la codeunit 11 para validar que la línea es correcta. Entonces ¿por que no usar siempre la codeunit 13? Sencillo, si utilizamos la codeunit 12 seremos nosotros los que decidiremos cuando guardamos los datos. La codeunit 13 tiene varios COMMIT, pero la codeunit 12 no tiene ninguno y la codeunit 11 tampoco.

Esto significa que yo puedo ir creando líneas en el diario general y mandarlas a registrar sin más. Al no utilizar la función COMMIT, el control de la función CONSISTENT no se ejecuta y puedo tener asientos “temporalmente” descuadrados. Yo, como programador, puedo decidir cuando empieza y cuando acaba el asiento contable y el único problema que puedo tener es que no haya controlado los registros lo suficiente y al acabar el proceso o al pasar por encima de un COMMIT reciba mensaje de CONSISTENT.

Es probable que algunos nunca se hayan encontrado con un error de CONSISTENT. Quizás los que vivimos el cambio de moneda allá por el 2000 no acordamos de alguno que nos diera dolores de cabeza. Si no estoy equivocado, sólo se utiliza en un par de puntos en todo NAV.