Buscar en este blog

martes, 29 de diciembre de 2015

Reportes SSRS en distintos idiomas en Dynamics Ax 2012

Cuando se trabaja con reportes en Ax, existe la posibilidad de que para clientes internacionales sea requerido que los documentos como facturas, remisiones o reportes personalizados se envíen en el idioma del cliente o proveedor, para este objetivo, Ax tiene en la configuración de clientes y proveedores una opción de idioma, que de acuerdo a la documentación oficial de Microsoft con solo cambiar el campo de idioma esto debería bastar para presentar facturas, remisiones y algunos otros reportes estándar en el idioma elegido, siempre y cuando existan las etiquetas del sistema.


Pero al parecer esto no funciona como debería, así que debemos hacer un ajuste para mandar el parámetro del idioma a nuestro reporte desde la clase controller.

En este ejemplo se ilustra el proceso para dos escenarios, un reporte estándar y un reporte personalizado.

Reporte personalizado

Si ya tenemos nuestro diseño de reporte creado en visual studio, necesitamos asegurarnos que usemos etiquetas de Ax que tengan traducción en los distintos idiomas que requerimos los reportes.

Por ejemplo, en Visual Studio, el campo debería tener algo como esto:


Y si buscamos ese identificador de etiqueta en Ax (MorphX, Herramientas > Etiquetas > Editor de etiquetas), podremos verificar en cada idioma qué es lo que se mostrara.



  

Ahora lo importante, en nuestra clase controller, debemos pasar el idioma en cuál queremos que se muestre el reporte, para este ejemplo, el idioma lo estoy tomando de la configuración del cliente, así que primero busco el idioma del cliente y después en el método preRunModifyContract, incluyo la línea:

this.parmReportContract().parmRdlContract().parmLanguageId(dirParty.parmLanguageId());


Con esto, el reporte cuando se lance, mostrará las etiquetas en el idioma que se haya seleccionado.


Reporte estándar

Para el caso de clientes, el campo "Idioma"  esta en la sección "General" del módulo  "Cuentas por cobrar > Común > Clientes", este campo va a indicar el idioma en que los documentos relacionados a ese cliente se van a mostrar. Para este caso, necesitamos que el idioma sea inglés solo para ese cliente.



En la clase controller de factura electrónica por ejemplo, tendríamos que agregar las líneas para buscar el idioma del cliente y posterior a eso, mandar en un método parm del contract, el idioma del cliente
 

Con este parámetro, cuando se ejecute el reporte de factura, Ax envía el idioma en el que se desea que se muestren las etiquetas, y de esta forma, todas las etiquetas que tengan traducción en el idioma seleccionado serán mostradas en el reporte.




Post relacionados:
Reportes SQL Reporting services (SSRS) en Microsoft Dynamics Ax 2012
Filtrar reportes en Dynamics Ax 2012 SSRS basado en query con un parámetro especifico
Reportes SSRS en Dynamics Ax 2012 basados en RDP (Report data provider)
Crear reportes SSRS usando RDP (Report Data Provider) con clase controladora en 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. 




domingo, 1 de noviembre de 2015

Saldo de cuenta contable por dimensión por código en Dynamics Ax 2012


Anteriormente había publicado cómo consultar el saldo de una cuenta que funciona tanto para cuentas normales como para totalizadoras, en esta ocasión el código a continuación sirve para calcular el saldo de una cuenta con una dimensión especifica hasta una fecha definida haciendo uso de la clase LedgerBalanceDimAttrValueAmounts.

El método requiere como parámetro la cuenta de la que se requiere el saldo, la dimensión que en este caso es una dimensión de sucursal y la fecha hasta donde se requiere el saldo.

