jeudi 23 juin 2011

How to create a range in a datasource of a form according to a value of another field

Hi 
If you need to create a range in the init method of the datasource of your field but you want to apply it not to all records only for some according to the value of another field check this example and follow the links below ;)

public void init()
{
     Query                   query;
    BOM                     BOM;
    queryrun                qr;
    Qty                     qtySched;
    QueryBuildRange         queryBuildRange1, queryBuildRange2;
    ;

    super();
    if (  element.args().caller()  &&
          element.args().dataset() == tablenum(ProdTable))
    {
        qtySched = ProdTable::find(element.prodId()).QtySched;

        queryBuildRange1 = ProdBOM_ds.query().dataSourceTable(tablenum(ProdBOM)).addRange(fieldnum(ProdBOM,Thy_Package));
        queryBuildRange1.value(strfmt('(%1 == 0) || (%1 == 1) && (%2 <= %3)',fieldstr(ProdBOM, Thy_Package), fieldstr(ProdBOM, Thy_limitPackage), int2str(qtySched)));
    }

}


http://www.axaptapedia.com/Expressions_in_query_ranges

mercredi 22 juin 2011

How to Avoid Null values in Lookup

If you don't want to show Null Values in a lookup list
The below code avoid Null Values in Lookup.

public void lookup()
{
PurchTable purchTable;
SysTableLookup sysTableLookup = SysTableLookup::newParameters(tablenum(PurchTable), this);
Query query = new Query();
QueryBuildDataSource queryBuildDataSource = query.addDataSource(tablenum(PurchTable));
;
sysTableLookup.addLookupfield(fieldnum(PurchTable, PurchId));

queryBuildDataSource.addRange(fieldnum(PurchTable, PurchId)).value("000010..000020");
//To avoid the null values in Dynamic lookup
//queryBuildDataSource.addRange(fieldnum(Test_Vend,Name)).value(SysQuery::valueNotEmptyString());
//queryBuildDataSource.addRange(fieldnum(Test_Vend,Name)).value('!="" ');
sysTableLookup.parmQuery(query);
sysTableLookup.performFormLookup();
}

refresh, reread, research, executeQuery - which one to use?

Follow this link to get the answer :)
http://kashperuk.blogspot.com/2010/03/tutorial-reread-refresh-research.html

vendredi 10 juin 2011

How to add filter to the dataSource of a form

set a relation between a DataSource  and Table for example relation between VendTable and smmBusRelSectorTable in smmBusRelSectorTable Table , set the validate proprety to no. Add smmBusRelSectorTable to your the DataSource of your form and set the appropriate LinkType proprety for example : ExistJoin

then,in the prompt method of the VendTable dataSource of your form :

public void prompt()
{
    QueryBuildDataSource  qbds;

    QueryBuildDataSource  qbdsAdd;

    Query                   Query;

    queryrun                qr;

    ;

    query = new Query();

    qbds = query.addDataSource(tablenum(VendTable));

    qbdsAdd = qbds.addDataSource(tablenum(smmbusrelsectortable));

    qbdsAdd.relations(true);

    qr = new sysqueryrun(query);

    this.queryRun(qr);

    super();
}

Happy Daxing!

How to make a lookup from using two DataSources

For example you make two grids in your form having each one a dataSource 

in the init of your form :

void init()
{;

    super();

    this.setSelectMode();
}

int the  setSelectMode method of  your form

void setSelectMode()
{
    switch (ctrlTab.tab())
    {
        case 0,1:
            this.selectMode(EmplTable_EmplId);
            EmplTable_EmplId.setFocus();
            break;
        case 2:
            this.selectMode(Payroll_EmplId);
            Payroll_EmplId.setFocus();
            break;
    }
}

In the init method of your first dataSource 

void init()
{
    Query                   query = new Query();
    QueryBuildDataSource    queryBuildDataSource;
    QueryBuildRange         queryBuildRange;
    PayrollEmployee         payrollEmployee;
    PayrollEmplId           payrollEmplId;
    ;

    queryBuildDataSource = query.addDataSource(tablenum(EmplTable));

    queryBuildRange = queryBuildDataSource.addRange(fieldnum(EmplTable, EmplId));
    select emplId from emplTable notexists join payrollEmployee
     where emplTable.EmplId == payrollEmployee.EmplId;
    payrollEmplId = emplTable.EmplId;
    queryBuildRange.value(queryValue(payrollEmplId));

    this.query(query);
}

 In the executeQuery method of this dataSource

