Buscar en este blog

viernes, 17 de julio de 2015

Publicar un servicio intermedio .Net para comunicar AIF Dynamics Ax con Java


Me he topado con la no grata sorpresa que para consumir servicios de dynamics Ax 2012 R2 mediante lenguajes distintos a .Net como Java o PHP, la única solución viable es que se ponga un servicio intermedio de .Net que si exponga el wsdl como lo necesitan las distintas plataformas. La razón? que Java o PHP necesitan que se exponga el xsd dentro del wsdl y de momento esto solo lo ofrece .Net, quedando la comunicación como en la figura:

image

Así que comencemos, supongamos que nuestros servicios en Ax están desarrollados y expuestos, esto lo verificamos desde Administración del sistema –> Configuración –> Services and Application Integration Framework –> Puertos de entrada, en esta pantalla podemos observar la url con la que se expone nuestro servicio y que es la url que vamos a referenciar en nuestro “servicio intermedio” de .Net

image

Revisamos que podamos ver en el explorador el wsdl que expone la url de Ax

image

Ahora comenzamos con el servicio intermedio, lo primero es abrir Visual Studio, no hay diferencia si es 2010, 2012 o 2013. Elegimos un nuevo proyecto de tipo WCF –> WCF Web application

image

En las referencias, agregamos nuestra url del servicio de Ax que vamos a consumir en este servicio intermedio. Click derecho sobre el nodo Service References –> Agregar referencia a servicio… Pegamos nuestra url y vemos los servicios, aquí debemos visualizar los métodos disponibles expuestos por nuestro servicio de Ax, con esto ya agregamos nuestro servicio de Ax al servicio intermedio de .Net.

image

Después de esto, necesitamos agregar la lógica que reciba los datos de alguna plataforma externa (Java o Php) para enviarlos hacia Ax. En mi caso, en la interfaz de .Net yo expongo un servicio con dos métodos, en uno recibo datos para crear ordenes de venta y en otro recibo el identificador de una orden de venta y regreso el estatus de la misma.

image

Cada uno con la lógica respectiva. Ahora nos resta publicar el servicio en el IIS para que pueda ser consumido por las distintas plataformas.

image

Elijo que lo quiero publicar en un sistema de archivos para mandarlo al IIS

image

En el Target Location, eliges la carpeta del IIS y el sitio donde quieras publicar, lo puedes publicar dentro de Defatul Web Site en un web application nuevo para tus pruebas o si ya tienes un sitio definido lo eliges.

image

Te regresa la ruta que elegiste a la venta a de perfiles, haces click en el botón “Publicar” y ahora ya abrir el IIS donde vas a ver tu App publicada.

image

Ahora necesitamos verla en el explorador para saber si esta bien publicada. Si le damos click en Browse. De primera instancia nos aparecería este error: “HTTP Error 403.14 – Forbidden, The web server is configured to not list the contents of this directory.”

image      image

Vamos en el IIS a la opción de Directory Exploring y damos doble click para entrar a las propiedades del elemento. Dentro de las propiedades en la barra lateral derecha, esta la opción “Enable”, hacemos click sobre ella.

image
image

Si presionas de nuevo “Browse” se abre el explorador ya con el wsdl listo para consumir!

image