private AmountMST saldoCuentaSucursalAx(str _cuenta,
                                           str _sucursal,
                                           date _fechaHasta)
{
       
    LedgerBalanceDimAttrValueAmounts        balance;
    MainAccountListPageBalanceParameters    balanceParaemeters;
    MainAccount                             mainAccount;
    DimensionAttributeValue                 dimensionAttributeValue;
    DimensionAttribute                      dimensionAttribute,
                                            dimensionAttributeSucursal;
       
    mainAccount = mainAccount::findByMainAccountId(_cuenta);
    balanceParaemeters = MainAccountListPageBalanceParameters::construct();
    balance = LedgerBalanceDimAttrValueAmounts::construct();
       
    dimensionAttribute = DimensionAttribute::findByName( "MainAccount");
    dimensionAttributeValue = dimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimensionAttribute.RecId, mainAccount.RecId);
       
    balance.parmAccountingDateRange(balanceParaemeters.getStartDate(), _fechaHasta);
    balance.parmPostingLayer(balanceParaemeters.getPostingLayer());
    balance.parmIncludeOpeningPeriod(balanceParaemeters.getIncludeOperatingPeriods());
    balance.parmIncludeRegularPeriod(balanceParaemeters.getIncludeOperatingPeriods());
    balance.parmIncludeClosingPeriod(balanceParaemeters.getIncludeClosingPeriods());
    balance.parmIncludeClosingPeriodBySystem(balanceParaemeters.getIncludeClosingPeriods());
       
    dimensionAttributeSucursal = DimensionAttribute::findByName( "Sucursal");
    balance.addDimAttrValue(dimensionAttributeSucursal.Recid, _sucursal);
    balance.calculateBalance(dimensionAttributeValue);
       
    return balance.getAccountingCurrencyBalance();
       

}



Post que podrían interesarte:
Saldo de cuenta contable
Saldo de cuenta contable por grupo de artículos


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. 

martes, 27 de octubre de 2015

Particiones en Dynamics Ax 2012 R2

Para dynamics Ax R2 y R3 existe un termino llamado particiones, estas particiones nos permiten compartir información entre empresas que pertenezcan a la misma partición y aislar estos datos del resto de las particiones.

Estas particiones a nivel usuario podemos verlas desde Administración del sistema > Configurar > Particiones.


Nosotros como desarrolladores, lo que debemos saber acerca de las particiones es que con una sentencia de consulta de datos sobre ax no podemos accesar a los datos de otra compañia que se encuentre en distinta partición aunque sea la misma instalación de Ax y la misma base de datos, si alguna vez necesitamos datos de distintas particiones esto debería realizarse por SQL. O si es necesario hacerlo desde ax, aquí un link de cómo realizar una consulta.

En Ax, cada clave y nombre de partición esta almacenada con un identificador. Este identificador es un campo llamado RecId en una tabla y que no es otra cosa que un Int64. Con este identificador Ax guarda el identificador de la partición en todos los registros de todas las tablas para saber a cuál partición pertenece el registro que se ha insertado en la tabla.

Una descripción gráfica de cómo es posible dividir las particiones se encuentra en el siguiente diagrama:

De acuerdo al diagrama, los usuarios de una compañia A tienen cierta configuración de acceso y no podrian entrar a la compañia Z una vez que ya iniciaron Ax. Aunque de otra forma, los usuarios de la compañia A comparten datos de los productos que se comercializan con la compañia B.

Si necesitas saber mas acerca de la arquitectura, link de Microsoft.


Post que podrían interesarte:
Menu de tutorial de desarrollo
Reportes SSRS en Ax



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, 22 de octubre de 2015

Actualizar información de direcciones en clientes por código X++ en Dynamics Ax 2012

En el post anterior les compartí un código para crear clientes ya sean personas o empresas con su dirección e información de contacto, aquí les comparto cómo actualizar estos datos. Espero les sea de utilidad.

