Buscar en este blog

miércoles, 1 de octubre de 2014

Crear lookup en formulario o en grid en Ax 2012

El siguiente ejemplo es para mostrarles cómo podemos agregar un lookup a una pantalla (formulario) en ax o también puede ser usado para un campo de un grid como se muestra en la imagen.


Esto se debe hacer en dos partes:
crear el método en la tabla principal que realice la consulta de los datos que queremos mostrar en el lookup
poner en el control (ya sea campo de formulario o campo de grid) la llamada al método que va a llenar los datos que queremos mostrar en el lookup

Paso 1. En mi caso, lo que necesito hacer es mostrar en el lookup todos los artículos que tienen un parámetro desactivado llamado GRWGenericProduct y a su vez necesito que esta lista de artículos que se consulte tenga como producto relacionado el articulo actual de mi tabla, entonces el método que consulta todos mis artículos es el siguiente:
public void lookupPurchItemNoGeneric(FormStringControl _ctrl)
{
    Query query = new Query();
    QueryBuildDataSource queryBuildDataSource;
    QueryBuildDataSource queryBuildDataSourceModule;
    QueryBuildRange queryBuildRange;
    QueryBuildRange queryBuildRangeModule;

    SysTableLookup sysTableLookup = SysTableLookup::newParameters( tableNum (InventTable), _ctrl);

    sysTableLookup.addLookupField( fieldNum (InventTable, ItemId), true);
    sysTableLookup.addLookupField( fieldNum (InventTable, NameAlias));
    sysTableLookup.addLookupField( fieldNum (InventTable, ItemType));

    queryBuildDataSource = query.addDataSource( tableNum (InventTable));

    queryBuildRange = queryBuildDataSource.addRange( fieldNum (InventTable, GRWGenericProduct));
    queryBuildRange.value(QueryValue(Noyes::No));

    queryBuildDataSourceModule = queryBuildDataSource.addDataSource(tableNum (InventTableModule));

    queryBuildRangeModule = queryBuildDataSourceModule.addRange( fieldNum (InventTableModule, GrwItemIdGeneric));
    queryBuildRangeModule.value(this.ItemId);

    queryBuildDataSourceModule.joinMode(JoinMode::ExistsJoin);
    queryBuildDataSourceModule.relations( true );

    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();

    //super();
}

Quiero aclarar que este método bien podría recibir algún parámetro para aplicar otro rango en mi filtro ademas del propio control que ya recibe como parámetro para sobreescribirle el lookup.

Paso 2. Sobreescribir o "Cancelar" el método lookup de nuestro control al que queremos mandarle los datos para el lookup.

En esta caso yo lo puse en el campo del datasource, bien puede ponerse directamente en el control, sobre el diseño del formulario.
Y este método debe llamar a nuestro método que llena los datos del lookup, osea el método que creamos arriba.
public void lookup(FormControl _formControl, str _filterStr)
{
    //super(_formControl, _filterStr);
    TmpPurchLine.lookupPurchItemNoGeneric(_formControl);
}

Aquí les dejo otro ejemplo un poco mas simple pero teniendo la misma funcionalidad, este jemplo funciona para un control normal y no uno que este dentro de un grid y que sea en base a otro valor.
Este es el método en la tabla que consulta los datos:
public client static void lookupTrackingDimension(FormStringControl _ctrl)
{
    SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum (EcoResTrackingDimensionGroup), _ctrl);
   
    Query query = new Query();
    QueryBuildDataSource qbds;
    ;
    sysTableLookup.addLookupfield( fieldNum(EcoResTrackingDimensionGroup, Name), true);
    sysTableLookup.addLookupfield( fieldNum(EcoResTrackingDimensionGroup, Description));
   
    qbds = query.addDataSource( tableNum(EcoResTrackingDimensionGroup));
   
    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}

Y este es el método que consulta esos datos para traerlos a mi control y llenarlo con los resultados del query que hace la consulta.
public void lookup()
{
    super();

    ISGR_RequestNewItemTabla::lookupTrackingDimension(this);
}


