Tuesday, May 18, 2021

Dynamics AX SSRS reports using SubReport

This can be tricky for sure. The most important point to be understood is that there has to be a parameter from the Main report that can be passed to the Subreport in the subreport Parameters.

From the main report design, you Right-click > Insert > Subreport.

Then you Right-click the Subreport to view Subreport Properties.

On the General tab, you must set the report that you want to use as the subreport. This should be in the format: Report.Design.

Here is an example:



The parameters tab is where the real magic happens.

First of all, you need three parameters that are standard for all (most?) ssrs reports. The "Name" column on this parameters screen should be thought of as the parameters from the Sub report. The "Value" column in this screen should be thought of as the parameters from the Main. The value parameters can be an actual parameter field or just a data field from your report. The Name will be the name of the parameter from the sub report. The Name drop-down will not be helpful to you. You will need to type in the name of the parameter to pass. The Value drop-down will also not be helpful to you. You can use the "fx" to build the expression. If you do this, you can choose the "Parameters" category and double click the parameter you want in the Values section:

Or you can choose a field from your dataset as the parameter for the report.

Or you can type them in the Values section of the Subreport properties screen like this:

Name                                        Value

AX_CompanyName                [@AX_CompanyName]
AX_UserContext                     [@AX_UserContext]
AX_ReportContext                 [@AX_ReportContext]

Then you need to pass the parameter(s) that the report needs for it to run. My report was passing the AccountNum. The customer account number in the main report had parameter "CustListReportDS_AccountNum." The customer account number in the subreport had parameter [@DataSet1_Customer_account], so my parameter looked like:

Name                                                            Value
CustListReportDS_AccountNum             [@DataSet1_Customer_account]

It will look like this when you are done:



Hope this helps!




Saturday, May 1, 2021

D365 - creating an externalItemId Lookup for Sales Orders, Purchase Orders and Sales Quotations

 For some reason, the external item field on these forms do not have lookups. If you want to set the external item manually, you would need a lookup on the field. Standard AX allows the user to type any string into the externalItemId field, it doesn't actually have to be in the external item table. We had a requirement to keep that functionality. If you wanted to limit the selection to only the items in the table you would need to add a relation on the salesLine, salesquotationline, and purchline tables to the CustVendExternalItem table and make sure validation is set to yes.

Doing this is not all that difficult. First you need to create a lookup on the custVendExternalItem table and then override the lookup on the form(s) you want to use it.

1. Here is the lookup code on the custVendExternalItem table

[ExtensionOf(tableStr(CustVendExternalItem))]
final class ModelCustVendExternalItem_Extension
{
    public static void modelLookupExternalItem(FormControl _formControl, CustVendRel _accountNum, ItemId _itemid)
    {
        Query query = new Query();
        QueryBuildDataSource qbds;
        QueryBuildRange qbr;

        SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(CustVendExternalItem),_formControl);

        sysTableLookup.addLookupfield(fieldNum(CustVendExternalItem, ExternalItemId),true);

        sysTableLookup.addLookupfield(fieldNum(CustVendExternalItem, ItemId));

        sysTableLookup.addLookupfield(fieldNum(CustVendExternalItem, CustVendRelation));


        qbds = query.addDataSource(tableNum(CustVendExternalItem));

        qbds.addRange(fieldNum(CustVendExternalItem, custvendrelation)).value(_accountNum);

        qbds.addRange(fieldNum(CustVendExternalItem, ItemId)).value(_itemid);

        sysTableLookup.parmQuery(query);

        sysTableLookup.performFormLookup();        

    }

}

2. Here is the code for the sales order form
[ExtensionOf(formStr(SalesTable))]
final class ModelSalesTableForm_Extension
{
    void init()
    {
        next init();

        Sales_ExternalItemId.registerOverrideMethod(methodStr(FormDataObject, lookup), formMethodStr(SalesTable, modelExternalItemLookup));
    }

    public void modelExternalItemLookup(FormStringControl _callingControl)
    {
        CustVendExternalItem::modelLookupExternalItem(_callingControl,SalesTable.CustAccount,SalesLine.itemId);
    }

}

3. The code for the purchase order form is very similar
[ExtensionOf(formStr(PurchTable))]
final class ModelPurchTableForm_Extension
{
    void init()
    {
        next init();

        PurchLine_ExternalItemId.registerOverrideMethod(methodStr(FormDataObject, lookup), formMethodStr(PurchTable, modelExternalItemLookup));
    }

    public void modelExternalItemLookup(FormStringControl _callingControl)
    {
        CustVendExternalItem::modelLookupExternalItem(_callingControl,PurchTable.OrderAccount,PurchLine.itemId);
    }

}

4. The code for the sales quotation form is also similar:

[ExtensionOf(formStr(SalesQuotationTable))]
final class modelSalesQuotationTableForm_Extension
{
    void init()
    {
        next init();

        Sales_ExternalItemId.registerOverrideMethod(methodStr(FormDataObject, lookup), formMethodStr(SalesQuotationTable, modelExternalItemLookup));
    }

    public void modelExternalItemLookup(FormStringControl _callingControl)
    {
        CustVendExternalItem::modelLookupExternalItem(_callingControl,SalesQuotationTable.custAccount,SalesQuotationLine.itemId);
    }

}