static void JobActualizaClientePersona(Args _args)
{
    CustTable                    custTable;
    NumberSeq                    numberSeq;
    Name                         name = 'Jorge Lopez';
 
    DirParty                        dirParty;
    DirPartyPostalAddressView       dirPartyPostalAddressView;
    DirPartyContactInfoView         dirPartyContactInfo;
    ;
 
    ttsBegin;
 
   try
    {
        custTable = custTable::find( "C000020695"); 
       
        select dirPartyPostalAddressView
        where dirPartyPostalAddressView.Party == custtable.Party
        && dirPartyPostalAddressView.IsPrimary == NoYes::Yes;
       
        //DirParty
        //Crea instancia de la clase DirParty a partir de dirPartyPostalAddressView
        //Actualiza dirección principal
        DirParty = DirParty::constructFromPartyRecId(dirPartyPostalAddressView.Party);
 
        dirPartyPostalAddressView.LocationName      = 'Oficina central ';
        dirPartyPostalAddressView.City              = 'Polanco Chapultepec';
        dirPartyPostalAddressView.Street            = 'Presidente Masarik';
        dirPartyPostalAddressView.StreetNumber      = '25';
        dirPartyPostalAddressView.CountryRegionId   = 'MEX'; //necesita ser un país valido
        dirPartyPostalAddressView.State             = '09' //necesita ser un estado valido
 
        // Llena dirección
        dirParty.createOrUpdatePostalAddress(dirPartyPostalAddressView);
 
        //Actualiza email de información de contacto
        dirPartyContactInfo.clear();
       
        select dirPartyContactInfo
        where dirPartyContactInfo.Party == custtable.Party &&
        dirPartyContactInfo.Type == LogisticsElectronicAddressMethodType::Email;
       
        DirParty = DirParty::constructFromPartyRecId(dirPartyContactInfo.Party);
       
        dirPartyContactInfo.LocationName    = 'Email Jorge Lopez';
        dirPartyContactInfo.Locator         = 'jorge.lopez222@gmail.com';
        dirPartyContactInfo.Type            = LogisticsElectronicAddressMethodType::Email;
        dirPartyContactInfo.IsPrimary       = NoYes::Yes;
 
        dirParty.createOrUpdateContactInfo(dirPartyContactInfo);
       
        //Actualiza telefono de información de contacto
        dirPartyContactInfo.clear();
        select  dirPartyContactInfo
        where dirPartyContactInfo.Party == custtable.Party &&
        dirPartyContactInfo.Type == LogisticsElectronicAddressMethodType::Phone;
       
        DirParty = DirParty::constructFromPartyRecId(dirPartyContactInfo.Party);
       
        dirPartyContactInfo.LocationName    = 'Telefono Jorge';
        dirPartyContactInfo.Locator         = '551291165343';
        dirPartyContactInfo.Type            = LogisticsElectronicAddressMethodType::Phone;
        dirPartyContactInfo.IsPrimary       = NoYes::Yes;
 
        dirParty.createOrUpdateContactInfo(dirPartyContactInfo);
 
        ttsCommit;
       
        info( strFmt("Cliente creado: %1" , custTable.AccountNum));
    }
    catch(Exception::Error)
    {
       ttsAbort;
       throw Exception::Error;
    }

}




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. 

martes, 20 de octubre de 2015

Crear clientes y direcciones por código x++ en Microsoft Dynamics Ax 2012

Aquí cómo crear un cliente con su dirección y un registro de información de contacto como email, mediante código X++.

static void JobCreaClientePersona(Args _args)
{
    CustTable                    custTable;
    NumberSeq                    numberSeq;
    Name                         name = 'Jorge Lopez';
 
    DirParty                        dirParty;
    DirPartyPostalAddressView       dirPartyPostalAddressView;
    DirPartyContactInfoView         dirPartyContactInfo;
    ;
 
    ttsBegin;
    custTable.initValue();
 
   try
    {
       //crea datos del cliente en la CustTable
        numberSeq               = NumberSeq::newGetNum(CustParameters::numRefCustAccount());
        custTable.AccountNum    = numberSeq.num();
        custTable.CustGroup     = '02';
        custTable.Currency      = 'MXP';
        custTable.PaymTermId    = '00';
        custTable.PaymMode      = '01';
 
        //aquí se define si es persona u organización
        custTable.insert(DirPartyType::Person, name);  
 
        //DirParty
        //Crea instancia de la clase DirParty a partir de la entidad de CustTable
        dirParty = DirParty::constructFromCommon(custTable);
 
        dirPartyPostalAddressView.LocationName      = 'Oficina central ';
        dirPartyPostalAddressView.City              = 'Polanco';
        dirPartyPostalAddressView.Street            = 'Presidente Masarik';
        dirPartyPostalAddressView.StreetNumber      = '22';
        dirPartyPostalAddressView.CountryRegionId   = 'MEX'; //necesita ser un país valido
        dirPartyPostalAddressView.State             = '09' //necesita ser un estado valido
 
        // Llena dirección
        dirParty.createOrUpdatePostalAddress(dirPartyPostalAddressView);
 
        dirPartyContactInfo.LocationName    = 'Email Jorge Lopez';
        dirPartyContactInfo.Locator         = 'jorge.lopez222@gmail.com';
        dirPartyContactInfo.Type            = LogisticsElectronicAddressMethodType::Email;
        dirPartyContactInfo.IsPrimary       = NoYes::Yes;
 
        // Llena dirección de contacto
        dirParty.createOrUpdateContactInfo(dirPartyContactInfo);
 
        ttsCommit;
       
        info( strFmt("Cliente creado: %1" , custTable.AccountNum));
    }
    catch(Exception::Error)
    {
       ttsAbort;
       throw Exception::Error;
    }

}

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. 

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.