Sunday, October 24, 2010

Using RunBaseBatchPrintable class

RunBase framework is used when we develop a class to run an operation within Dynamics AX, such as posting a sales order or used in any data manipulation operation. If we need to batch the operation, we will commonly use the RunBaseBatch framework by extending the RunBaseBatch class.
Dialog for a class that extends RunBaseBatch
The RunBaseBatch class does not provide the access to printer such as when running a report. If you need to provide the printer support to allow users to specify the printer options in the operation, you can extend the RunBaseBatchPrintable class instead of RunBasebatch class.
Dialog for a class that extends RunBaseBatchPrintable
When extending the RunBaseBatch class, you need to override the pack() and unpack() methods. If query is used in the operation, you may need to also override the initParmDefault(), queryRun(), and showQueryValues() methods.

When extending the RunBaseBatchPrintable class, in addition to the above methods, you would also need to make the following amendments:-
1) Modify the pack() to serialise the printJobSettings object (inherits from RunBaseBatchPrintable class)
public container pack()
{
    ;
    return [#CurrentVersion,
            #CurrentList,
            queryRun.pack(),
            printJobSettings.packPrintJobSettings()  // Serialise the printJobSettings object
           ];
}
2) Modify the unpack() to deserialise the printJobSettings object
public boolean unpack(container _packedClass)
{
    Version         version = RunBase::getVersion(_packedClass);
    container       packedQuery;
    container       packedPrintJobSettings;
    ;
    switch (version)
    {
        case #CurrentVersion:
            [version, #CurrentList, packedQuery, packedPrintJobSettings] = _packedClass;
            if (packedQuery)
            {
                queryRun = new QueryRun(packedQuery);
            }
            
            // Deserialise the printJobSettings object
            if (isSwappedFromServer)  
            {
                printJobSettings = SysPrintOptions::newPrintJobSettingsOnServer(packedPrintJobSettings);
            }
            else
            {
                printJobSettings = new PrintJobSettings(packedPrintJobSettings);
            }
            break;

        default:
            return false;
    }
    return true;
}
3) To retrieve the user-selected printer settings, you can use the printJobSettings variable directly in the code. For example:-
public void run()
{
    ;
    info(strfmt('Selected printer is %1', printJobSettings.printerPrinterName()));

    // pass the printJobSettings object to run a report based on the selected printer settings
    reportRun = classFactory.reportRunClass(args);
    reportRun.init();
    reportRun.printJobSettings(printJobSettings.packPrintJobSettings());
    reportRun.run();
}
Happy DAXing!!

Tuesday, October 19, 2010

Unable to submit workflow when non form root data source is used as workflow data source

If your workflow data source is NOT the form root data source, then when you submit the workflow you might encounter the following error:-
Wrong argument types in variable assignment.
The variable assignment error is due to different record is received by the SubmitToWorkflow class rather than the specified workflow record.

Although the WorkflowDatasource property in the form has been specified properly, the SubmitToWorkflow class will always use the form root data source as the workflow data source.
After debugging, I realised that the problem actually lies in the SysWorkflowFormControls class\ initControls() method. The line below
actionBarSubmitButton.dataSource(workflowDatasource.name());
is not working properly to assign the workflowDatasource to the workflow Submit button. Hence the Submit button treats its DataSource property is empty and use the root data source.

I created a quick test to add the SubmitToWorkflow menu item button manually to the form and use the above code to assign the data source. It was still not working.
Then I created another SubmitToWorkflow menu item button, but instead of using code, I specify the data source for the button using AOT Properties window. And this time the workflow was submitted.
So I can confirm that the MenuItemButton.dataSource() method did not do its job properly.

So what’s the workaround? If the DataSource property in MenuItemButton is empty, it will first use the DataSource specified in its parent container (i.e. Group control), and continue search upward till the DataSource specified in the form Design node. If no data source found, it will use the form root/first data source by default.
So to fix the workflow problem, we can use the above behaviour to implicitly assign the data source to the SubmitToWorkflow button. One way to do this is in the SysWorkflowFormControls class\ initControls(), add the below line
actionBarGroup.dataSource(workflowDatasource.name());
to assign the data source to group control that contains the button, which will then inherited by the button.