Showing posts with label AX Technical. Show all posts
Showing posts with label AX Technical. Show all posts

December 13, 2022

Validate financial dimension combination

Hi Folks, 

Often we need to create Journals via X++ code as part of customization or integration and dimension is always the tricky part of this. How to validate the dimension combination value as per rules set in the system. 

I am sharing a code sample to do the same, check this code and you may need to replace some dimension names or add/remove dimensions as per your requirement. The below code sample will validate

1. Main account 
2. Individual dimension value 
3. Deactivated dimension values
4. Dimension combination 




-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

August 05, 2022

Create Code extension in D365FO

Hi Folks, 

In case you missed this, Microsoft recently added one more option in Visual Studio to create an extension 'class' of any object (not as an object extension but an extension class to add code/new method).

Navigate to 'Application explorer' (aka AOT) and find your object, right click on this and you will find an option to 'Create code extension', if you select this, it will create a class with all syntax you need to create an extension of that object (i.e. final keyword, add 'ExtensionOf' at the top).


This action will create a class with the name 'ObjectName_Model_Extention' in your project with the below syntax, 









This is super quick to create an extension call for any applicable object. (Yeah you can not create an extension on an EDT using this option ;) )

Cheers!!! Happy Weekend. 

-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

July 24, 2022

[Solved] Debugger not working, Symbols not loaded

Hi Folks, 

In the recent Dev box where we are getting Visual Studio 19  for IDE, the debugger is not so friendly, it could be demanding to favor you  :) .

Let's see what are those demands, you may or may not need all those fixes. 

1. Uncheck  "Load Symbols Only For Items In The Solution". Go to Extension > Dynamics 365 > Option >


























2. Uncheck ‘Enable Just My Code’. Go to Extension > Dynamics 365 > Option
    


and Check the "Microsoft Symbol Server"



-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

July 22, 2021

QuickFix: Delete command button doesn't work as expected

Scenario: I've created a form with multiple data sources, one of the tab pages needs its own new, delete button. (Can not use design property). When adding command buttons for New and delete, New works fine but delete doesn't. 

Possible reason: There is a lot of commands which start with Delete, and probably you have chosen the 'Delete' command, while you need to choose 'Delete record' as this button spouse to delete a record (or multiple records). Try this.

-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

December 20, 2020

[Solved] Table browser not working

Hi Folks,

 Few days back I got a new dev box which was recently rolled out by one of a colleague.  All of a sudden it started behaving strangely. Whenever browsing a table I was getting below error.

 

Access Denied: You do not have sufficient permissions to open the menu item systablebrowser. Please contact your system administrator.

I double checked all the access, I got full admin access on this server but still same issue. This created more confusion when I was trying to run the debugger, I started getting below error. 

Access Denied: You do not have sufficient permissions to open the menu item sysclassrunner. Please contact your system administrator.

So to overcome this issue, double-check if the developer configuration key is enabled, in my case it was disabled and that was the root cause of these problems.

 


Now if you see the message on top of this form (Sysadmin > setup > License configuration) it is saying you cannot edit any record in the form until the server is in maintenance mode.

(See this link for how to enable maintenance mode in D365FO)

So first you need to enable maintenance mode on this server and then enable the development key.





Once than done, make sure you disable maintenance mode. And give it a try now, you should be able to browse a table. ( Also, the debugger is working fine as well 😊 )

Merry Christmas to all. Have a great holiday ahead.

-Harry 

Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

July 02, 2020

[Solved] Issue with data entity EcoResReleasedProductCreationV2Entity - Error executing code. The field with Id '0' does not exist in table 'InventTableModule

Hi Folks,

There are two data available in system EcoResReleasedProductV2Entity and EcoResReleasedProductCreationV2Entity with a similar appearance. Let’s first understand the use of each, To create release products in the system user has to use EcoResReleasedProductCreationV2Entity while updating release products user have to use EcoResReleasedProductV2Entity.

Now let's discuss the error which I was facing while using EcoResReleasedProductCreationV2Entity data entity to create release product. Below is the error message.

"Result: Error executing code. The field with Id '0' does not exist in table 'InventTableModule'. "

Now to fix this issue you need to install one hotfix in your system which is suggested by Microsoft. Go to your LCS project and search for KB4559650, 


now you have to install this KB on your machine. On successful deployment, you should be able to use this data entity to release product import.

Cheers!!!

-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

June 14, 2020

