Home

Sunday, June 26, 2016

Add Range in query ax 2012

static void AddRangeToQuery3Job(Args _args)
{
    Query q = new Query();  // Create a new query.
    QueryRun qr;
    CustTable ct;
    QueryBuildDataSource qbr1;
    str strTemp;
    ;

    // Add a single datasource.
    qbr1 = q.addDataSource(tablenum(CustTable));
    // Name the datasource 'Customer'.
    qbr1.name("Customer");

    // Create a range value that designates an "OR" query like:
    // customer.AccountNum == "4000" || Customer.CreditMax > 2500.

    // Add the range to the query data source.
    qbr1.addRange(fieldNum(CustTable, AccountNum)).value(
    strFmt('((%1.%2 == "US-012") || (%1.%3 > 100))',
        qbr1.name(),
        fieldStr(CustTable, AccountNum),
        fieldStr(CustTable, CreditMax)));

    // Print the data source.
    print qbr1.toString();
    info(qbr1.toString());

    // Run the query and print the results.
    qr = new QueryRun(q);

    while (qr.next())
    {
        if (qr.changedNo(1))
        {
            ct = qr.getNo(1);
            strTemp = strFmt("%1 , %2", ct.AccountNum, ct.CreditMax);
            //print strTemp;
            info(strTemp);
        }
    }
    pause;
}
================================================================
static void Job34(Args _args)
{

    Query q = new Query();  // Create a new query.
    QueryRun qr;
    InventTrans inventTrans;
    QueryBuildDataSource qbr1;
    str strTemp;
    ;

    // Add a single datasource.
    qbr1 = q.addDataSource(tablenum(InventTrans));
    // Name the datasource 'Customer'.
    qbr1.name("InventTrans");

    // Create a range value that designates an "OR" query like:
    // customer.AccountNum == "4000" || Customer.CreditMax > 2500.

    // Add the range to the query data source.
    qbr1.addRange(fieldNum(InventTrans, StatusReceipt)).value(
    strFmt('((%1 == %2 ") || (%1 == %3) ||  (%4 == %5)))',
        fieldStr(InventTrans, StatusReceipt),
        any2int(StatusReceipt::Purchased),
        any2int(StatusReceipt::Received),
        fieldStr(InventTrans, StatusIssue),
        any2int(StatusIssue::sold)));

    // Print the data source.
    print qbr1.toString();
    info(qbr1.toString());

    // Run the query and print the results.
    qr = new QueryRun(q);

    while (qr.next())
    {
        if (qr.changedNo(1))
        {
            inventTrans = qr.getNo(1);
            strTemp = strFmt("%1 , %2", inventTrans.ItemId, inventTrans.itemName());
            //print strTemp;
            info(strTemp);
        }
    }
    pause;
}
======================================================================
static void queryEmpDept(Args _args)

{
Query query;
QueryBuildDataSource queryBuildDataSource1,queryBuildDataSource2;
QueryBuildRange queryBuildRange;
QueryBuildLink queryBuildLink;
QueryRun queryRun;
CustTable deptTrainingTable;
CustTrans empTrainingTable;
;
// Create a new query object
query = new Query();
// Add the first data source to the query
queryBuildDataSource1 = query.addDataSource(tablenum(CustTable));
// Add the range to this first data source
queryBuildRange = queryBuildDataSource1.addRange(fieldnum(CustTable, AccountNum));
// Set the range
queryBuildRange.value("US-021");
// Add the second datasource to the first data source
queryBuildDataSource2 =queryBuildDataSource1.addDataSource(tablenum(CustTrans));
// Add the link from the child data source to the parent data
//source
queryBuildLink = queryBuildDataSource2.addLink(fieldnum(CustTable,AccountNum),fieldnum(CustTrans, OrderAccount));
// Create a new QueryRun object based on the query definition
queryRun = new QueryRun(query);
// Loop through all the records returned by the query
while (queryRun.next())
{
// Get the table data by using the get() method
deptTrainingTable = queryRun.get(tablenum(CustTable));
empTrainingTable = queryRun.get(tablenum(CustTrans));
info (strfmt("AccountNum %1,  Name %2, voucher Id %3, order Account %4 ", deptTrainingTable.AccountNum,deptTrainingTable.name(),empTrainingTable.voucher,empTrainingTable.AmountCur));
}
}