Por último, te invito a que te unas a la página de facebook recién creada para estar al día con las actualizaciones del blog y que podamos tener más comunicación. La meta? es hacer la comunidad de habla hispana mas grande sobre Dynamics Ax en cuestiones de desarrollo.


martes, 30 de septiembre de 2014

Leer un query mediante X++ en Dynamics Ax

Hola,
Esta vez, les voy a poner un fragmento de código para leer un query, en este caso, este código aplica tanto para Ax 2009 como para Ax 2012. Algunas veces cuando creamos un query en el AOT de Ax necesitamos varias cosas para validar que esta consultando la información que requerimos, por ejemplo:
  1. queremos ver algún campo o muchos campos específicos aplicando uno o mas filtros o rangos en distintos campos
  2. queremos ver la sentencia SQL que esta haciendo a la base de datos
  3. queremos ver toooooda la información que arroja la consulta en una tabla

Para cada uno de estos puntos tenemos soluciones.
Para comenzar, aquí nuestro query en el AOT


1. Queremos ver algún campo o muchos campos específicos aplicando uno o mas filtros o rangos en distintos campos; aquí el código en un job indicándole el nombre del query, el filtro que queremos y asignamos a nuestros buffer de las tablas el resultado.
static void grwQueryEtapa1(Args _args)
{   
    QueryBuildRange range;
   
    QueryRun queryRun;
    Counter recordsFound;
    GRWTransportTable gRWTransportTable;
    GRWTransportInput gRWTransportInput;
    ;
   // Indicamos el nombre del query
    queryRun = new QueryRun(queryStr (GRWTransportQuery));
    //Le indicamos que en dataSource numero 1, osea mi primera tabla del query, le queremos aplicar un filtro al campo Shipment
    range = queryRun.query().dataSourceNo( 1).addRange(fieldNum (GRWTransportTable, Shipment));
    range.value( "12345");

    //Con el promt se lanza el dialogo del query por si quisieramos poner mas filtros a mano, esto es opcional, podriamos evitar este if
    if(queryRun.prompt())
    {
        //Recorremos los resultados del query
        while(queryRun.next())
        {
            //Asignamos a cada buffer el resultado del query
            gRWTransportTable = queryRun.get( tableNum(GRWTransportTable));
            gRWTransportInput = queryRun.get( tableNum(GRWTransportInput));
           //Mostramos en pantalla el resultado
            info( strFmt("%1, %2, %3" ,gRWTransportTable.Shipment, gRWTransportTable.MaterialType, gRWTransportTable.MovementType));
            info( strFmt("%1, %2, %3" , gRWTransportInput.QualificationGeneral, gRWTransportInput.QualificationUnit, gRWTransportInput.AuthorizedDate));
            recordsFound++;
        }
    }
    //Mostramos el total de registros leidos
    info( strFmt("registros: %1" , recordsFound));
}

2. Queremos ver la sentencia SQL que esta haciendo a la base de datos
static void grwQueryEtapa1(Args _args)
{   
    QueryBuildRange range;
    QueryRun queryRun;    
    ;
   // Indicamos el nombre del query
    queryRun = new QueryRun(queryStr (GRWTransportQuery));
    //Le indicamos que en dataSource numero 1, osea mi primera tabla del query, le queremos aplicar un filtro al campo Shipment
    range = queryRun.query().dataSourceNo( 1).addRange(fieldNum (GRWTransportTable, RecId));
    range.value( "12345");

    
    //Mostramos la sentencia SQL
    info( strFmt("consulta: %1" , queryRun.query().toString()));
}



3. Queremos ver toooooda la información que arroja la consulta en una tabla; Creamos una vista arrastrando nuestro query al datasource de la vista y abrimos la vista como si fuera una tabla, ya sea con click derecho -> Abrir o posicicionandonos en el nombre de la vista y presionando Ctrl+O


