Pages

Saturday, May 30, 2020

Using the product configurator in integration scenarios

Product configuration in D365FO must happen through the user interface, as the product configuration form is the only piece of code that communicates with the solver, wrapped in a dll outside D365FO's X++ codebase. The communication happens through the JavaScript of a designated form control. This is not great if you want to create a configuration in integration scenarios.

In AX 2012 R3 CU8 a class was introduced to allow you to pass a set of attributes and values for these, without using UI parts, and then get the solver to return the XML needed for processing in the backend engine. The class is named PCRuntimeSynchronousConfigurator and you can read a bit about it here.
Even though the solver dll basically is the same between AX 2012 and D365FO, this class didn't make it to D365FO. Well until now, where the class is included in 10.0.12.

So here is an example of how to generate configuration XML for the backend engine:
public static void main(Args _args)
{
    PCProductConfigurationModel productConfigurationModel = 
        PCProductConfigurationModel::findByName('High End Speaker (D0004)');

    str modelXML = productConfigurationModel.getXML();

    System.String values;
    values = '<Assignments>' +  
             '<Assignment xPath="CabinetFinish" value="Black"' +
             '<Assignment xPath="SpeakerHeight" value="12"' +
             '<Assignment xPath="FrontGrill" value="Metal"' +
             '<Assignment xPath="CornerProtection" value="true"' +
             '</Assignments>'; 

    PCRuntimeSynchronousConfigurator configurator = PCRuntimeSynchronousConfigurator::construct();
    configurator.parmSolverStrategy(productConfigurationModel.getSolverStrategy());
        
    Microsoft.Dynamics.Ax.Frameworks.Controls.ProductConfiguration.IsConfigurationComplete isConfigurationComplete;
        
    isConfigurationComplete = configurator.configure(modelXML, values);

    if (isConfigurationComplete == 
            Microsoft.Dynamics.Ax.Frameworks.Controls.ProductConfiguration.IsConfigurationComplete::Complete)
    {
        str configuredProductXML = configurator.getAllAssignedValues();
    }
}

Inside the class, the attributes are loaded this way:
    ...
    configuratordll.LoadAttributeValuesByXPath(values)
    ...

Of course you could also previously do what the "new" class does, but it would have been an unsupported and undocumented call to the solver dll and Microsoft could change the dll without any prior notice.

There are a couple of other ways to pass the attributes and values to the solver dll, but they are not supported as no standard X++ code uses these:
    ...
    configuratordll.AssignAttributeValueByXPath('CabinetFinish', 'Black'); 
    configuratordll.AssignAttributeValueByXPath('SpeakerHeight', '12');
    configuratordll.AssignAttributeValueByXPath('FrontGrill', 'Metal'); 
    configuratordll.AssignAttributeValueByXPath('CornerProtection', 'true');
    ...
And
    ...
    configuratordll.AssignAttributeValueById(2, 'Black');  // Cabinet finish
    configuratordll.AssignAttributeValueById(5, '14');     // Speaker height
    configuratordll.AssignAttributeValueById(3, 'Metal');  // Front grill
    configuratordll.AssignAttributeValueById(4, 'true');   // Corner protection
    ...

If you need to implement something like this, I encourage you to check out this flow diagram on docs:
https://docs.microsoft.com/en-us/dynamics365/supply-chain/pim/build-product-configuration-model#pcadaptor-class
It would be nice if more things were documented with flow diagrams like this.

Wednesday, March 11, 2020

Store your Remote Desktop connection files locally

Today we could experience yet an outtage on LCS, where LCS loses contact to the deployed environments. It took something like a days and a half before things were restored to normal operations.

This means that you can't see any environment details, download RDP files or perform any other environment actions from LCS.

The environments could be running, or you can start them from the Azure portal. But if you haven't stored correct credentials that doesn't get you very far with RDP.

To ensure I can continue development work during another outage likes this, I'll from now on be using a Remote Desktop manager for each of the environments I'm using. That allows me to have the RDP files locally incl. necessary credentials. I'm using the plain one from Microsoft: https://www.microsoft.com/en-us/download/details.aspx?id=44989.

The 2LCS tool allows you to easily export the RDP settings for an entire LCS project and add that to the manager.
2LCS is an open source, unsupported, tool maintained by Microsoft. You can get it from GitHub here: https://github.com/microsoft/2LCS.
The tool has several other nice features and is much faster to navigate in, compared to the sluggish LCS UI.

For the next outage, I'm prepared.

And for the record, a workaround to this type of issue could also be to add an additional administrator account to the machine from the Azure portal.


Wednesday, January 8, 2020

Label translations not showing in the label search dialog?

Microsoft is now adding translated label files to the deployed developer boxes, which is supposed to make is possible to search for labels in other languages than en-us. I'm not sure if this is done for all models though.

If the search doesn't work, the likely cause is that Microsoft didn't add the related XML file for the language under \AOSService\PackagesLocalDirectory\Package\Model\AxLabelFile.

You can add these manually Here is an example for the Danish SYS label file:


Now search is able to find the Danish labels: