AX 2012 R2: Visualizar paquetes job P de SynchService

4 03 2015

En el sistema de sincronización SynchService de Microsoft Dynamics AX 2012 R2 for Retail para la sincronización de los datos de AX a tienda y viceversa disponemos de la utilidad Pack View para descomprimir los paquetes que el sistema transacciona entre AX y la tienda y al revés. La herramienta Pack View es extremadamente simple, tan solo es necesario indicar el archivo de la carpeta c:\User\<User>\AppData\Local\Microsoft Dynamics AX\60\Commerce Data Exchange\Synch Service\work que queremos descomprimir y pulsar la opción Convert. La herramienta genera en el directorio especificado una carpeta que contiene todos los XML de los datos y tablas que deben modificarse en el destino.

Sin embargo, hay que tener en cuenta que para poder descomprimir los paquetes de los jobs P que viajan de la tienda a AX hay que realizar un cambio de nombre antes de utilizar la herramienta. Así pues, si queremos descomprimir un archivo de un job P que ha llegado a AX, debemos cambiar la letra I del archivo por una R. Una vez cambiada la letra, podemos usar la herramienta para descomprimirlo. En el ejemplo siguiente se ha copiado el archivo recibido SRVPOS01-432727-I.tmp, cambiando la letra I por una R en el directorio c:\Temp:

Tras realizar la copia he ejecutado el Pack View y como observareis he podido descomprimir el archivo sin problemas:





AX Retail 2012 R2: Herramienta de comprobación de la sincronización de datos Offline

17 12 2013

A menudo tras instalar el sistema Offline en un POS de Microsoft Dynamics AX for Retail 2012 R2 nos surge la duda de saber si se han sincronizado los datos por primera vez a la base de datos Offline del POS. En otras ocasiones, tras haber activado el sistema Offline durante un tiempo, queremos comprobar si los datos generados en el estado Offline se han sincronizado a la base de datos de tienda. Para ello, tan solo disponemos de la tabla RETAILOFFLINESYNCLOG y de los logs (si los hemos activado) del servicio Offline. En Prodware hemos creado una herramienta que nos permite comprobar si los datos de la base de datos Offline de un POS están correctamente sincronizados con la base de datos Offline.

La herramienta Offline Database Comparer, realiza una comprobación de todas las tablas de los distintos ámbitos de un perfil Offline mediante la recuperación del campo clave de cada una de las tablas. A partir de la clave primaria de cada tabla, se compara el contenido de cada tabla en la base de datos Offline con su homóloga en la base de datos de tienda dependiendo de la dirección de sincronización definida en el ámbito del perfil.

La herramienta recupera la información de conexión a la base de datos de tienda y a la base de datos Offline desde el archivo de configuración POS.exe.config. A partir de esta información nos muestra en primer lugar las últimas sincronizaciones de cada uno de los POS de la tienda en la pantalla principal.

Una vez aceptadas las cadenas de conexión, la aplicación ejecuta una comprobación por cada una de las tablas de cada ámbito del perfil Offline asociado al POS, mostrándonos como resultado una tabla en la que, para cada tabla nos indica si todos los registros de una misma tabla del ámbito están en ambas tablas según la dirección de sincronización determinada en el ámbito.

Offline Database Comparer es una aplicación Windows Forms desarrollada en C# que se instala fácilmente mediante XCOPY en el directorio de la aplicación POS.





AX Retail 2012 R2: Error al instalar CU1 o KB

13 06 2013

Al intentar actualizar un terminal POS con el Cumulative Update 1 o cualquier KB posterior, obtenemos un error si el POS y el usuario con el que iniciamos la sesión en Windows no pertenecen a un dominio.

En general los POS no tienen por qué estar en un dominio por lo que este aviso puede ser habitual que nos aparezca. Para solucionar el problema, podemos proceder del siguiente modo:

1. Ir a Computer/Properties

2. Ejecutar el link Advanced system settings

3. Abrir la opción Environment Variables…

4. Crear una nueva variable con el siguiente nombre y valor:

UserDnsDomain TEST