Friday, June 24, 2016

Form data source validateWrite

public boolean validateWrite()
{
    boolean ret;
    int q;
    int ascii;
    int i;
    q= strLen(Mobile.Phone);
    ret = super();
    if(Mobile.Phone)
    {
    for (i=1; i<=q; i++)
    {
    ascii = char2num(Mobile.Phone, i);
    if( ascii >= 48 && ascii <= 57)
    ret = true;
    else
    {
    ret = false;
    error('Phone Number must be numeric only');
    break;
    }
    }

    if(q!=10)
    {
    error('Phone Number must be of 10 digits');
    Mobile.Phone = "";
    Mobile.insert();
    }
    }

    return ret;
}

Thursday, June 23, 2016

AX 2012 - How to debug Code in Visual Studio


This post basically addresses how to debug code in Visual studio.
Most of code running on AOS runs in CIL environment, so it cannot be debugg in Microsoft Dynamics AX Debugger.
You might have confused/surprised why ax debugger is not opening inspite of  inserting breakpoint at particular place. It means code might be running in CIL and to debug visual studio 2010 is required.

Step1: 
Make sure AOS Service runs on account which you logged in. Right click on AOS Service and change log on property to logged in windows credentials.
Log off windows and then re log in.          

Step2:
Open visual studio and click on AX Application explorer (Shortcut Ctrl + D)
AOT opens and you can browse nodes as you used to do in Dynamics AX.
Open the object which you want to debug and insert breakpoint.

Step3:
Then in Visual studio, Click on Debug->Attach process

As shown in above image, First make sure two check boxes at bottom are marked.
Then only you can find and able to select AX32Serv.exe(AOS)  process and click on attach button.

Note : When you are doing this step 3 for first time it prompts you to Restart Visual studio, kindly select the same option.

Step4:
You done with setting up visual studio to debug code running in CIL.
Now restrart process in Dynamics AX which you want to debugg and you can find Visual studio debugger opened for you.
Continue debugging with hotkeys as you use to do in AX debugger like F10/F11.

Wednesday, June 22, 2016

FAQ: Microsoft Dynamics AX Kernel Hotfixes

Q1: What is a kernel hotfix?
A kernel hotfix updates the binary source files and other supporting files for all the AX components.

Kernel hotfixes are therefore also commonly referred to as binary hotfixes. Some examples of the files a kernel fix may update are the executable files (ax32.exe, ax32serv.exe) and assemblies (Microsoft.Dynamics.AX.*.dll). The installer will replace each file that needs patching with a newer version.

Q2: What is an application hotfix?
An application (X++) fix updates objects in the AOT.

It can make updates in the SYP, GLP, FPP & SLP layers (the layers reserved for Microsoft code). These changes are made in the AX model store in AX 2012 and later versions.

Q3: What are the major differences between these two types of fix?
A kernel fix is always cumulative.

Each, new kernel build contains every kernel fix previously published.

An application fix is NOT cumulative.

Application fixes will normally update just the objects that need fixing in order to resolve a specific issue. However, it may also need to update any dependencies (i.e. additional objects in the AOT that the “fixed”objects reference and that have also been fixed themselves).

The exception is a cumulative update or service pack, where both the kernel and application patches are cumulative.

Q4: What is the relationship between the application code and the kernel?
The AX kernel provides the underlying functionality that supports the execution of the application (X++) code.

The X++ application code is an interpreted language and the X++ interpreter is a part of the AX kernel. The kernel manages the resources used during the execution of X++ and performs garbage collection to clean up X++ objects and other resources that go out of scope.

