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.

Asignación de credenciales para acceder a servicios web

Hace un par de semanas tuve un pequeño problema cuando intentaba acceder a un servicio web publicado en NAV. Disponía de mis desarrollos en asp.net en una máquina virtual con un dominio distinto al servidor donde se encontraba NAV. Por lo tanto, tenía que indicarle de alguna manera el usuario, password y dominio que tenía que utilizar la aplicación web para conectarse. En varios sitios encontré que había que utilizar la siguiente linea de código antes de hacer la llamada a la función del servicio web:

someService.Credentials = new NetworkCredential(“user”, “password”, “domain”);

Hay que recalcar que el último parámetro es optativo pues no es necesario indicarlo cuando el servidor se ubique en el mismo dominio. En mi caso, por encontrarme en un dominio distinto, lo indiqué.

Bien, la aplicación web se conectaba sin problemas y llegados a ese punto me olvidé del tema de las credenciales. Cuando la aplicación web estaba terminada, la publiqué en el servidor definitivo que sí que se encontraba en el mismo dominio y mi sorpresa fue ver que no había forma humana de que funcionara. Constantemente obtenía un error 401 – No autorizado.

La solución: la verdad es que hice bastantes pruebas pero creo que lo hizo que funcionara fue quitarle el parámetro del dominio a la función que otorga las credenciales. A mi entender, no tiene mucho sentido que un método de autenticación falle cuando se le proporciona mas información de la que necesita. En todo caso debería ignoraría pero nunca dar error (y menos si es tan poco descriptivo).

Creación de una BBDD para NAV Developer’s Toolkit

Hace ya bastante tiempo que ando utilizando Developer’s Toolkit (en adelante DevKit) como herramienta para el control de cambios en proyectos de cierta envergadura. Su uso me permite analizar fácilmente las afectaciones que tiene una modificación, los usos que se hacen de un campo o detectar posibles errores que de otro modo se convierten en una odisea. En este post vamos a tratar uno de los puntos que hacen desistir a mucha gente de utilizarlo: Crear la base de datos.

Últimamente vengo utilizando la versión 3.01.410 que podréis encontrar sin problemas en la sección downloads de mibuso.com. En mi caso, me gusta utilizar SQL para alojar la BBDD. Esto permite que varios usuarios puedan utilizar la BBDD y así pueda convertirse en una herramienta ya no personal si no, de todo el equipo de trabajo que pudiera estar involucrado en el proyecto. Así, mientras estéis descargando DevKit podéis ir comprobando que disponéis de Microsoft SQL Express 2008 R2. Acostumbro a utilizar esta versión por varios motivos. Los principales son que es compatible con la versión de NAV que vamos a usar y que no consume excesivos recursos si vamos a utilizar la BBDD de vez en cuando.

Una vez tengamos SQL a punto y hayamos instalado DevKit, lo siguiente que hay que hacer es abrir NAV 2009 SP0. Esto es importante: normalmente la versión que DevKit que viene en el CD de NAV ha sido diseñada para trabajar con la versión antecesora (todavía no entiendo muy bien porque se hace esto). Una vez abierto, creamos una nueva BBDD en nuestro servidor SQL, una nueva empresa e importamos el FOB que hay en la carpeta donde se ha instalado DevKit. Este FOB contiene la estructura de datos y funciones necesaria para que se haga una indexación de la estructura de objetos que importaremos.

Una vez hayamos hecho esto, ya podemos cerrar el cliente de NAV y podemos abrir la BBDD con DevKit. Inicialmente la base de datos no contiene datos. Para crear los datos tenemos dos opciones:

  1. Importar directamente desde NAV. Para poder hacerlo, DevKit utiliza un cliente de NAV que ya tengamos abierto como puente para acceder a todos los objetos de la BBDD y traerse a su BBDD todas sus entrañas.
  2. Importar un TXT generado desde la BBDD. El tiempo de importación es más o menos el mismo, pero a este hay que añadirle el tiempo de exportación.

Cuando el proceso haya terminado, tendremos una foto de la estructura de datos, funciones y procesos de la BBDD. Podremos por ejemplo saber en que puntos de todo el programa se utiliza un campo, detectar en que sitios se hace un DELETE de una de nuestras tablas, etc.

Además, si somos un poco ordenados con las importaciones y las empresas que creemos, dispondremos de un fantástico control de versiones para poder volver a cualquier estado anterior de los desarrollos que estemos haciendo.

La importancia del nombre