Por último, te invito a que te unas a la página de facebook recién creada para estar al día con las actualizaciones del blog y que podamos tener más comunicación. La meta? es hacer la comunidad de habla hispana mas grande sobre Dynamics Ax en cuestiones de desarrollo.

lunes, 29 de septiembre de 2014

Listas y containers desde Ax 2012 para .Net mediante business connector (BC)

Aquí les dejo un ejemplo de código que trabaja con el business connector de Ax. En este caso quiero comunicar Ax 2012 R2 con una aplicación externa desarrollada en C# de .Net.
Lo que hago primero es consultar todos los valores de dimensiones en Ax enviando como parámetro el nombre de la dimensión financiera que estoy buscando y guardo esos valores en una lista, el problema surge cuando vas a leer en .Net, yo me encontré con la pregunta de qué usar, si listas o containers de ax, y en caso de usar uno u otro, cómo leerlo en .Net, así que abajo dejo el código para leer tanto containers como listas provenientes de Ax 2012 R2.

Método en Ax

static List getDimensionValuesFromAttribute(Name nameDimensionAttribute)
{
    DimensionAttribute          attribute;
    Common                      common;
    //container                   conValues;
    //int i = 1;
    List                        values = new List(Types::String);
    DimensionFinancialTag       finanacialTag;
    Query                       query;
    QueryRun                    queryRun;
    QueryBuildDataSource        qbDS;
    ;

    attribute = DimensionAttribute::findByName(nameDimensionAttribute);

    query = new Query();
    qbDS = query.addDataSource(attribute.BackingEntityType);
    qbDS.addSelectionField(attribute.ValueAttribute);
    qbDS.addSelectionField(attribute.NameAttribute);

    if(attribute.Type == DimensionAttributeType::CustomList)
    qbDS.addRange( fieldNum (DimensionFinancialTag, FinancialTagCategory)).value(SysQuery::value(attribute.financialTagCategory()));

    queryRun = new QueryRun(query);
    while(queryRun.next())
    {
        common = queryRun.get(attribute.BackingEntityType);
        //Si quisiera usar container
        //conIns(conValues, i, common.(attribute.ValueAttribute));
        //info(strFmt("valor en contenedor: %1, %2", i, conPeek(conValues, i)));
        //i += 1;

        //Usando Listas
        values.addEnd(common.(attribute.ValueAttribute));
    }

    return values;
}


El método en C# quedaría de la siguiente forma:

public List <InfoComboEntidad > ConsultaValoresDimension(string nombreDimensionAx)
        {
            InfoComboEntidad infoCombo = new InfoComboEntidad ();
            List< InfoComboEntidad> listaInfoCombo = new List <InfoComboEntidad >();
            Axapta ax = new Axapta();
            AxaptaObject axObjeto;
            AxaptaObject axObjetoParseado;
            //AxaptaContainer contenedor;

            try
            {
                // autenticación con ax
                ax.Logon( null, null, null, null);

                // Funciona si AX regresa un container
                //contenedor = (AxaptaContainer)ax.CallStaticClassMethod("GRWTools", "getDimensionValuesFromAttribute", "CostCenter");
                //for (int i = 1; i <= contenedor.Count; i++)
                //{
                //    string dato = contenedor.get_Item(1).ToString();
                //}

                // Funciona si AX regresa un List
                axObjeto = ax.CreateAxaptaObject( "Object");
                axObjeto = ( AxaptaObject)ax.CallStaticClassMethod("GRWTools" , "getDimensionValuesFromAttribute" , "CostCenter" );
                axObjetoParseado = ( AxaptaObject)axObjeto.Call("getEnumerator" );

                while ( Convert.ToBoolean(axObjetoParseado.Call( "moveNext")))
                {
                    infoCombo = new InfoComboEntidad();
                    infoCombo.Clave = axObjetoParseado.Call( "current").ToString();
                    infoCombo.Descripcion = axObjetoParseado.Call("current" ).ToString();
                    listaInfoCombo.Add(infoCombo);
                }               

                ax.Logoff();

                return listaInfoCombo;
            }
            catch ( Exception ex)
            {
                ax.Logoff();
                throw new Exception(ex.Message);
            }
        }