The AX kernel is primarily programmed in C++ but also includes .NET assemblies. It is Microsoft-proprietary code and is not published externally, whereas the X++ source code is visible in the AOT.

The X++ programming language includes system classes, which are actually kernel classes (i.e. they are implemented in C++). For more information, refer to http://msdn.microsoft.com/en-us/library/aa853470.aspx

Q5: What is a hybrid fix?
A hybrid fix includes patches for both the kernel and application code.

It’s similar to a cumulative update/rollup except that the application part of a hybrid fix will target a specific issue and is therefore not cumulative. Another similarity with a cumulative update is that you can apply just the kernel or just the application update.

Hybrid fixes are released when changes in the application code reference new functionality in the kernel (or vice-versa). However, these references are implemented in such a way as to ensure that the application will still run normally when only the application or kernel portion of the fix is installed (see Q8 for more on this).

Q6: Do I need to update my customizations after applying a kernel hotfix?
No, you do not need to resolve code conflicts between the patched Microsoft code and custom application code.

It’s a common misconception that applying the kernel hotfix will cause conflicts with custom X++ code. This only applies to application fixes, which as mentioned above will update the X++ source code in the lower, Microsoft-owned layers and can therefore affect customizations in higher layers.

Q7: Do I need to test a kernel hotfix before I implement it in Production?
You should always follow your normal processes for testing changes to your Dynamics AX environment before introducing the kernel hotfix into Production.

Each fix is tested before release, but it doesn’t completely guarantee against the introduction of undesired behaviour in a customer’s environment; every environment is different with a unique combination of hardware, configuration settings, integrations and custom application code and it’s simply not possible to test every combination before the hotfix is published.

You should always take appropriate measures that minimize the risk of downtime and ensure your business critical functionality works as expected after the fix is applied.

For more information on how to implement a Dynamics AX hotfix, please refer to the following TechNet article:

http://technet.microsoft.com/en-us/library/hh335183.aspx

Q8: Is it supported to have a different kernel and application build?
YES, it is supported to have different builds for the application and the kernel BUT… they must be for the same version and service pack level.

Our Product Group ensure that dependencies between the application and kernel are not introduced when creating AX hotfixes. Dependencies between the application and kernel builds can only be introduced in a new product version and a new service pack (NOT in a rollup/cumulative update).

We also recommend having a kernel build that is the same or higher build than the application build. Applying a kernel update is normally a simpler process than updating the application code, so in the case of applying a cumulative update it makes sense to apply the kernel part of the update as well as the application part. This also ensures that you get the full benefit from any hybrid fixes, which as mentioned above require updates in both the kernel and application to function fully.

for more information Click here

Tuesday, June 21, 2016

Container in Ax 2012

public class daxTestJob
{
}

public static container test()
{
    container contTest;
    boolean dataInCont = true ;
     
    if (dataInCont)
    {
        contTest += 5;
        contTest += 6;
        contTest += -52;
        contTest += 'DAXDUDE';
    }

    return contTest;
}
public static void main(Args _args)
{
container cont;
 boolean data = true ;    
int i;
cont = daxTestJob::test();
info (strFmt("Length of the container: %1", conLen(cont)));
for (i=1; i <= conLen(cont); i++)
    {
        info (strFmt("container value %1 is %2", i, conPeek(cont, i)));
    }
}

Monday, June 20, 2016

THREE WAYS TO COUNT TIME IN DYNAMICS AX 2012

timeConsumed takes two arguments of int type and returns string in format X hours X minutes X seconds. It is particularly useful because we do not have to bother to format string it does it for us. One remark is that this method will return time over 24 hour intervals.