AppChecker in Dynamics 365 Finance and operations

Hi Folks,

 

You may have seen one checkbox for AppChecker while doing a model build or while creating deployable packages OR maybe somewhere else in this lockdown. :)

 

Have you ever wondered what this all about and why it can be useful in your project. Well this tool is another check to ensure that your custom code meets all MS best practice and it behaves kind of a gatekeeper to ensure your coding standards are met to avoid any further upgrade issue with #MSDyn365FO.

 

In other words (I mean using copy-paste ;)  it Allows you to get insights into what processes a particular application is performing, including stack traces and low level memory management data. It will complement Activity Tracking and will hopefully have its own dashboard in LCS where all of this data is overlaid for easy consumption.

 

You can get more details on AppChecker on below links

 

Application checker on GitHub

 

Biggest Takeaways From Microsoft BizApp Summit 2019

 

Enjoy home arrest for few more days..... No week or maybe another month.

Cheers!!!

Harry

 

-Harry Follow us on Facebook to keep in rhythm with us. https:fb.com/theaxapta

October 15, 2018

Table Event handler methods in Dynamics 365 FO

Hi Guys,

In my last post Form Event hander methods in Dynamics 365 FO, we discussed different event handlers which available on Form.  Let’s continue this discussion with Table event handler method today.
Let’s see the different type of event handler in today’s post.
You need to add a new class to write the event handler methods. I would recommend adding one class to one table. To make it easy for another developer postfix the name by EH or eventHander or Hander so your teammate can identify if they need to add more business logic than create a new class from scratch.

1. Table onValidateField event handler



2. Table OnValidated event hander (same logic you can try for many other event hander)
[DataEventHandler(tableStr(InventLocation), DataEventType::ValidatedField)]
public static void InventLocation_onValidatedField(Common sender, DataEventArgs e)
{
InventLocation inventLocation = sender as InventLocation;
ValidateFieldEventArgs fieldArgs = e;
boolean ret;
InventLocation inventLocationLoc;
switch(fieldArgs.parmFieldId())
{
case fieldNum(InventLocation, field1):
if(inventLocation.MyWorkerAssociate != '')
{
<Your code/ business ogic/validation>
<ret = true or false>
fieldArgs.parmValidateResult(ret);
}
}
}

Let me know if it helps you or you got some more example.

Cheers,
Harry
Follow us on Facebook to keep in rhythm with us. @Facebook

November 16, 2015

Use one table for creating multiple relation

Hi Folks,
After a long time I’m writing this new post.
Requirement: I need to use the single table to add multiple relation on a table. For eg. I have a parent table Table1 with field ItemId and ProcessItem. Now I need to add relation to InventTable to both fields. Hence I have to create two relation with InventTable.

How to do: Add two new relation in your table as shown below.

image
You might get an error message after this,
'RelatedTableRole' conflicts with another 'RelatedTableRole' on relation InventTable_Item on table ProcessedItemTable.
image
Solution to this error:
Set below two properties to each relation
1. UseDefaultRoleNames- set it to “NO”
2. Role: Give any logical name here, for eg. “Item”

image
image
Now compile your table, error must gone.
Write your any query/feedback in comment box and help us to improve. Thanks..!!!
-Harry

May 05, 2015

Error while Unit Testing [AX 2012 R3]