Por último, te invito a que te unas a la página de facebook recién creada para estar al día con las actualizaciones del blog y que podamos tener más comunicación. La meta? es hacer la comunidad de habla hispana mas grande sobre Dynamics Ax en cuestiones de desarrollo.


domingo, 28 de septiembre de 2014

Visualizar reporte SSRS en AX 2012 mediante código X++

Para visualizar un reporte SSRS creado en Ax 2012, tenemos dos opciones, una es mediante código como les voy a mostrar en el siguiente método y la otra es mediante un Menu Item que se ponga en un menu o en un formulario.

Casos:
1. SSRS basado en query y  sin clase controladora --> Crear MenuItem del tipo Output para el objeto del reporte SSRS ó por código como se muestra abajo.
2. SSRS RDP sin clase controladora --> mismo caso que el anterior.
3. SSRS basado en query y  con clase controladora  --> Crear MenuItem del tipo Output a la clase controladora.
4. SSRS RDP con clase controladora --> mismo caso que el anterior.

Entonces, en caso de no querer usar un menu item, también se puede hacer la llamada por código, aunque la práctica recomendable es usar menu items.

private void ssrsReporteView(RetailStoreId _idStore, date _startProcess)
{
    SrsReportRun srsReportRun;

    //Inicializando el reporte, en este caso mi reporte se llama GRWDepositReport y el diseño se llama Report
    srsReportRun = new SrsReportRun ("GRWDepositReport.Report" );
    srsReportRun.init();
    //Título del reporte que se visualiza en la ventana donde se abre (report viewer)
    srsReportRun.reportCaption( "Reporte de depósito");
    //Si tiene parámetros, se los paso igual por código
    srsReportRun.reportParameter( "DepositDS_IdStore").value(_idStore);
    srsReportRun.reportParameter( "DepositDS_DateStartProcess").value(_startProcess);
    //Le digo que no me presente el dialog de los parámetros, esto para que muestre el reporte directo al usuario
    srsReportRun.showDialog( false);

    if( srsReportRun )
    {
        //Aquí se ejecuta el reporte
        srsReportRun.executeReport();
    }
}

Finalmente, si buscamos imprimir el reporte directo a PDF, aquí el código.

private void ssrsReporteView(RetailStoreId _idStore, date _startProcess)
{
    SrsReportRun srsReportRun;

    //Inicializando el reporte, en este caso mi reporte se llama GRWDepositReport y el diseño se llama Report
    srsReportRun = new SrsReportRun ("GRWDepositReport.Report" );
    srsReportRun.init();
    //Si tiene parámetros, se los paso igual por código
    srsReportRun.reportParameter( "DepositDS_IdStore").value(_idStore);
    srsReportRun.reportParameter( "DepositDS_DateStartProcess").value(_startProcess);
    //Le digo que no me presente el dialog de los parámetros, esto para que muestre el reporte directo al usuario
    srsReportRun.showDialog( false);

    //Imprimir a un archivo PDF
    srsReportRun.printDestinationSettings().printMediumType(SRSPrintMediumType::File);
    srsReportRun.printDestinationSettings().fileFormat(SRSRepoFileFormar::PDF);
    srsReportRun.printDestinationSettings().overwriteFile(true);
    srsReportRun.printDestinationSettings().fileName(@"C:\ReporteDeposito.pdf");

    if( srsReportRun )
    {
        //Aquí se ejecuta el reporte
        srsReportRun.executeReport();
    }
}



Por último, te invito a que te unas a la página de facebook recién creada para estar al día con las actualizaciones del blog y que podamos tener más comunicación. La meta? es hacer la comunidad de habla hispana mas grande sobre Dynamics Ax en cuestiones de desarrollo.


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



<<    Anterior - Crear reportes RDP....                              Siguiente - Repetir encabezados....    >>



<<<<<     Indice de tutorial de Reportes SSRS....