static void timeConsumedFcn(Args _args)
{
FromTime startTime;
int seconds = 5;
int i;
str elapsed;
;
startTime = timeNow();
i = sleep(seconds*1000);
elapsed = timeConsumed(startTime, timeNow());
info(strFmt(“Time elapsed: %1”, elapsed));
}
Another approach is to use WinApi class static method called getTickCount. It gives us greater precision than previous approach so that we can measure to milliseconds accuracy. Worth thing to notice here is that this method comes in two flavours, first is getTickCount which returns int and also getTickCount64 which returnsint64 as we will see in the comparison below this gives us greater accuracy.

static void winApiTickCount(Args _args)
{
int64 startTime, endTime;
int seconds = 5;
int i;
int64 elapsed;
;
startTime = WinAPI::getTickCount64();
i = sleep(seconds*1000);
endTime = WinAPI::getTickCount64();
elapsed = endTime – startTime;
info(strFmt(“Time elapsed: %1”, elapsed));
}
The third way is to use .Net class called Stopwatch. Microsoft Dynamics AX 2012 has a feature called .Net interop which allows us to access assemblies installed with .Net framework, through X++. This can be very useful, you can read more about this on msdn (https://msdn.microsoft.com/en-us/library/cc598160.aspx).
static void stopWatchdotNetInterop(Args _args)
{
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
int seconds = 5;
int i;
int64 elapsed;
;
stopwatch.Start();
i = sleep(seconds*1000);
stopwatch.Stop();
elapsed = stopwatch.get_ElapsedMilliseconds();
info(strFmt(“Time elapsed: %1”, elapsed));
}
Simple comparison between methods, evaluated for ten repetitions of above jobs:
 winApi64winApistopwatch
Mean5.00085.00755.0001
SD0.00060.00050.0003
*in seconds, mean (arithmetic mean), SD (standard deviation)
Conclusion:
By looking at the distance of mean value from the real value in our case 5s we can see that indeed winApi64(getTickCount64) is slightly more accurate than winApi(getTickCount), and stopwatch is even more accurate than winApi64.  For most of the cases WinAPI::getTickCount64 is accurate enough but if we want to achieve more accuracy we should use .Net interop.

difference between Kernel version and Application ax 2012

The Dynamics AX Kernel is the component executing the X++ Application code. So the Kernel version is the version of the executable (Client, Server, Business Connectors) while the Application version is the version of the Dynamics AX “Business Logic” - the X++ Application code, Forms, Repots – everything in the AOT.
You can check the current Application version in the Dynamics AX Client going to "Help - About Microsoft Dynamics AX".

timeConsumed()–a very useful function in Global class in AX 2012 [x++]

There is a very useful function timeConsumed() in Global class which we can use to calculate the time taken to execute business logic in AX 2012.
This function will return time consumed string in the form of XX hours XX minutes XX seconds (00:00:00). It handles up to a 24 hour time difference not dependent on start/end time. 

Limitation: If time consumed is greater then 24 hours will only report time over 24 hour intervals.
Code: 
static void DemoTimeConsumed(Args _args)
{
    FromTime startTime = timeNow();
    int i;
    str res;
    ;
   
    for (i = 1 ; i <= 500000; i++)
    {
        res+= int2str(i);     
    }
       
    info(strFmt("Total time consumed with this operation is  %1", timeConsumed(startTime, timeNow())));
}

Wednesday, June 15, 2016

DATA PARTITIONING IN MICROSOFT DYNAMICS AX 2012 R3

Microsoft Dynamics AX 2012 R2 enables data isolation by using data partitions. For example, an organization has several subsidiaries. If the management of the organization does not want employees of one subsidiary to have access to the data for other subsidiaries, data partitions can provide the boundaries that are required for data isolation.
Data partitions provide a logical separation of data in the Microsoft Dynamics AX database. To achieve this separation, Microsoft Dynamics AX adds a column to each table that contains data that must be isolated. This column contains a partition ID, which is the RecId of an entry in the Partitions table. In a partitioned table, rows that contain the same partition ID value belong to the same partition. The partition ID is also added to relevant indexes.

Partitions are defined in the Partitions form, where the system administrator creates the partition and provides a partition key. A partition key identifies a partition by using a unique string value that the system administrator specifies. Microsoft Dynamics AX displays the partition key in the title bar of the client application. Partitions can also be defined during installation and upgrade.


Scope of data isolation
It is important to understand that data partitions do not create separate installations of Microsoft Dynamics AX. Consider the following characteristics of partitioned systems:

  • Shared AOS – A partitioned system is created in the context of a single instance of Microsoft Dynamics AX Application Object Server (AOS) or an AOS cluster. When Microsoft Dynamics AX is first set up, the system creates a default partition. The partition key for the default partition is "initial". Additional partitions can be created during installation or upgrade, or at any time after the system is deployed. After a partition has been created, it cannot be deleted.
  • Shared database – In a partitioned system, all data is stored in the same database or database cluster. Partitions provide only logical data separation. No physical isolation of data occurs. Many system tables are shared tables that do not contain a column for the partition ID.
  • Shared AOT – A partitioned system has one Microsoft Dynamics AX Application Object Tree (AOT). Customizations are always shared across all partitions. The model store database is not partitioned. Metadata that describes objects in the AOT is shared. Custom code is shared across the system.
    By default, code runs in the context of the partition for the current session. This behavior resembles the behavior of X++, which handles companies by using thedataAreaId field. Therefore, pre-existing code that uses the X++ query mechanism works without modification. Direct SQL calls must be modified to filter on the context of the current partition.
    For more information about using data partitions in development projects, see Partitions, Companies, and Data Isolation in Microsoft Dynamics AXsee link
    The Microsoft Dynamics AX cross-reference system is shared. Role definitions are shared across the system. In Microsoft Dynamics AX 2012 R2 and later versions, multi-partition configurations have no new requirements to define or maintain reports.
  • Common administration – Users who have the system administrator role can access data in all partitions. However, to view data in a particular partition, the administrator must log on to a client instance for that partition.
    System administrators can create new partitions. Both system administrators and security administrators can manage users in the context of a partition.
    License keys and configuration keys are shared across the system.
  • Common application integration – In a partitioned system, Services and Application Integration Framework (AIF) is a shared subsystem. To guarantee that incoming requests are correctly isolated, you can restrict an inbound integration port to a particular partition. Additionally, you can specify a target partition for an incoming request by including the partition key in an XML element in the header of the document. Similarly, outbound responses indicate the source partition for the response data by including the partition key in the header.
    Because AIF uses a single gateway queue, a system administrator can view all documents in the queue, AIF history, or exceptions list in any partition. The forms that display these lists now have a field that shows the partition key for each document.
  • Common batch framework – Like AIF, the batch processing framework is a shared subsystem. One batch server is shared across partitions. However, each batch job is associated with a specific partition. The batch server executes batch jobs in the context of the correct partition. To view batch jobs or their history, you must log on to the partition that the batch jobs are associated with.
  • Separate application data – Access to application data is controlled by a combination of the partition ID and the user's role and permissions. The Microsoft Dynamics AX client does not let users view unified data across partitions. Microsoft Dynamics AX does not provide a query mechanism to retrieve and combine data from multiple partitions.
  • Separate organizational hierarchies – Each partition contains its own organizational hierarchy, which includes one or more legal entities. Like a new deployment of Microsoft Dynamics AX, each partition that is created contains the DAT company as a default legal entity. System administrators can add legal entities to each partition. Legal entities are never shared between partitions, even if the legal entities have the same name.
  • Separate user configurations – Each partition contains its own list of authorized users. The system administrator who created the partition is automatically created as a user who has the system administrator role in the new partition. After a system administrator logs on to a partition, he or she can add authorized users to the partition.
    A user can be authorized to access data in more than one partition. However, the user must be created and managed separately in each partition. This user must use a separate client configuration to start a separate client session for each partition. Each user is associated with a default partition. This default partition can be changed by a system administrator. A user who logs on to Microsoft Dynamics AX by using a default client configuration is logged on to the user's default partition.
    The Microsoft Dynamics AX client application displays the partition key for the current session in the title bar of the main window.
    User roles are assigned for each partition.

In Microsoft Dynamics AX 2012 there are many types of data elements such as the chart of accounts, products, party, exchange rates and more, which are shared across all legal entities in an AX environment. For some organizations, data needs to have a clear separation between entities whether for security, differences in shared data or other unique requirements. This is when Partitioning comes in to play. Available in Microsoft Dynamics AX R2 and higher, Partitioning is designed to provide a logical separation of data between legal entities to isolate the data.
Before Partitioning is configured, Microsoft Dynamics AX data would be structured as per the diagram in Figure 1. One single partition would exist that would contain data for all corporate divisions.
In the case of a company within the AX environment requiring complete isolation of their data they would use Partitioning. For example an organization with a division that does not use the same product list, or a division that should not share their contact list or employee list.
To partition data, follow these steps:
IMPORTANT NOTE: Once a data partition is created it cannot be deleted.
  1. Navigate to: System administration > Setup > Partitions
  2. Click ADD and create the required partition(s)
  1. Outside of AX create a new shortcut or menu item to enter Microsoft Dynamics AX. Using your existing desktop shortcut, copy and paste the shortcut but rename with the partition key for easier identification.


  1. Right click on the newly created icon, choose Properties. Modify the Target path by appending the following after AX32.exe: “-partition={partition name}”. In our case, our partition name is ‘PS’. This is what our shortcut looks like:
        "C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe" -partition=ps
After the partition is in place our data will now be logically separated as shown in Figure 2. Company 3 data is now isolated while Companies 1 and 2 are still sharing the original partition. Partitioning utilizes the same single database. Microsoft Dynamics AX is able to distinguish the data partitions using a key that is on shared data records.

Partitioning is not a requirement for all companies and should only be an option when the need to separate data exists. Remember a partition cannot be deleted, so review your requirements thoroughly before proceeding. The benefits of maintaining a single partition with data shared among legal entities provides management efficiencies for your IT department, creates a single party contact list for your marketing and communications, allows for intercompany transactions and shared product lists across the organization. Consider these factors should you look to move to a partitioned data set.
=========================================================================
Benefits
  • If an organization runs multiple business entities that shares the same business application, can Share IT infrastructure across independent businesses.
  • While sharing the IT infra, Organization achieves strict data isolation across businesses.
  • This reduces Total cost of ownership (TCO) for managing IT infrastructure.
Data partition basics
Below are some basic features of data partitions. The implementor should understand these before designing/preparing for data partitions.
Understanding Partion and Legal entitiy
Understanding Partition and Legal entity
  • Metadata (Business application)  is common across all partitions.
  • Enabling/disabling configuration key affects all partitions.
  • Named user licenses are calculated per principal, i.e. AD user, regardless of the number of partitions they have access to.
  • A default partition named Initial is always created for each AX instance.
  • DAT company exists in every partition. It is automatically created when a new partition is created.
  • A company with same name can exist in multiple partitions. Intercompany doesn’t work across partitions
  • AX users are defined per partition.
    • With in a partition a principal can be associated with one AX user.
    • Each user has a “default” partition associated with them, however a user can be authorized to access data in more than one partition.
    • AX user IDs other than admin and Guest are unique across partitions.
    • The principal that creates a new partition automatically becomes the admin user in the partition
    • Each partition contains at least one company or legal entity. A legal entity occurs in only one partition. When you create a legal entity, the system assigns it to the current partition. The legal entity can never be moved to another partition. However, its data can be exported from the partition and then imported to another company in another partition.
    Data Partition Structure
    Data Partition Structure
    • User to role assignment is per partition.
    • Organizations (e.g. departments, cost centers, etc.)  and hierarchies are defined within a partition.
    Data Abstraction Levels
    • User-Role-Organization assignment is per-partition.
    • Intended partition is specified at session creation time via client configuration.
    • If no partition is specified then the user’s default partition is chosen
  •  In a partitioned system, Services and Application Integration Framework (AIF) is a shared subsystem. To guarantee that incoming requests are correctly isolated, you can restrict an inbound integration port to a particular partition. Additionally, you can specify a target partition for an incoming request by including the partition key in an XML element in the header of the document. Similarly, outbound responses indicate the source partition for the response data by including the partition key in the header.   Because AIF uses a single gateway queue, a system administrator can view all documents in the queue, AIF history, or exceptions list in any partition. The forms that display these lists now have a field that shows the partition key for each document. for more info click
  • Like AIF, the batch processing framework is a shared subsystem. One batch server is shared across partitions. However, each batch job is associated with a specific partition. The batch server executes batch jobs in the context of the correct partition. To view batch jobs or their history, you must log on to the partition that the batch jobs are associated with.
  • Separate organizational hierarchies – Each partition contains its own organizational hierarchy, which includes one or more legal entities. Like a new deployment of Microsoft Dynamics AX, each partition that is created contains the DAT company as a default legal entity. System administrators can add legal entities to each partition. Legal entities are never shared between partitions, even if the legal entities have the same name.
Datapartition architecture
Recommendation
Implementation choice must be made carefully as the companies between two partitions cannot be merged and Intercompany features cannot be used. The only option is to use Data migration tool kit for data export import between partitions and AIF for inter company operations.
How it is implemented Technically?

  1. A partition Table is introduced. that keeps the list of partitions in the system.
  2. The partition key  is applied in all contexts as data area id used to apply, like all queries, forms etc.
  3. Every table in the system now has one more field named partition, that is nothing but the record id of the record created in the step one.
  4. Partition table implementation
  5. Cross company query doesn’t work across paritions
  6. Global function getcurrentpartitionrecid() introduced.

Change color on all forms

In the AOT, locate the SysSetupFormRun class and modify the run() method. After the super() method, you can add either snippet of code to change the color on all forms.

this.design().colorScheme(FormColorScheme::RGB);
//set background color to yellow
this.design().backgroundColor(0x63F2F2);
Or, if you would like to change it based on the current company account you are in, you can do something like this.

    switch (curext())
    {
        case "SAV1":
            this.design().backgroundColor(0x6E966B);  //green
            break;
        case "SAV2":
            this.design().backgroundColor(0x63F2F2);  //yellow
            break;
        case "SAV3":
            this.design().backgroundColor(0xA35D4D);  //blue
            break;
        case "SAV4":
            this.design().backgroundColor(0xA3838B);  //purple
            break;
        default:
            break;
    }

Muli Table Lookup ax 2012

public void lookup()
{
 
    Query                   query;
    QueryBuildDataSource    queryBuildDataSourceTable;
    QueryBuildDataSource    queryBuildDataSourceTableDescriptions;
    QueryBuildRange         queryBuildRange;
    //you need to define the multitable, but initalize it AFTER you have defined the query
    //SysTableLookup          sysTableLookup  = SysTableLookup::newParameters(tableNum(UnitOfMeasure), ctrl);
    SysMultiTableLookup sysTableLookup;
    query = new Query();
     super();
    queryBuildDataSourceTable = query.addDataSource(tableNum(VendTable));
    //join the translation table so we can get a description of the UOM
    queryBuildDataSourceTableDescriptions = queryBuildDataSourceTable.addDataSource(tableNum(DirPartyTable));
    queryBuildDataSourceTableDescriptions.joinMode(JoinMode::InnerJoin);
    queryBuildDataSourceTableDescriptions.relations(false);
    queryBuildDataSourceTableDescriptions.addLink(fieldNum(VendTable, Party),fieldNum(DirPartyTable, RecId));

    //filter by the unit class being passed
    queryBuildRange = queryBuildDataSourceTable.addRange(fieldNum(VendTable, Party));
    ///queryBuildRange.value(queryValue(unitClass));
    //define multiple table lookup query
    sysTableLookup  = SysMultiTableLookup::newParameters(this, query);
    //add which fields will be displayed to the user (symbol + desc.)
    sysTableLookup.addLookupfield(fieldNum(VendTable, AccountNum),1 );
    sysTableLookup.addLookupfield(fieldNum(DirPartyTable, Name),2,true);
    //do not use for multi table
    //sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}


==========================================================

public void lookup()
{
    Query                   query = new Query();
    QueryBuildDataSource    qbds;
    QueryBuildDataSource    qbdsJoin;
    SysTableLookup          sysTableLookup = sysTableLookup::newParameters(         tableNum(VendTable), this);
    ;

    qbds= query.addDataSource( tableNum(VendTable));
    qbdsJoin= qbds.addDataSource( tableNum(DirPartyTable));
    qbdsJoin.relations( false);
    qbdsJoin.fields().dynamic(NoYes::Yes);
    qbdsJoin.addLink( fieldNum(VendTable, Party), fieldNum(DirPartyTable, RecId));
    qbdsJoin.joinMode(JoinMode::InnerJoin);

    sysTableLookup.parmQuery(query);
    sysTableLookup.addLookupfield( fieldNum(VendTable, AccountNum), true);
    sysTableLookup.addLookupfield( fieldNum(VendTable, VendGroup), true);
    sysTableLookup.addLookupfield( fieldNum(VendTable, Party));
    sysTableLookup.performFormLookup();
}

Tuesday, June 14, 2016

Get current user name x++ AX 2012

when it is require to show current user name related with worker try below code in AX 2012.


static void getUserName(Args _args)
{
    info(strFmt('%1',curUserId()));
    
    info(strFmt('%1',HcmWorker::userId2Worker(curUserId())));
    
    info(HcmWorker::find(HcmWorker::userId2Worker(curUserId())).name());
}

Monday, June 13, 2016

How to create Query in AX 2012 through X ++ code


With the following job we can create and execute the query : 

Static void Querytest(Args _Args)
{
    Query query;
    QueryBuildDataSource queryBuildDataSource;
    QueryBuildDataSource queryBuildDataSource1;
    QueryBuildRange queryBuildRange;
    QueryRun  queryRun;
    CustTable custTable;
    DirPartyTable DirPartyTable;
    ;
    query=new query();      //Initialize Query
    queryBuildDataSource=query.addDataSource(tableNum(CustTable));   //Add Query
    queryBuildDataSource.addSortField(fieldNum(custTable,AccountNum),SortOrder::Descending); //Add sorting
    queryBuildRange=queryBuildDataSource.addRange(fieldNum(CustTable,AccountNum)); // Add Range
    queryBuildRange.value(queryValue('11')+('*')); // Add Query Value
    queryBuildRange=queryBuildDataSource.addRange(FieldNum(CustTable,AccountNum));
    queryBuildRange.value(queryValue('22')+('*'));
    
    //queryBuildDataSource1=queryBuildDataSource.addDataSource(tableNum(CustTrans)); //Add other Data Source for Joining
    //queryBuildDataSource1.relations(true);// Enable Relation
    // queryBuildDataSource1.joinMode(JoinMode::InnerJoin);//Define Join Mode
    
    queryRun= new QueryRun(query);   //Pass query to run it
    while(queryRun.next())
    {
        custTable=queryRun.get(tableNum(CustTable));
        print(strFmt("Customer Name, Account num and Currency are  %1 , %2 and %3",DirPartyTable::findRec(CustTable.Party).Name,CustTable.AccountNum,CustTable.Currency));
        pause;
    }

}