Wednesday, June 27, 2018

The Product variants form can only be opened for a product master

When right-clicking > View Details on a Variant number you may receive the following message  "The Product variants form can only be opened for a product master."

Call Stack

[c]    \Data Dictionary\Tables\EcoResProductMaster\Methods\getProductMasterFromCaller   34
[c]    \Classes\EcoResProductVariantsCompanyHelper\newFromFormRun       18
[c]    \Classes\EcoResProductVariantsFormHelper\newFromFormRun             21
[c]    \Forms\EcoResProductVariantsPerCompany\Methods\productVariantsFormHelper 5
[c]    \Forms\EcoResProductVariantsPerCompany\Methods\init       3
[c]    \Classes\SysSetupFormRun\init                           5
[c]    \Classes\FormDataObject\jumpRef                                                                          
[c]    \Classes\FormStringControl\jumpRef                                                                       
[c]    \Classes\FormRun\Task                                                                                    
[c]    \Classes\SysSetupFormRun\Task                48
[c]    \Classes\FormStringControl\Context                                                                       


Problem

The method \Data Dictionary\Tables\EcoResProductMaster.getProductMasterFromCaller() handles EcoResDistinctProductVariant but not InventDimCombination.


Solution
Add the following code to \Data Dictionary\Tables\EcoResProductMaster.getProductMasterFromCaller()

    //coming from the Go to Main Table
    if (_args.lookupTable() == tableNum(InventDimCombination))
    {
        ecoResDistinctProductVariantCaller = EcoResDistinctProductVariant::find(InventDimCombination::findVariantId(_args.lookupValue()).DistinctProductVariant);
        callerRecord = EcoResProductMaster::find(ecoResDistinctProductVariantCaller.ProductMaster);
    }

Friday, June 8, 2018

Generating Random Numbers and Dates (AX 2012)

The Random class creates random integer values.  Although the range of an int (32 bit) is: [-2,147,483,647 : 2,147,483,647], Random.nextInt() generates values from 0 to 32,767, which is an unsigned 16-bit integer.  Let's run the Random class to validate the randomness.

The results of generating 1,048,574 random numbers represented as a histogram:




The RandomGenerate class enables you to specify a range for the random numbers.  Let's test RandomGenerate.randomInt() method.

Results of generating 1,048,574 random numbers between 0 and 3,000 represented as a histogram:


There is an interesting drop off close to the 3,000 mark.

Generating a random date

dateNull() is 1/1/1900 or 0 as an integer
dateMax() is 12/31/2154 or 93136 as an integer

12/30/2154 is 93135 as an integer, so dates are stored as the number of days since January first of 1900.  So we can generate a random date by generating numbers between 0 and 93,136.

Results of generating 1,048,574 random numbers between 0 and 3,000 represented as a histogram:


There isn't an obvious issue. :)  I checked and as far as I could tell it did not generate the same numbers over and over, and it can accept a seed:

  randomGenerate = RandomGenerate::construct();
  randomGenerate.parmSeed(new Random().nextInt());

Keep in mind that the compiler needs to you first assign the output of the function to an integer before casting it to a date:

  myInt = randomGen.randomInt(0, 93136);
  myDate = dateNull() + myInt;  // Convert to date

As long as you are not generating random numbers for cryptography, this implementation should satisfy the requirement.  As an alternative, call to the .NET class System.Random or another library.