Hi All,
I was facing below error while running test cases for a customization. 


  • An internal error occurred in the remove operation in the SysTestRecordCleanUp#Context object cache.
  • A critical error has occurred in function SysTestRecordCleanUp::cleanUpContext.
  • An error has occurred. Contact your administrator for further assistance.

  • clip_image001 
    Solution: However i am not very much sure why this error was coming and what is the main reason for this, but I used below steps and its resolved this issue.
    1. Stop to AOS
    2. Delete AUC files from below path.
    3. Restart AOS.
    Try now, it should work fine.
    image
    -Harry

    March 27, 2015

    Auto Settlement of Sales Invoice in AX

    In an organization where thousands (or more) of sales transaction happening every day, and here is this auto settlement requirement comes in picture. Auto settlement process save a ton of time to manually settlement of each and every customer or record. There are three different ways to perform a auto settlement of the sales invoices.

    1. By Sales parameter select auto settlement.
    2. By select open transaction at the time of invoice posting
    3. Through X++ code

    1. By Sales parameter select auto settlement: Go to AR/Setup/Parameter under settlement tab you will found a check box for automatic settlement. Select this check box. And your system will auto settle your sales invoice.
    clip_image002

    This will settle a transaction whenever you post a payment journal.

    2. By select open transaction at the time of invoice posting: You can also choose the open transaction at the time of invoice journal creation. At the time of invoicing click on “open transaction settle” button, this will open a new form to select records to be settle from open transaction of that customer.


    clip_image004

    clip_image006

    3. Finally we have code as well (I love this part ;)): So here we are to do some tricky things. Yes, we can do the settlement by X++ code as well. Below code is an example in Job. You can use the same logic for any trigger point in AX.

    static void theAxapta_AutosettlePayment(Args _args)
    {
    CustTable custTable;
    CustTrans invCustTrans, payCustTrans;
    SpecTransManager manager;
    CustVendTransData custVendTransData;
    ;
    custTable = CustTable::find("504411");
    // Find the oldest unsettled invoice
    select firstonly invCustTrans
    order by TransDate asc
    where invCustTrans.AccountNum == custTable.AccountNum &&
    invCustTrans.TransType == LedgerTransType::Sales &&
    !invCustTrans.closed;
    // Find the oldest unsettled payment
    select firstonly payCustTrans
    order by TransDate asc
    where payCustTrans.AccountNum == custTable.AccountNum &&
    payCustTrans.TransType == LedgerTransType::Payment &&
    !payCustTrans.closed;
    ttsbegin;
    // Create an object of the CustVendTransData class with the invoice transaction as parameter
    custVendTransData = CustVendTransData::construct(invCustTrans);
    // Mark it for settlement
    custVendTransData.markForSettlement(CustTable);
    // Create an object of the CustVendTransData class with the payment transaction as parameter
    custVendTransData = CustVendTransData::construct(payCustTrans);
    //mark it for settlement
    custVendTransData.markForSettlement(CustTable);
    ttscommit;
    // Settle all marked transactions
    if(CustTrans::settleTransact(custTable, null, true,
    SettleDatePrinc::DaysDate, systemdateget()))
    info("Transactions settled");
    }

    Enjoy…..

    - Harry

    March 03, 2015

    The table WHSWorkLineCycleCount does not contain the method WHSWorkTable.

    Hi Folks,

    Today i just got this error message for "WHSWorkLineCycleCount" table.  while there is no changes in standard objects. Have a look on below case and share your suggestion and feedback as well. Here i am sharing my experience with the same.

    Compilation error:
    The table WHSWorkLineCycleCount does not contain the method WHSWorkTable.

    CIL Error:
    CIL generation: Warning: CIL could not be generated for X++ method WHSWorkTableForm.sourceButton_clicked due to X++ compile errors. This method throws an exception if run as CIL.

    Possible Reason:
    After the configuration key "Warehouse and Transportation management" is disabled, you will get above compilation and CIL error on standard AX 

    Solutions:
    1. Add one method in table WHSWorkLineCycleCount named WHSWorkTable
    To fix it on your environment, simply create a method with name whsWorkTable() on the WHSWorkLineCycleCount table, that returns the corresponding work based on the relation field 
    2. You can also try below hotfix:
    http://support2.microsoft.com/hotfix/KBHotfix.aspx?kbnum=3001197&kbln=en-in

    -Harry

    March 02, 2015

    Unable to save . This version of Menu FixedAssets belongs to a lower application object layer

    Error: Unable to save . This version of Menu FixedAssets belongs to a lower application object layer

    Solution:
    Clear your cache

    image

    Try to save now.

    -Harry

    February 18, 2015

    After upgrading my windows from 8 to 8.1, my dynamics ax is not working

    Hi Folks,

    Recently one of my collogue just update his OS from windows 8 to windows 8.1 and AX just stop working… :(  When he trying to start my AOS services its gives below error message

    clip_image001

    If you open event log you will found this error

    Object Server 01: The home directory for Axapta (C:\WINDOWS\system32\) does not match the required structure or can not be accessed. Please check installation, configuration and access rights.”

    AND

    “Object Server 01: The directory "C:\WINDOWS\system32\\bin" does not exist or access to it has been denied by the operating system.”

    AND

    “Object Server 01: Error accessing registry: Cannot open key SYSTEM\CurrentControlSet\Services\Dynamics Server\6.0\01. Error code: 0”

    Possible reason :
    Open AX server configuration from administrator tools. Here you would see it completely empty

    clip_image003

    clip_image005

    The problem is that registry keys located in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Dynamics Server\ were deleted during the update.

    clip_image006

    To resolve this issue You can create manually registry entry (That can be a difficult task if you are not friendly with windows registry editor), OR just reinstall the AOS and it will work.

    (To open registry editor open “RUN” enter “regedit” and hit enter)

    BUT…. At the end of the day its not recommended for PROD or LIVE server you can do this R&D only and only on your local or DEV environment.
    All the best guys…..

    -Harry

    January 09, 2015

    How to add new fields/Methods in Listpage from in AX 2012

    How to add new fields/Methods in List page from in AX 2012
    Here we use the Production Order list page for example
    Open Production order list page from below link
    Production control/Common/Production orders/All production orders
    clip_image002
    Now we need to add one new field “Serial Number” in this grid (Assuming there will be only one item in one Production order in every case).
    This serial number is available in “Transaction” from of this production order.
    Untitled
    Now to display new fields you can add a new display method in table and drag-drop this method in a grid as a field.
    Add one new method in “ProdTable” table add copy below code
    display InventSerialId inventTransInventSerialId()
    {
    InventTransOrigin InventTransOrigin;
    InventTrans InventTrans;
    ;
    select InventTrans join InventTransOrigin
    where InventTrans.InventTransOrigin == InventTransOrigin.RecId &&
    InventTrans.ItemId == InventTransOrigin.ItemId &&
    InventTransOrigin.ReferenceId == this.ProdId &&
    InventTransOrigin.ItemId == this.ItemId;
    return InventDim::find(InventTrans.inventDimId).inventSerialId;
    }
    Now set DataSource property of this new field as ProdTable. Save your from and compile for any error.
    Now open this from, here is your from
    clip_image008

    -Harry

    September 11, 2013

    How to use Complex Query Ranges in Dynamics AX

    Use of Complex Query Ranges in Dynamics AX

         1.  Adding a query with a datasource.


    query = new Query();
    dsInventTable = query.addDataSource(tableNum(InventTable));
    // Add our range
    queryBuildRange = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));

        2.  Simple criteria


    Lets find the record where the value of ItemId field is Item1. Take note of the single quotes and parenthesis surrounding the entire expression.

    queryBuildRange.value(strFmt('(ItemId == "%1")', queryValue("Item1")));
    Find records where the ItemType is Service. Note the use of any2int().
    queryBuildRange.value(strFmt('(ItemType == %1)', any2int(ItemType::Service)));


    Find records where the ItemType is Service or the ItemId is Item1. Note the nesting of the parenthesis in this example.

    queryBuildRange.value(strFmt('((ItemType == %1) || (ItemId == "%2"))', any2int(ItemType::Service), queryValue("Item1")));

    Find records where the modified date is after 1st January 2000. Note the use of Date2StrXpp() to format the date correctly.

    queryBuildRange.value(strFmt('(ModifiedDate > %1)', Date2StrXpp(01012000)));

        3.  Complex criteria with combined AND and OR clauses


    We need to find those records where the ItemType is Service, or both the ItemType is Item and the ProjCategoryId is Spares. This is not possible to achieve using the standard QueryRange syntax.


    queryBuildRange.value(strFmt('((%1 == %2) || ((%1 == %3) && (%4 == "%5")))',fieldStr(InventTable, ItemType),any2int(ItemType::Service),any2int(ItemType::Item),fieldStr(InventTable, ProjCategoryId),queryValue("Spares")));

    -Harry

    March 15, 2013

    Dynamics AX – Form lookups and how they work

    There are few different ways to achieve a lookup field on a form.
    1.     Create an Extended data type – EDT123




    2.     Create a table Table123
    3.     Add EDT123 to the table and the Description EDT field
    4.     Go back to the EDT and create a relation between table123.EDT123 and the EDT123
    5.     Automatically when the EDT field is added to another table lets say CustTable a lookup displaying the values from table123 will be displayed in the drop down.
    6.     Now let’s say you want to add the description field to the lookup as well. Add the description field to the AutoLookup field group on the table. Now the lookup will display EDT123 and the description field from table123.

    That is a simple way to create a lookup. Another way to create a lookup is to write a dynamic lookup on the table in which the data is coming from. This method will be a static method and will require the passing of arguments – typically the formstringcontrol that is to be the point of lookup. I prefer this method and use it often.

    This a very simple example of a static lookup from a table



    static void lookupTruckLoadIdEndingInv(FormStringControl  _ctrl)
    {
        SysTableLookup          sysTableLookup  = SysTableLookup::newParameters(tablenum(WfsRMTruckLoadStatus), _ctrl);
        Query                   query           = new Query();
        QueryBuildRange         qbr;
        ;
    
        query.addDataSource(tablenum(WfsRMTruckLoadStatus));
    
        sysTableLookup.addLookupfield(fieldnum(WfsRMTruckLoadStatus, truckLoadId ));
    
        query.dataSourceTable(tablenum(WfsRMTruckLoadStatus)).addRange(fieldnum(WfsRMTruckLoadStatus,retTransferred)).value(SysQuery::value(NoYes::No));
    
        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    }
    
    
    Joins can be peformed as well to pull back the desired data so you are not limited to querying on one table to return the proper data back to your lookup
    
    
    static void lookupSettledTruckLoadIdCashier(FormStringControl  _ctrl)
    {
        SysTableLookup          sysTableLookup  = SysTableLookup::newParameters(tablenum(WfsRMTruckLoadHeader), _ctrl);
        Query                   query           = new Query();
        QueryBuildRange         qbr;
        queryBuildDataSource    qbdsTruckLoadStatus,qbdsTruckLoadHeader,qbdsTenderSlipHeader;
        ;
    
        qbdsTruckLoadHeader = query.addDataSource(tablenum(WfsRMTruckLoadHeader));
    
        qbdsTruckLoadStatus         = qbdsTruckLoadHeader.addDataSource(tablenum(WfsRMTruckLoadStatus));
        qbdsTruckLoadStatus.relations(true);
    
        qbdsTruckLoadStatus.addRange(fieldnum(WfsRMTruckLoadStatus,settled)).value(enum2str(NoYes::No));
        qbdsTruckLoadStatus.addRange(fieldnum(WfsRMTruckLoadStatus,HHTruckLoadIdEnded)).value(enum2str(NoYes::Yes));
        qbdsTruckLoadStatus.addRange(fieldnum(WfsRMTruckLoadStatus,RetTransferred)).value(enum2str(NoYes::Yes));
    
        qbdsTenderSlipHeader         = qbdsTruckLoadStatus.addDataSource(tablenum(wfsRMTenderSlipHeader));
        //qbdsTenderSlipHeader.relations(true);
        qbdsTenderSlipHeader.addLink(fieldnum(WfsRMTruckLoadStatus, truckLoadId),fieldnum(wfsRMTenderSlipHeader, truckLoadId));
        qbdsTenderSlipHeader.joinMode(joinMode::NoExistsJoin);
    
        sysTableLookup.addLookupfield(fieldnum(WfsRMTruckLoadHeader, truckLoadId));
        sysTableLookup.addLookupfield(fieldnum(WfsRMTruckLoadHeader, routeId));
        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    }




    
    
    Another way is to create an actual form and call it in a method on the table. You will still need to pass in the formstringcontrol object but in this case you will be calling an actual existing form that you have created. Now why do this? Well one reason may be that you want to be able to filter on a specific field in the lookup that maybe you could not on a typical lookup or maybe you need to add a field to the lookup that would otherwise not be possible like you can add a display method to a lookup but maybe you want to see the field referenced in the display method and have the ability to sort on the field or filter on the field. For example, like DirPartyTable.Name. Sure, you can access it using a display method but maybe you want to see it in your lookup and be able to filter on it.
    So you will create a form and call it like a lookup so you can have all the the filtering of a standard form
    
    
    public client static void WfsRMlookupEmplIdCashier(Object _ctrl)
    {
        Args        args;
        FormRun     formRun;
        ;
    
        args = new Args();
        args.name(formstr(WfsRMEmplIdLookupCashier));
        args.caller(_ctrl);
        formRun = classfactory.formRunClass(args);
        formRun.init();
        _ctrl.performFormLookup(formRun);
    }
    
    
    The standard lookups present in AX like the item number lookup and the customer lookup are very interesting in that you only see one field on the relation but no fields in the autolookup. In these cases the lookup fields are coming from the standard indexes on the table. Take note of what you see in the itemId lookup when unchanged and then reference the indexes coincidence not really. this can apply to any new lookup you create as well.
    You can also override the lookup on the datasource - field of a form or an actual field string edit control on a form and perform a lookup
    Form design object
    
    
    public void lookup()
    {
    
        SysTableLookup        sysTableLookup;
        Query                 query=new Query();
        QueryBuildDataSource  qbds;
    
        ;
        sysTableLookup=SysTableLookup::newParameters(tablenum(Dimensions),this);
    
        sysTableLookup.addLookupfield(fieldnum(Dimensions,Num));
        sysTableLookup.addLookupfield(fieldnum(Dimensions,Description));
    
        qbds = query.addDataSource(tablenum(Dimensions));
    
        qbds.addRange(fieldnum(Dimensions, DimensionCode)).value(queryValue(COSAllowedDimensions::getAllowedDimensionValue(sysDim)));
    
        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    }
    //Lookup from a field on the form data source
    public void lookup(FormControl _formControl, str _filterStr)
    {
        Args    args;
        FormRun formRun;
        SysTableLookup      sysTableLookup = sysTableLookup::newParameters(tablenum(InventTable),_formControl);
        Query               query = new Query();
        QueryBuildDataSource     queryBuildDataSource;
        QueryBuildRange     queryBuildRange;
        ;
        sysTableLookup.addLookupfield(fieldnum(InventTable,ItemID));
        sysTableLookup.addLookupfield(fieldnum(InventTable,ItemName));
        sysTableLookup.addLookupfield(fieldnum(InventTable,ItemGroupID));
        sysTableLookup.addLookupfield(fieldnum(InventTable,NameAlias));
        sysTableLookup.addLookupfield(fieldnum(InventTable,ItemType));
        sysTableLookup.addLookupfield(fieldnum(InventTable,DimGroupID));
    
        queryBuildDataSource = query.addDataSource(tablenum(Inventtable));
        queryBuildRange = queryBuildDataSource.addRange(fieldnum(InventTable,ItemGroupID));
        //FGL, FGR, Returns
        queryBuildRange.value('xxx');
    
        queryBuildRange = queryBuildDataSource.addRange(fieldnum(InventTable,ItemGroupID));
        queryBuildRange.value('yyy');
    
        queryBuildRange = queryBuildDataSource.addRange(fieldnum(InventTable,ItemGroupID));
        queryBuildRange.value('Returns');
    
        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    
    }
    -Harry

    March 01, 2013

    Add multiple range and multiple table lookup

    Add multiple range and multiple table lookup





    public void lookup()
    {
    SysTableLookup tableLookup;
    QueryBuildRange rangeTransDate;
    QueryBuildRange vlgCode,ItemId,DistCode,talCode;
    QueryBuildRange CropId;
    QueryRun queryRun;
    QueryBuildDataSource qbds,qbds1,qbr,qbr1,qbr2;
    Query q = new Query();
    Query q1 = new Query();
    QueryBuildLink QueryBuildLink1,QueryBuildLink2;
    _TmpLookup _TmpLookup1;
    InventTable InventTable_1;
    boolean flg;
    ;
    tableLookup = SysTableLookup::newParameters(tableNum(_TableDetails),this);
    qbr = q.addDataSource(tableNum(_TableDetails));
    qbr2=qbr.addDataSource(tablenum(_Inspection1));
    qbr2.joinMode(Joinmode::NoExistsJoin);
    QueryBuildLink2 = qbr2.addLink(fieldnum(_TableDetails, _TableNo),fieldnum(_Inspection1,TableNo));
    // qbr2.addRange(fieldnum(_TableDetails,_TableNo)).value(queryNotValue(SysQuery::valueEmptyString()));
    qbr2.relations(true);
    if(tmpfilter.DistrictCode != "" )
    {
    qbr.addRange(fieldnum(_TableDetails,_DistrictCd)).value(queryValue(tmpfilter.DistrictCode));
    }
    if(tmpfilter.talCode != "" )
    {
    qbr.addRange(fieldnum(_TableDetails,_talCd)).value(queryValue(tmpfilter.talCode));
    }
    if( tmpfilter.vlgCode != "")
    {
    qbr.addRange(fieldnum(_TableDetails,_vlgCd)).value(queryValue(tmpfilter.vlgCode));
    }
    if(tmpfilter.ItemId != "")
    {
    qbr.addRange(fieldnum(_TableDetails,ItemId)).value(queryValue(tmpfilter.ItemId));
    }
    // qbr2.addRange(fieldnum(_TableDetails,_TableNo)).value(queryValue(''));
    //ss
    //ss
    // qbr.addRange(fieldnum(_TableDetails,_Area)).value(queryNotValue(0));
    //ss
    qbr1 = qbr.addDataSource(tablenum(_Table));
    qbr1.joinMode(Joinmode::InnerJoin);
    QueryBuildLink2 = qbr1.addLink(fieldnum(_TableDetails, RegId),fieldnum(_Table,RegId));
    qbr1.relations(true);
    if(enum2str(tmpfilter.Season) != "")
    {
    qbr1.addRange(fieldnum(_Table,_SeasonId)).value(queryValue(tmpfilter.Season));
    }
    if(tmpfilter.CustAccount != "")
    {
    qbr1.addRange(fieldnum(_Table,CustAccount)).value(queryValue(tmpfilter.CustAccount));
    }
    // qbr2.addRange(fieldnum(_TableDetails,_TableNo)).value(queryNotValue(""));
    //ss
    // qbr2.addRange(fieldnum(_TableDetails,_TableNo)).value(queryValue('090000004'));
    //info(_Inspection1.TableNo);
    //ss
    tableLookup.parmQuery(q);
    tableLookup.addLookupfield(fieldNum(_TableDetails,_TableNo));
    tableLookup.addLookupfield(fieldNum(_TableDetails, ItemId));
    tableLookup.addLookupfield(fieldNum(_TableDetails, ItemName));
    tableLookup.setLabel("Name");
    tableLookup.performFormLookup();
    }
    -Harry

    February 28, 2013

    Dynamics AX – Passing parameters between object – What is args??

    Hi Friends,

    ARGS is your friend in the world of AX (me also :) ). It allows you to pass records, the calling locations (form, report, query etc) , ENUMS and the list goes on!  
    Simple declaration of args

    Args  args = new Args();

    Now lets try passing args an record.

    select firstonly custTable where custTable.AccountNum == ‘XXXX’
    if(custTable)
    {
    args.record(custTable);
    }

    Now lets view a snippet of code that passes in a record and runs a report using the record passed in. 
    I- Create an instance of the report run class.
    Create a new Args instance to hold all of this information. 
    Pass the name of the report.
    Instantiate the report run object and call the init and and run methods of the report.

    II- Next override the init method of the report and put a condition that checks to see if a record was passed to the report from the args object. If so do not allow the user to be interactive with the report and sent the report straight to the screen.

    III- Set a report variable eHeader to the record that was passed to the report. If there is no calling record to the report meaning the report is being launched from a menu or elsewhere besides a place with a calling record then allow interaction of the report query for the users to select the range criteria they want to use.

    IV- Then override the fetch method and keep the super in place to allow the standard query to run however before the super use a condition to determine if a record has been passed into the report. If so then set a query of a key field to the a field from the record passed in.

    V- You can use args to do the same with forms as well
    You can pass in objects such as maps to run reports I have done this as well and I find it very helpful and useful
    
    
    void printPickList(wfsEMPickListHeader  wfsEMPickListHeader)
    {
        Args                    args = new args();
        ReportRun               reportRun;
        ;
    
        args.name(reportStr(wfsEMExportPickList));
        args.caller(this);
        args.record(wfsEMPickListHeader);
    
        reportRun = classfactory.reportRunClass(args);
        reportRun.init();
    
        reportRun.run();
    }
    
    
    public void init()
    {
        super();
        if(element.args().record())
        {
            this.report().interactive(false);
            this.query().interactive(false);
            this.printJobSettings().preferredTarget(PrintMedium::Screen);
            eHeader = element.args().record();
    
        }
        else
        {
            this.report().interactive(true);
            this.query().interactive(true);
        }
    }
    
    
    public boolean fetch()
    {
        boolean ret;
        if(element.args().record())
        {
            element.query().dataSourceTable(tablenum(wfsEMPickListHeader)).
           addRange(fieldnum(wfsEMPickListHeader,PickListId)).value(eHeader.PickListId);
        }
        ret = super();
    
        return ret;
    }
    
    
    void wfsRMRunManualTruckLoadIdForm()
    {
        wfsWhseUser    wfsWhseUser;
        FormRun        formRun;
        Args           args = new Args();
        boolean        ret = false;
        ;
        args.record(this);
        formRun = new MenuFunction(menuitemdisplaystr(wfsManualTruckLoadSelection),
        MenuItemType::Display).create(args);
        formRun.run();
        formRun.wait();
    }
    
    
    -Harry