void executeQuery()
{
    PayrollEmployee             payrollEmployee;
    ;

     Select emplTable  notexists join payrollEmployee
      where emplTable.EmplId == payrollEmployee.EmplId;
}

In the second init method of your dataSource 

void init()
{
    Query   query = new Query();
    ;
    super();

    query.addDataSource(tablenum(EmplTable));

    this.query(query);
}

Here you can dowload the example of the lookup Form.

jeudi 9 juin 2011

How to enable or disable a field in a dataSource of a form

Instead of using the field name, it's better to use this functionality :

inventTable_ds.object(fieldnum(InventTable,ItemId)).allowedit(True);

check this link to see where to enable/disable form elements

http://patrikluca.blogspot.com/2009/02/x-code-snippet-disabling-form-elements.html

mardi 7 juin 2011

How to use multiple ranges in Dynamics AX

here is an example :)

void init()
{
    Query                   query = new Query();
    QueryBuildDataSource    qbds;
    QueryBuildRange         qbr;
    Str                     custAccount;
    ;
    super();

    qbds = query.addDataSource(tablenum(CustConfirmJour));
    qbds.addRange(fieldNum(CustConfirmJour, invoiceAccount)).value( element.args().parm());
    qbds.addRange(fieldNum(CustConfirmJour,thy_proformaId)).value(SysQuery::valueNotEmptyString());
    qbds.addRange(fieldNum(CustConfirmJour,thy_proformaIdUsed)).value(enum2str(Noyes::No));

    this.query(query);
}

lundi 6 juin 2011

How to get Language in Dynamics AX

If you need to get the Client language use this method :

companyinfo::languageId();

If you need to get the current user language try this :

    xInfo inf;
    ;
 
    inf = new xInfo();
    if( inf )
    {

        inf.language()
    }
Or  
info(infolog.language()); 
Good Daxing!

vendredi 3 juin 2011

How to use batch in Dynamics AX

To make a batch in Dynamics AX you need to use runBaseBatch extended class and use this class a menuItem of type Action for example you have a button that called this menuItem  and passes a parameters 

void clicked()
{
    Args            args;

    MenuFunction    menuFunction;
    ;

    args = new args();

    menuFunction = new Menufunction(identifierstr(Thy_ForUpdateItemBatch), MenuItemType::Action);

    args.parm( InventItemGroup.ItemGroupId );

    menuFunction.run(args);


    super();

}

You runBaseBatch extended class

See this attached class

You can the parameter passed to the menuItem Action in the initFromArgs method of the class.

void initFromArgs(Args _args)
{
    ;
    if(_args.parm())
    {
        groupId  = _args.parm();
    }
    else
    {
        error("@SYS22539");
    }

}


http://www.2shared.com/file/-eL_PJm6/Class_Thy_ForUpdateItemBatch.html


Happy Daxing !

How to pass parameter through SalesFormLetter Class

throughFor example, you want to pass parameter from SalesEditLines Form to SalesInvoice report, you need to pass through SalesFormLetter Class

Here is what you can do :

  in the method CloseOk of your SalesEditLines  Form, you get the value of a control
        salesFormLetter.Thy_ProformaId(Thy_ProformaIdTable_ProformaId.valueStr());

Here is the method  Thy_ProformaId in the SalesFormLetter Class

//<iba>
Thy_ProformaId thy_ProformaId(Thy_ProformaId _thy_ProformaId = thy_ProformaId)
{
    ;
    thy_ProformaId = _thy_ProformaId;
    return thy_ProformaId;
}
//</iba>
In the classDeclaration add  thy_ProformaId variable to the localMacro

 #LocalMACRO.CachedArgsList
        parmEnum,
        callerFormName,
        isProforma,
        formHasInterCompanyRefreshCacheMethod,
        parmSkipPrompt
    #ENDMACRO

You need also to initilize the variable in resetParmListCommonCS method like the other variable of localMacro