5. Abrir el registro de Windows (regedit)

6. Editar la variable siguiente de la entrada HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Control/ComputerName/ActiveComputerName

ComputerName TEST (Guardar el valor antes de modificar porque deberemos volver a su valor original tras la instalación)

7. Ejecutar la instalación de CU1 y los KB que queramos instalar

8. Una vez finalizada la instalación, eliminar la variable UserDnsDomain y volver la clave del registro a su valor original

 





AX Retail 2012 R2: Crear un skin personalizado

29 03 2013

Una de las características de AX Retail 2012 R2 es la posibilidad de crear un nuevo estilo (skin) para la aplicación POS. Si bien es muy sencillo crear un nuevo skin, debe validarse completamente el comportamiento de cada estilo en el POS tras realizar la personalización. Para personalizar el skin seguiremos los pasos siguientes:

1. Instalamos la aplicación Developer Express v2011 vol 2 específica para AX Retail. Para ello, deberemos adquirir una licencia del producto (necesaria para personalizar el POS de AX Retail) en http://www.devexpress.com y solicitar esa versión específica

2. Una vez instalada la aplicación ya dispondremos de la herramienta SkinEditor, la ejecutamos:

3. Podemos crear un skin desde cero pero, os recomiendo que utilicéis como base el skin por defecto de AX Retail 2012 R2 y a partir de este skin personalicéis lo que necesitéis. Para ello, en primer lugar tendremos que usar la opción File/import para importar la librería por defecto de skins de AX Retail 2012 R2. Encontrareis la librería de skins por defecto, POSThemes.dll, en el directorio C:Program Files (x86)Microsoft Dynamics AX60Retail POSSkins.

4. Seleccionad el archivo POSThemes.dll tras seleccionar el tipo de archivos Skin assembly(*.dll)

5. Tras realizar la importación, los estilos por defecto de AX Retail 2012 R2 estarán disponibles como plantillas para iniciar vuestro skin personalizado (blue, red, green…)

6. Creamos un nuevo proyecto de skin a partir de uno de los skins importados en el paso anterior. Utilizamos la opción File/New y seleccionamos como Template skin, alguno de los estilos de AX Retail 2012 R2 (gray, green, light, pink, blue o dark):

7. En este ejemplo, hemos nombrado el proyecto como TestSkinTheme y el nuevo skin como TestSkin (este nombre lo usaremos posteriormente en AX HQ para asignarlo a un POS):

8. Una vez creado el proyecto, ya podemos personalizar las características que deseemos. En concreto, quizás el que más os interese personalizar sea el formato del formulario y de los botones, que encontrareis en la opción Common, y el aspecto de las tablas, que encotnrareis en el apartado Grid

9. En el apartado Grid podréis personalizar todos los controles relacionados con las tablas. En nuestro ejemplo hemos modificado algunos colores del background de la cabecera y de las filas y en el apartado Common hemos modificado el color de fondo y de la fuente para ajustar el formato a la imagen corporativa de nuestro cliente

10. Una vez realizados los cambios, Guardamos el proyecto y creamos el ensamblado con la opción File/Create assembly

11. Observaremos que se ha creado un nuevo ensamblado en el directorio donde hemos indicado. En nuestro ejemplo, tras completar el proceso:

12. Comprobamos que se ha generado el ensamblado

13. A continuación vamos a aplicar nuestro nuevo skin a un POS. Para ello, tendremos que añadir el nuevo skin a las opciones de AX HQ. En los perfiles visuales, nos situamos en el perfil visual que queramos personalizar y añadimos el nuevo skin al campo Tema y seleccionamos Ver detalles. En el enumerado correspondiente añadimos la opción TestSkin.

14. Una vez configurado el Perfil visual, podemos sincronizar los datos con el POS y continuar con la configuración del skin en el POS.

15. Para configurar el POS, debemos copiar el ensamblado del skin en la carpeta C:Program Files (x86)Microsoft Dynamics AX60Retail POSSkins

16. Tras copiar el ensamblado y haber sincronizado la configuración del Perfil visual, al iniciar la aplicación veremos que utiliza nuestro nuevo skin

