Monday, January 21, 2013

AX2012: Update Invent Registration from code


*** Update: 2013-2-4 ***
Credits go to Andy Adamak for spotting a problem with the code below.
This bit of code simply grabs the first InventTransOrigin record where the InventTransID's match, then grabs the FIRST record of the InventTrans table where it matches up with the origin... regardless of status. The issue I was running into was even if it was received/registered, whatever status, it would grab the first InventTrans and override the record and it's InventDim record as well.
So... It works, but not really because it totally messes up all your transactions if you receive more than once against the same PO line
------------------------------------------------------------------------------------------------------------------

Here's a job to update Invent Registration in AX2012. Feel free to try the following job in your testing/development environment.
static void DEV_InventTransRegistrationFromCode(Args _args)
{
    InventTransWMS_Register inventTransWMS_register;
    InventTrans             inventTrans = InventTrans::findTransId( "<inventTransId>");
    InventSerialId          id1 = "<serialId1>", id2 = "<serialId2>" ;
    TmpInventTransWMS       tmpInventTransWMS;
    InventDim               inventDim = inventTrans.inventDim();
   
    inventTransWMS_register = inventTransWMS_register::newStandard(tmpInventTransWMS);
   
    tmpInventTransWMS.clear();
    tmpInventTransWMS.initFromInventTrans(inventTrans);
    tmpInventTransWMS.InventQty = 1;
    inventDim.inventSerialId = id1;
    tmpInventTransWMS.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;
    tmpInventTransWMS.insert();
   
    inventTransWMS_register.writeTmpInventTransWMS(tmpInventTransWMS,
                                                   inventTrans,
                                                   inventTrans.inventDim());
   
    tmpInventTransWMS.clear();
    tmpInventTransWMS.initFromInventTrans(inventTrans);
    tmpInventTransWMS.InventQty = 1;
    inventDim.inventSerialId = id2;
    tmpInventTransWMS.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;
    tmpInventTransWMS.insert();
   
    inventTransWMS_register.writeTmpInventTransWMS(tmpInventTransWMS,
                                                   inventTrans,
                                                   inventTrans.inventDim());
   
    inventTransWMS_register.updateInvent(inventTrans);   
}

** The above is for interest only and comes with no warranties **

Tuesday, January 15, 2013

AX2012 Service: Customize dialog layout

When using AX services with data contract, all parameters are placed one by one and there is always a “Parameters” caption on top.
20130115_000523
This would look much nicer if I can place each check box to the right of their respective string input.

The way to customize the layout is not very obvious and I’ll show one way of doing it here.

1) First of all, create a new class which extends SysOperationAutomaticUIBuilder.
20130115_000525 

2) Override the postBuild() method and get a reference for each dialog field.
20130115_000526

3) After that, add code to modify the layout. (I put them in a separate method in this example.)
20130115_000527
Things to note:
- Create a new FormBuildGroupControl (subGroup) and set it’s hierarchyParent to “General”
- After that, build the rest of the form within “subGroup”
- Place the parameters fields to your desired place by modifying their hierarchyParent property.
- The order of assigning the controls affect their order of display, play with it to figure out how it works.

End result:
20130115_000528

** The above is for interest only and comes with no warranties **

Wednesday, January 09, 2013

Create financial dimension combination in AX2012 from code

I found this excellent post from Becky Newell about creating financial dimension combinations under X++.
===================
The first and best way to create dimension combinations is to use the class and method DimensionServiceProvider\buildDimensionStorageForLedgerAccount.  The buildDimensionStorageForLedgerAccount method takes a
LedgerAccountContract class.  In the LedgerAccountContract class there are two parm methods, parmMainAccount and parmValues.  The parmMainAccount method takes the MainAccount like ‘10060’ and the parmValues method takes a list of the other dimension values you want to set.  More specifically the parmValues method takes a list of classes.  The classes are of type DimensionAttributeValueContract.  On the DimensionAttributeValueContract class you set two
methods, parmName and parmValue.  For example, ‘Department’ for the name and ‘10’ for the value. Build up a list of DimensionAttributeValueContract classes for each dimension you want to specify and then pass the list to the parmValues method on the LedgerAccountContract class.  Once you have the LedgerAccountContract built up send it to the DimensionServiceProvider\buildDimensionStorageForLedgerAccount.

Optionally you can use a utility method in AX in AxdDimensionUtil\getLedgerAccountId.  This one is not as nice as buildDimensionStorageForLedgerAccount because it takes a container instead of a class (with known types).  Here’s an example of the method in AX:
container myContainer = ["110180-USAA", “110180”, 1, "Country", "USAA"];  //The third argument, 1, indicates the number of dimensions you are going to include, this does not include the main account.
AxdDimensionUtil::getLedgerAccountId(myContainer);
Here is another example constructing the contents of the
container with the dimensions included in the demo data

    // Construct input
    dimensionValueIn =
    [
        // Display value      
        strFmt('%1-%2-%3-%4', ‘10060’, '10’, ‘2020’, ‘M010’),
         // Main account
        ‘10060’,
         // Segment count
        3,
         // 2nd segment of 1st hierarchy
        ‘Department’, ‘10’,
        // 3rd segment of 1st hierarchy
        ‘Center’, ‘2020’,
         // 4th segment of 1st hierarchy
        ‘Purpose’, ‘M010’
    ];

Tuesday, January 08, 2013

Validate dialog input in Business Operation Framework

In AX2012, SysOperation framework replaces the old Runbase Batch framework. While working with it, I wasn’t able to found out how to add validation before closing the dialog. But Palle saves the day. Check out his full posting here.

=====================================
However the documentation from Microsoft in this area currently is not yet comprehensive, so here is my first article on a small area of the framework.
If you need to validate the input of the dialog for a data contract, you need to add code to the data contract. Your data contract must implement the SysOperationValidatable interface:

[DataContractAttribute]
public class BOFDataContractA implements SysOperationValidatable
{
int parmIntProperty;
str parmStrProperty;
}

And you need to add the validate method of the interface:

public boolean validate()
{
if (this.parmIntProperty() <= 25)
{
return checkFailed("The number must be higher than 25");
}
return true;
}