public void resetParmListCommonCS()
{
    ;
    salesTable          = null;
    editLinesChanged    = false;
    reArrangeNow        = false;
    initAllowEmptyTable = false;
    allowEmptyTable     = false;
    enableUpdateNow     = false;
    lockSalesUpdate     = false;
    createFromLines     = false;
    createFromHistory   = false;
    showQueryForm       = false;
    multiForm           = false;
    transDate           = dateNull();
    giroType            = 0;
    defaultGiroType     = NoYes::No;

    //<iba>
    thy_proformaId      = '';
    //</iba>
}

Finally in the init method ofthe salesInvoice report, get the value of thy_ProformaId method of SalesFormLetter Class in a variable declared in classDeclaration and use it in a display method to use it in your report

if (classidget(element.args().caller()) == classnum(SalesFormLetter_Invoice))
    {
        salesFormLetter = element.args().caller();

        if(! SalesformLetter.proforma()
           && ( SalesformLetter.documentStatus() == DocumentStatus::Invoice )
           && ( SalesformLetter.thy_ProformaId()))
        {
            thy_proformaId = salesFormLetter.thy_ProformaId();
            thy_ProformaId0.visible(true);
            thy_ProformaId0.showLabel(true);
        }
        else
        {
            thy_ProformaId0.showLabel(false);
            thy_ProformaId0.visible(false);
        }
    }

Happy Daxing ! 

jeudi 2 juin 2011

How to add a lookup form to a string edit control of a form

After creating your  form lookup, use this method in your string edit control to call it .

public void lookup()
{
    FormRun formRun;
    Args args;
    ;
   
    args = new Args("Thy_ProformaIdLookup");
    formRun = classFactory::formRunClassOnClient(args);
    args.parm(SalesParmSubTable.OrigSalesId);
    formRun.init();
    this.performFormLookup(formRun);
}

mercredi 1 juin 2011

How to use GlobalCache (alternative to GlobalVariables in X++)

Many times because of flawed implementation designs, we often need global variables. We may use a table with a key field and a container field for this purpose, but the simplest way of doing this will be using a Global Cache.
A global cache is an instance of class - SysGlobalCache, which is nothing but a Map containing Maps with Userid as Key. These Maps contain the actual value and a key.
In Ax, we have three(infact 4) Global Caches - Infolog.globalCache(), Appl.globalCache(), ClassFactory.GlobalCache().
How to use:

To Set a Value:

static void GlobalCacheSet(Args _args)
{
SysGlobalCache globalCache;
;
globalCache = ClassFactory.globalCache();
globalCache.set(curuserid(), 1, "One");


To Get the Value:

static void GlobalCacheGet(Args _args)
{
SysGlobalCache globalCache;
;
globalCache = ClassFactory.globalCache();
print globalCache.get(curuserid(), 1);
globalcache.remove(curuserid(), 1);
pause;
}

In the above the example, we can also use Infolog.globalCache() or Appl.globalCache().

Why do we have three Caches?

Its simple, the term "Caching" comes when there is something to do with Performance.

Infolog Object resides in Client and Application Object resides in Server.
To share your global variable across the network and accept the performance penalty of a client/server call, use the infolog variable (Info class) or appl variable (Application class) instead of ClassFactory.

ClassFactory is a special class, which has instances residing at both server and client. At run time, two instances of the ClassFactory class exist, and they share name classFactory. However confusing the implementation details might sound, this is a powerful concept. When you call a method on classFactory from code running on the client, you are calling the classFactory object on the client tier; when you call a method on classFactory from code running on the server, you are calling the classFactory object on the server tier. Remember this when debugging the ClassFactory class. 

How to add a range of value not null in a dataSource of a form

Here is the Key

this.query().dataSourceTable(tablenum(CustConfirmJour)).addRange(Fieldnum(CustConfirmJour,
thy_ProformaId)).value(sysquery::valueNotEmptyString());

It is better to add the range in the init method of the dataSource  because executequery is used after refresh,write, lots of events when you do it in init only one attempt you can target the bird.
In the executequery you disable the possibility that anyone can change it but in the init method, when you lock a range no body or action (refreshing or etc) can ruin your range
unless you dont use clearRanges() method of datasource for locking the range you can use status method of querybuildrange object.

qbr.status(RangeStatus::Locked);