17. Podemos probar directamente el skin modificando el campo POSSKINNAME de la tabla RETAILVISUALPROFILE en la base de datos de tienda. De este modo no tenemos que modificar el visual profile en HQ. Sin embargo, una vez validado, deberemos aplicarlo en HQ para que cuando se sincronice el JOB correspondiente no nos sobrescriba ese cambio





CRM 2011: Pasar parámetros a un webresource de tipo HTML

20 05 2012

Uno de los temas a tener en cuenta cuando trabajamos con webresource de tipo HTML es que, para pasar parámetros al HTML, tan solo podemos usar la variable data en la URL. Así por ejemplo si llamamos a un webresource con otros parámetros que no sean el parámetro data obtenemos este error:

/webresource/Test.html?test=test

Por tanto, si queremos pasar parámetros al webresource, tendremos que usar la variable data. Pero, ¿como podemos entonces determinar que variables estamos pasando?. Imaginemos que queremos pasar dos variables al webresource de tipo HTML (var1 y var2), tenemos dos opciones:

Opción1. Establecer el formato de las variables y pasar los valores de las mismas separadas con un símbolo (por ejemplo, |). De este modo, en el HTML deberemos parsear el valor de la variable data y obtener los valores de las variables var1 y var2. Sin embargo esto nos obliga a establecer un orden de los valores en la URL. En el siguiente ejemplo, queremos pasar los valores test1 y test2 a las variables var1 y var2 respectivamente.

/webresource/Test.html?data=test1|test2

En el código del HTML debemos parsear la variable data a través del carácter | y asignar el valor de la posición 0 a var1 y la posición 1 a var2. El problema lo tenemos cuando quien usa el webresource no sabe el orden de asignación de las variables…

Opción 2. Componer en el parámetro data el nombre de variable y el valor separado por otro carácter (por ejemplo +), distinto del carácter que usemos para separar las asignaciones. De este modo podemos pasar los valores de las variables en el orden que queramos e incluso obviar alguna de las variables. En cualquier caso, en el código HTML debemos establecer las variables pasadas en la URL a través del parámetro data.

/webresource/Test.html?data=var1+test1|var2+test2

A partir de la variable data, parseamos para obtener las asignaciones y, para cada asignación parseamos el nombre de la variable del valor (parseando por el carácter +). Posteriormente, creamos una array con cada par y creamos una función que devuelva el valor para una variable o creamos un switch que a partir del nombre de la variable, asigne el valor…

<html>
<head>
<title>Asignación de variables a partir de parámetros en un webresourece de tipo HTML</title>
<script type="text/javascript">
var var1 = "";
var var2 = "";
function OnLoad() {
try {
var params = getUrlParam("data").split("|");
for (i = 0; i < params.length; i++) {
var vls = params[0].split("+");
switch (vls[0]) {
case "var1":
var1 = vls[1];
break;
case "var2":
var2 = vls[1];
break;
}
alert("La variable " + vls[0] + " se ha inicializado con el valor " + vls[1]);
}
}
catch (e) {
}
}
</script>
</head>
<body onload="OnLoad()">
<div id="results"></div>
</body>
</html>

Obviamente debemos tener en cuenta los casos en los que el usuario quiera pasar los caracteres que usemos como delimitadores en el propio texto… controlar cuando no pasa ningún parámetro… Pero eso entiendo que seréis capaces de controlarlo ampliando este código ;-).





CRM 2011: Mostrar datos de entidades relacionadas

15 05 2012

Una de las opciones solicitada a menudo por los clientes es poder visualizar (en modo de sólo lectura) información relacionada con un lookup en el formulario de detalle donde este reside. Así por ejemplo, en alguna ocasión se nos ha solicitado mostrar datos del contacto principal de una cuenta en el propio formulario de la cuenta. Normalmente, la respuesta suele ser que simplemente pulsando sobre el link del contacto en el lookup, puedes acceder al formulario de detalle del contacto. Sin embargo, a continuación os propongo una solución, extraída a partir del blog de Darren Turner, en la que de una forma sencilla, con un webresource configurable de tipo HTML podemos mostrar información en el propio formulario de cuenta (el ejemplo es valido para cualquier lookup en un formulario, no para partylist).