Hoy he tenido una batalla con la instalación de los servicios de tercera capa de NAV 2009. Resulta que había que replicar un entorno real de aplicación con acceso a NAV a través de Microsoft Dynamics NAV Business Web Services. Después de restaurar una copia de la BBDD, replicar la aplicación y cambiar el puerto de la ruta de acceso al Web Service, me he dispuesto a crear una nueva instancia del servicio Microsoft Dynamics NAV Business Web Services. En varios foros he encontrado que la forma rápida de hacerlo consistía en duplicar la carpeta donde se encuentran los servicios de tercera capa de NAV, modificar el archivo *.config para indicarle los nuevos puertos que se van a utilizar e instalar nuevos servicios. El problema ha venido cuando, después de instalar los nuevos servicios y arrancarlos, el que en teoría tenía que ser el servicio Microsoft Dynamics NAV Business Web Services se arrancaba como un Microsoft Dynamics NAV Server. Con lo cual las dos instancias que se estaban creando eran de Microsoft Dynamics NAV Server y al arrancar la segunda daba error pues decía que el puerto utilizado ya estaba siendo utilizado. Después de muchas, muchas pruebas he dado con la siguiente página que me ha resuelto todas las dudas. En ella se explica las 4 ó 5 claves que hay que tener en cuenta a la hora de instalar los servicios y da 2 ejemplos perfectos para copiar y pegar. Después de esto, todo ha ido como la seda. En resumen lo que viene a decir la página es:

  • Lo que define si el servicio que se está creando es “Microsoft Dynamics NAV Server” o “Microsoft Dynamics NAV Business Web Services” es el nombre del servicio. Si el servicio empieza por “MicrosoftDynamicsNAVWS” estaremos instalando una instancia de “Microsoft Dynamics NAV Business Web Services”. Cualquier otra cosa, se tratará de uns instancia de “Microsoft Dynamics NAV Server”.
  • Ofrece dos ejemplos de lo que tiene que ser la línea de comandos idónea para instalar los servicios:
  1. SC CREATE “MicrosoftDynamicsNAV$Svr2” binpath= “C:Program FilesMicrosoft Dynamics NAV60Service2Microsoft.Dynamics.Nav.Server.exe” DisplayName= “MSSvr2”
  2. SC CREATE “MicrosoftDynamicsNAVWS$Svr2″ binpath= “C:Program FilesMicrosoft Dynamics NAV60Service2Microsoft.Dynamics.Nav.Server.exe $Svr2” DisplayName= “MSWSSvr2” type= share

Discos SSD para mejorar el rendimiento de NAV

Hace un tiempo ya tuve la ocasión de ver la mejora que representa la implementación de los discos SSD (sobretodo en portátiles). Recuerdo perfectamente un vídeo donde se comparaba el tiempo de arranque de un ordenador con discos convencionales y uno exactamente igual con discos SSD y la diferencia era notable, por no hablar de la eficiencia de los últimos cuando había vibraciones.

Era cuestión de tiempo que este tipo de tests llegaran al mundo de los servicios de datos y, por supuesto, a NAV. En el siguiente enlace podemos ver un buen estudio de comparativa de varios procesos de NAV. En todos ellos el rendimiento de los discos SSD es bastante bueno, y aunque todavía resultan algo caros, hay que valorar convenientemente el coste de este cambio frente al coste que conlleva la mejora de rendimiento de los procesos.

Estas asignaciones nunca fallan

SOBREPASAMIENTO: ¿A quién no le ha pasado alguna vez lo siguiente? Te piden hacer un proceso “sencillo” para importar información en Navision. Como buen experto que eres lo tienes listo en unos pocos minutos y, para asegurarte, haces unas cuantas pruebas y compruebas que realmente funciona. Te aseguras de que el proceso detecta los duplicados, no estropea datos, es estable, etc. Para acabar de probarlo bien, pides un fichero de pruebas que funciona sin problemas. Al cabo del tiempo, llega el día D y la hora H, necesitas lanzar el proceso y de repente…

SOBREPASAMIENTO. Bien!! No pasa nada, esto no daña tu imagen, pero… a nadie le gusta llevar una mancha en la camisa y… esta te la has colgado en el desayuno (campeón)… Es un error tan tonto y tan básico que incluso la persona que tienes al lado dice “¿no cabe?” a lo que respondes “prfff… más o menos”. No va mal encaminado pues es cierto que “algo no cabe en algún sitio” hasta ahí llegamos todos… Ahora el problema es que hay que encender el debbuger y esperar a que la barrita se vuelva a poner en el 95%. De esto hablaremos otro día pero está comprobado que la probabilidad de que una importación falle viene indicada en la propia barra de proceso y que cuando llegas al 100 es que Navision te ha perdonado la vida.

Volvamos a la parte técnica: Evidentemente, el problema es que hemos intentado almacenar una cadena de caracteres en un campo o variable donde no puede caber. Existe un pequeño truco que nos permite cubrirnos las espaldas ante esto:

variableDestino := COPYSTR(variableOrigen,1,MAXSTRLEN(variableDestino));

Con MAXSTRLEN obtenemos la longitud máxima de la variable destino y con COPYSTR seleccionamos solamente esos primeros caracteres. Con esto conseguimos que el proceso no desate un error, aunque hay que advertir al usuario que el proceso truncará aquellos datos que se excedan de los límites admitidos.

En el caso de los dataports, acostumbro a utilizar variables de anchos generosos (XXL) sobre los que volcar la información para después pasarlo a los campos de las tablas. Es, en el paso de variable a campo, dónde utilizo este trozo de código. Es una forma de asegurarme que no existan sobrepasamientos y de ofrecer una tarea más sencilla a un futuro debbugador del proceso.