Ahora, este es el wsdl normalito (http://xx.xx.xx.xx/GAELTPortalNet/ServicioNet.svc?wsdl), si lo que buscas es que sea consumido por java, debes poner el xsd en el wsdl, para eso solo cambiamos la ruta agregándole el singlewsdl al final: http://xx.xx.xx.xx/GAELTPortalNet/ServicioNet.svc?singlewsdl

Espero te ayude.

Post que podrían interesarte:
Crear servicio personalizado AIF
Crear documentos asociados a un registro por código (DocuRef)
Teclas rápidas en Microsoft Dynamics Ax 2012


Y por cierto, acuérdate de darle click a algún anuncio si el post te sirvió de algo. O comenta si quieres saber sobre algún tema en específico.

No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma. 

sábado, 4 de julio de 2015

Rellenar o incluir caracteres en cadenas con strRFix en Dynamics Ax 2012

Muchas veces necesitamos incluir en nuestras cadenas de texto ciertos caracteres porque requerimos que nuestra cadena cumpla con un formato especifico. Por ejemplo, si queremos que un folio en el que no usamos secuencias tenga una norma de 6 dígitos, necesitamos que cuando el usuario introduzca el número "1" se transforme en "00001".

Para esto tenemos la función strRFix, que se usa:

static void mascaraFolios(Args _args)
{
    int                             folioSiguiente;
    DimensionValue                  cedisMascara;
    str                             folioMascara,
                                    cedisSalesLine,
                                    folioOriginal, 
                                    folioFinal;
   
    cedisSalesLine = "13" ;
    folioOriginal = "5" ;

    //Modificación para incluir el cedis en el formato del folio
    //Se requieren 3 dígitos para cedis
    cedisMascara = strRFix(cedisSalesLine, 3 '0' );
   
    folioSiguiente = str2int(folioOriginal) + 1;
    folioMascara = strRFix(int2str(folioSiguiente), 6'0');
    folioFinal = cedisMascara + "-" + folioMascara;
   
    info(folioFinal);
}

Y el resultado:


Si quisieras que los ceros los agregara del lado derecho, solo usamos la función strLFix. Por ejemplo:

static void mascaraFolios(Args _args)
{
    int                             folioSiguiente;
    DimensionValue                  cedisMascara;
    str                             folioMascara,
                                    cedisSalesLine,
                                    folioOriginal, 
                                    folioFinal;
   
    cedisSalesLine = "13" ;
    folioOriginal = "5" ;

    //Modificación para incluir el cedis en el formato del folio
    //Se requieren 3 dígitos para cedis
    cedisMascara = strLFix(cedisSalesLine, 3 '0' );
   
    folioSiguiente = str2int(folioOriginal) + 1;
    folioMascara = strLFix(int2str(folioSiguiente), 6'0');
    folioFinal = cedisMascara + "-" + folioMascara;
   
    info(folioFinal);
}

Y el resultado:

Post que podrían interesarte:
Capturar errores del infolog mediante código x++
Crear documentos asociados a un registro por código (DocuRef)
Teclas rápidas en Microsoft Dynamics Ax 2012


Y por cierto, acuérdate de darle click a algún anuncio si el post te sirvió de algo. O comenta si quieres saber sobre algún tema en específico.

No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma. 


jueves, 4 de junio de 2015

Archivos de logs de compilación en Dynamics Ax 2012


Aquí las rutas donde se localizan los distintos archivos de compilación de Ax.

Cuando es una compilación paralela, el log de resultados se encuentra en:
C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\Log\AxCompileAll.html

Cuando es una compilación completa desde al AOT:
C:\Users\user1\Microsoft\Dynamics Ax\Log\AxCompilleAll.html
 o dicho de otra forma: %UserProfile%\Microsoft\Dynamics Ax\Log\AxCompilleAll.html

Cuando se genera el cil full:
C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL\Dynamics.Ax.Application.dll.log



Post que podrían interesarte:
Crear barra de progreso por código
Consultas en tablas con ValidTimeState en Ax 2012
Multiselect de grid en Ax 2012
Crear lookup en clase dialog



Y por cierto, acuérdate de darle click a algún anuncio si el post te sirvió de algo.

No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma. 

miércoles, 20 de mayo de 2015

Crear barra de progreso en Dynamics Ax 2012

Muchas veces tenemos procesos muy tardados que necesitan al menos que el usuario sepa que se están realizando para que no comience a dar clics por todos lados y espere pacientemente a que el proceso termine.

Para esto están las barras de progreso mundialmente conocidas, es algo como lo siguiente:

image

Para hacerlo en nuestro código es muy sencillo, primero necesitamos identificar el inicio de nuestro proceso, por ejemplo, yo tengo un lectura de una base de datos externa que tarda unos cuantos segundos, así que al inicio de todo mi proceso agrego mi progress

public void run()
{
    #Macrolib.AviFiles
    str ruta;
    //ruta = "Data Source = 'C:\\Temp\\RBAsset.sdf'; LCID= 1033; Case Sensitive=true";    

    if (ruta != "" )
    {
        progress = new RunbaseProgress( 1null);
       progress.setCaption( strFmt ("Procesando %1" "base de datos movil"));
       progress.setTotal(TotalDeRegistros);
       progress.setAnimation(#AviTransfer);
       progress.updateInterval( 1 );

        //Llena tabla intermedia
        this.bulkToAx(ruta);       
    }
    else
        warning( "No se ha definido la ruta de la BD ó el dispositivo no esta conectado." );


}

Y en mi proceso mas pesado, que en este caso es dentro del método bulkToAx es donde voy actualizando la barra, algo similiar al siguiente código:
 
//Manda llamar la clase de .Net para leer la BD Sdf del dispositivo movil
public void bulkToAx( str _rutaBd)
{
    System.Data.DataRowCollection       dataRowCollection;
    System.Data.DataRow                 dataRow;
    int                                 i,totalRow;
    GRWActivosFijosSdf                  gRWActivosFijosSdf;

    System.Data.DataTable tablaNet = new System.Data.DataTable();
    GRWBdSdfToAx.GRWBdSdfToAxClass clase = new GRWBdSdfToAx.GRWBdSdfToAxClass();

    tablaNet = clase.ConsultaTodosLosActivos(_rutaBd);

    dataRowCollection       = tablaNet.get_Rows();
    totalRow                = dataRowCollection.get_Count();

    for(i = 0 ; i < totalRow; i ++)
    {
        dataRow = dataRowCollection.get_Item(i);
        
        gRWActivosFijosSdf.clear();
        gRWActivosFijosSdf.CodigoBarras     = dataRow.get_Item( 0 );
        gRWActivosFijosSdf.Descripcion      = dataRow.get_Item( 1 );
        gRWActivosFijosSdf.Serie            = dataRow.get_Item( 2 );        
        gRWActivosFijosSdf.insert();

        progress.setCount(i);
      progress.setText( strFmt ("Cargando registro: %1" ,i));
      progress.update( true );
    }

}

Listo, con esas tres líneas en nuestro proceso mas pesado, la barra va a ir corriendo e informando al usuario que ax sigue trabajando.


Post que podrían interesarte:
Distintos tipos de indicadores de progreso
Consultas en tablas con ValidTimeState en Ax 2012
Multiselect de grid en Ax 2012
Crear lookup en clase dialog



Y por cierto, acuerdate de darle click a algún anuncio si el post te sirvio de algo.

No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma. 


lunes, 18 de mayo de 2015

Cómo leer una base de datos sdf desde Dynamics Ax 2012

Después de buscar un poco, al parecer en esta versión de ax es un poco complejo (por no decir que no se puede) leer una base de datos de un dispositivo móvil, en este caso una SQL Compact Edition o lo que es lo mismo SQL CE.

Así que la opción que aplique fue, crear un proyecto en visual studio, de tipo librería de clases y ahí hacer la conexión, la consulta de datos, la modificación o inserción de nuevos registros a la base de datos móvil, pero dejando toda la lógica en Ax.

Lo primero que debemos hacer es crear nuestro proyecto en visual studio y agregar la referencia de Sql Ce que generalmente se encuentra en la ruta:

C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v4.0\Desktop\System.Data.SqlServerCe.dll

En la clase del proyecto de vs, creamos un método que realice la conexión como el siguiente:
public DataTable ConsultaTodosLosActivos( string rutaBaseSdf)
        {
            var conn = new SqlCeConnection();

            // Leer la ruta del archivo sdf
            //Para la app normal seria: Data Source = |DataDirectory|\RedBeam\Asset Tracking\RBAsset.sdf
            conn.ConnectionString = "Data Source = 'C:\\temp\\RBAsset.sdf'; LCID= 1033; Case Sensitive=true";

            try
            {
                // Abrir base
                conn.Open();
                return LlenaDataTable(conn);
            }
            catch (Exception )
            {
                try
                {
                    //Como la base de datos esta en una versión anterior, se debe usar el método SqlCeEngine.Upgrade()
                    var engine = new SqlCeEngine(conn.ConnectionString);
                    engine.Upgrade(conn.ConnectionString);

                    conn.Open();
                    return LlenaDataTable(conn);
                }
                catch (Exception exInterno)
                {
                    conn.Close();
                    throw new InvalidOperationException(exInterno.Message);
                }
            }
        }

La línea de la ruta de conexión contiene al final:
var engine = new SqlCeEngine(conn.ConnectionString);
engine.Upgrade(conn.ConnectionString);

esto se refiere a que si la base de datos es un poco mas antigua que nuestro vs 2010 le hace un upgrade y nos permite leerla. Algo importante es que los dispositivos móviles, por default manejan las bases de datos en una ruta similar a esta: “Equipo\WindowsCE\\\Program Files\Aplicacion\Asset Tracking” entonces si tu ya tienes la ruta de donde vas a leer tu base de datos esta perfecto, sino puedes usar la anterior por default, claro cambiando el nombre “Aplicacion” por el que publique la aplicación.

Una vez que hicimos la conexión, llenamos un datatable que es el voy a regresar a ax para despues manipular los datos:
private DataTable LlenaDataTable( SqlCeConnection conexionBd)
        {
            var table = new DataTable();
            table.Columns.Add( "CodigoBarras" typeof ( string));
            table.Columns.Add( "Descripcion" typeof ( string));
            table.Columns.Add( "Serie" typeof ( string));
            table.Columns.Add( "Edificio" typeof ( string));
            table.Columns.Add( "ZonaEdificio" typeof ( string));
            table.Columns.Add( "Custodio" typeof ( string));
            table.Columns.Add( "NombreCustodio" typeof ( string));

            try
            {
                //Leer tablas
                using (SqlCeCommand com = new SqlCeCommand ("SELECT * FROM tblAssets INNER JOIN tblCustodians ON tblAssets.CustodianID = tblCustodians.CustodianID", conexionBd))
                {
                    SqlCeDataReader reader = com.ExecuteReader();
                    while (reader.Read())
                    {
                        table.Rows.Add(reader.GetString(0).Trim(), reader.GetString(1).Trim(), reader.GetString(2).Trim(), reader.GetString(3).Trim(), reader.GetString(4).Trim(), reader.GetString(10).Trim(), reader.GetString(12).Trim());
                    }
                }

                conexionBd.Close();
            }
            catch (Exception exInterno)
            {
                conexionBd.Close();
                throw new InvalidOperationException(exInterno.Message);
            }

            return table;

        }

Una vez que se tienen los métodos en .Net, se agrega el proyecto a AOT y se implementa (o se hace deploy, es lo mismo).

En Ax, para invocar la dll recién creada en vs, invocar el método y recibir esta tabla de .Net, haría algo como esto:

///Manda llamar la clase de .Net para leer la BD Sdf del dispositivo movil
public void bulkToAx( str _rutaBd)
{
    System.Data.DataRowCollection       dataRowCollection;
    System.Data.DataRow                 dataRow;
    int                                 i,totalRow;
    GRWActivosFijosSdf                  gRWActivosFijosSdf;

    System.Data.DataTable tablaNet = new System.Data.DataTable();
    GRWBdSdfToAx.GRWBdSdfToAxClass clase = new GRWBdSdfToAx.GRWBdSdfToAxClass();

    tablaNet = clase.ConsultaTodosLosActivos(_rutaBd);

    dataRowCollection       = tablaNet.get_Rows();
    totalRow                = dataRowCollection.get_Count();

    for(i = 0 ; i < totalRow; i ++)
    {
        dataRow = dataRowCollection.get_Item(i);

        //Los datos de .Net vienen: [0] CodigoBarras, [1] Descripcion, [2] Serie, [3] Edificio, [4] ZonaEdificio
        //[5] Custodio, [6] NombreCustodio
        gRWActivosFijosSdf.clear();
        gRWActivosFijosSdf.CodigoBarras     = dataRow.get_Item( 0 );
        gRWActivosFijosSdf.Descripcion      = dataRow.get_Item( 1 );
        gRWActivosFijosSdf.Serie            = dataRow.get_Item( 2 );
        gRWActivosFijosSdf.Edificio         = dataRow.get_Item( 3 );
        gRWActivosFijosSdf.ZonaEdificio     = dataRow.get_Item( 4 );
        gRWActivosFijosSdf.CodigoCustodio   = dataRow.get_Item( 5 );
        gRWActivosFijosSdf.NombreCustodio   = dataRow.get_Item( 6 );
        gRWActivosFijosSdf.insert();        
    }
}

Listo!!! así se lee una tabla de un dispositivo movil y se guarda la información en una tabla de ax.

Tip: Una vez que se implemento el proyecto de vs, en caso de no ver la dll por código (aunque si en el AOT), hay algunas cosas que es posible hacer, por ejemplo borrar los archivos AUC del archivo de cliente que generalmente estan la ruta:
C:\Users\ADMINMDX_DES\AppData\Local\Microsoft\Dynamics Ax


Post que también podrían ser de tu interés:
Capturar errores del infolog mediante código x++
Crear documentos asociados a un registro por código (DocuRef)
Teclas rápidas en Microsoft Dynamics Ax 2012


Y por cierto, acuérdate de darle click a algún anuncio si el post te sirvió de algo.


No olvides que te puedes unir a la página en Facebook Aprendiendo Dynamics Ax donde únicamente se tratan temas de desarrollo y se busca crear una comunidad de desarrollador@s de Ax en nuestro idioma.