La solución consiste en crear una página HTML, a la que referenciamos varios webresource como json2.js y jquery1.4.1.min.js para poder realizar llamadas REST y algunas páginas de estilo estándar de CRM 2011. El código de la página HTML es el siguiente:

<HTML xmlns="<a href="http://www.w3.org/1999/xhtml&quot;>">http://www.w3.org/1999/xhtml"></a>
<HEAD>
<TITLE>Related Entity Information</TITLE>
<SCRIPT type=text/javascript src="jquery1.4.1.min.js"></SCRIPT>
<SCRIPT type=text/javascript src="json2.js"></SCRIPT>
<LINK REL=StyleSheet HREF="/_common/styles/global.css.aspx" TYPE="text/css">
<LINK REL=StyleSheet HREF="/_common/styles/fonts.css.aspx" TYPE="text/css">
<LINK REL=StyleSheet HREF="/_common/styles/theme.css.aspx" TYPE="text/css">
<LINK REL=StyleSheet HREF="/_common/styles/form.css.aspx" TYPE="text/css">
<META charset=utf-8></HEAD>
<BODY style="BACKGROUND-COLOR: #F6F8FA; MARGIN: 0px; font-family: Segoe UI, Tahoma, Arial; font-size: 11px;" onload=onload() contentEditable=true>
<DIV id=related></DIV>
<SCRIPT>
var FORM_TYPE_UPDATE = 2;
var FORM_TYPE_READ_ONLY = 3;
var FORM_TYPE_DISABLED = 4;
var ODataPath;
var serverUrl;
var entityName = "";
var id = "";
var fields;
var labels;
var lookup;
var rows = 2;
var entity;
var html = "<table cellpadding='3' cellspacing='0' height='1%' style='table-layout: fixed;' valign='top' width='100%'>";
html += "<col width='115'><col><col class='FormSection_WriteColumnHeaders_col' width='135'><col>";
function onload() {
init();
}
function init() {
serverUrl = parent.Xrm.Page.context.getServerUrl();
ODataPath = serverUrl + "/XRMServices/2011/OrganizationData.svc";
GetParameters();
if (parent.Xrm.Page.ui.getFormType() == FORM_TYPE_UPDATE ||
parent.Xrm.Page.ui.getFormType() == FORM_TYPE_READ_ONLY ||
parent.Xrm.Page.ui.getFormType() == FORM_TYPE_DISABLED) {
var value = parent.Xrm.Page.ui.controls.get(lookup).getAttribute().getValue();
if (value != null) {
id = value[0].id.replace('{', '').replace('}', '');
entityName = value[0].entityType;
}
}
retrieveRecord(id);
}
function LoadTable() {
var index = 1;
for (var i = 0; i < fields.length; i++) {
if (index == 1)
html += "<tr valign='top'>";
html += "<td class='ms-crm-FieldLabel-LeftAlign ms-crm-Field-Normal'><label>";
if (labels != null)
html += labels[i];
else
html += fields[i];
var val = "";
try {
if (typeof entity[fields[i]] == "object")
val = entity[fields[i]].Name;
else if (typeof entity[fields[i]] == "undefined")
val = "N/A";
else
val = entity[fields[i]];
}
catch (err) { }
html += "</label></td><td align=left>" + val + "</td>";
if (fields.length == 1)
html += "<td class='ms-crm-Text ms-crm-ReadOnly' colspan=2>&nbsp;4</td>";
if (index == rows) {
html += "</tr>";
index = 1;
}
else
index++;
}
html += "</table>";
related.innerHTML = html;
}
function retrieveRecord(Id) {
var retrieveReq = new XMLHttpRequest();
retrieveReq.open("GET", ODataPath + "/" + entityName.toTitleCase() + "Set(guid'" + Id + "')", true);
retrieveReq.setRequestHeader("Accept", "application/json");
retrieveReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
retrieveReq.onreadystatechange = function () {
retrieveReqCallBack(this);
};
retrieveReq.send();
}
function retrieveReqCallBack(retrieveReq) {
if (retrieveReq.readyState == 4 /* complete */) {
if (retrieveReq.status == 200) {
//Success
entity = JSON.parse(retrieveReq.responseText).d;
LoadTable();
}
else {
throw new Error("Error retrieving Record");
}
}
}
function GetParameters() {
var querystring = unescape(window.location.search.replace('?', '').replace('data=', ''));
var params = querystring.split('&');
for (var i = 0; i < params.length; i++) {
var param = params[i].split('=');
switch (param[0]) {
case "lookup":
lookup = param[1];
break;
case "fields":
fields = param[1].split(',');
break;
case "labels":
labels = param[1].split(',');
break;
}
}
}
String.prototype.toTitleCase = function () {
var A = this.split(' '), B = [];
for (var i = 0; A[i] !== undefined; i++) {
B[B.length] = A[i].substr(0, 1).toUpperCase() + A[i].substr(1);
}
return B.join(' ');
}
</SCRIPT>
</BODY>
</HTML>

Al añadir el webresource en un formulario, debemos pasarle como parámetros, el lookup, los campos a mostrar y los nombres que queremos mostrar en las etiquetas. Con esta simple configuración, el webresource al cargarse, recuperará la información del registro relacionado mediante una llamada REST y los mostrará en un formato de tabla 2xn con estilo CRM 2011. En el siguiente ejemplo, se muestran datos de dos campos lookup a contactos en una entidad personalizada:

Para ello se ha configurado cada webresource con los siguientes datos:

Como veréis en el webresource, se han configurado los parámetros lookup, fields y labels, separados por un &, en el que se indican respectivamente el nombre del lookup del que sacar el GUID, los nombres de esquema a retornar y las etiquetas de los campos a mostrar.





AX Retail 2009: Control del password de usuario en POS

30 04 2012

Una de las características importantes del POS de AX Retail 2009 es la utilización de Transaction Service para realizar operaciones desde el POS al BackOffice. Una de estas operaciones remotas puede aplicarse a la validación del password de usuario (LogOn). Sin embargo, una configuración específica de este servicio puede tener como consecuencia que el usuario pueda entrar en el POS sin que se valide su clave de usuario, o lo que es lo mismo, que el POS no tenga ninguna validación de la clave del usuario. A continuación describimos brevemente esa situación. Entendemos que esto se trata de un bug de la aplicación (por lo que así lo hemos reportado), sin embargo, mientras esa solución no llega, consideramos importante tener en cuenta la configuración que explicamos a continuación.

En la configuración del Perfil de Transaction Service disponemos de un check que permite indicar si la validación de la clave del usuario se realizará en el equipo local o bien a través de Transaction Service contra el BackOffice.

Si marcamos este flag, debemos tener en cuenta que la validación de la clave se realizará en BackOffice por lo que debemos asegurar la conexión entre el POS y el BackOffice y que el servicio Transaction Service funciona correctamente. Si alguno de esos aspectos falla, la validación del usuario no podrá realizarse por lo que el usuario no podrá acceder al POS tras esperar un tiempo a que el sistema detecte el fallo de conexión y, apareciendo el siguiente mensaje:

Para evitar esta situación, con el flag de autenticación por Transaction Service, uno puede usar otro parámetro de configuración a nivel de usuario que permite obviar los mensajes de error de Transaction Service. Si, manteniendo el flag de autenticación por Transaction Service, marcamos la opción de continuar con errores en Transaction Service en un usuario:

Al intentar acceder al POS, el sistema intentará validar la clave en BackOffice a través de Transaction Service, si encuentra un error lo evitará y accederá al POS sin haber validado la contraseña!!!.

Por tanto, es muy importante que, a menos de que el fabricante aporte otra solución, no se realice la autenticación del usuario en BackOffice a través de Transaction Service y se utilice la autenticación local, es decir que NO se marque el flag de Personal de Retail Transaction Service (traducción poco acertada por cierto…).