Tuesday, 4 September 2018

Custom SSRS report in the Print management section in Ax 2012 using X++

Requirement: 
To add the new custom SSRS report (in my case the report is calling the print management settings from SL, PL, customer and vendor) in the Print management section which can be access from Sales Ledger, Customer, Purchase Ledger, Vendors.

Path of Print management:
Sales Ledger: SalesLedger/Setup/Forms/Form setup/button: Print management
Purchase Ledger: Purchase ledger/Setup/Forms/Form setup/button: Print management
Customer: Sales ledger/Common/Customers/All customers/General tab/Set up group/ Print management
Vendor: Purchase ledger/Common/Vendors/All vendors/General tab/Set up group/ Print management.


Code changes:


Enum:
Add report name in the below Enums which you want to show on Print management setUp:
\Data Dictionary\Base Enums\PrintMgmtNodeType
\Data Dictionary\Base Enums\PrintMgmtDocumentType

Tables:

Add the following conditions at the bottom as shown below in the populate method of table PrintMgmtReportFormat
\Data Dictionary\Tables\PrintMgmtReportFormat\Methods\populate: 

addAX (PrintMgmtDocumentType::SalesAdvancePayment); 
addAX (PrintMgmtDocumentType::PurchAdvancePayment);
addAX (PrintMgmtDocumentType::LoadAdviceNote);
Here SalesAdvancePayment, PurchAdvancePayment and LoadAdviceNote are my SSRS report representatives on the print management setUp:
Here is an example:

Classes: Add the following changes in the below classes at the end of the methods.
PrintMgmtHierarchy_Purch:
Method: getNodesImplementation(): 
supportedNodes.addEnd(PrintMgmtNodeType::PurchAdvancePayme
supportedNodes.addEnd(PrintMgmtNodeType::LoadAdviceNote);
Method: getParentImplementation():
case PrintMgmtNodeType::PurchAdvancePayment:
// When no parent is present, return null
result.parmReferencedTableBuffer(null);
result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::PurchAdvancePayment));
break;

case PrintMgmtNodeType::LoadAdviceNote:
// When no parent is present, return null
result.parmReferencedTableBuffer(null);
result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::LoadAdviceNote));
break;

Similarly for Class: PrintMgmtHierarchy_Sales:
Methods:
\Classes\PrintMgmtHierarchy_Sales\getNodesImplementation
\Classes\PrintMgmtHierarchy_Sales\getParentImplementation

\Classes\PrintMgmtNode_CustTable: 
Methods: getDocumentTypes()
if (isConfigurationkeyEnabled(configurationKeyNum(LedgerBasic)))
{
docTypes.addEnd(PrintMgmtDocumentType::SalesAdvancePayment);
}
Similarly for these classes also:
\Classes\PrintMgmtNode_VendTable
if (isConfigurationkeyEnabled(configurationKeyNum(LedgerBasic)))
{
docTypes.addEnd(PrintMgmtDocumentType::PurchAdvancePayment);
docTypes.addEnd(PrintMgmtDocumentType::LoadAdviceNote);
}
\Classes\PrintMgmtNode_Purch:
Method: getDocumentTypes()
if (isConfigurationkeyEnabled(configurationKeyNum(LedgerBasic)))
{
docTypes.addEnd(PrintMgmtDocumentType::PurchAdvancePayment);
docTypes.addEnd(PrintMgmtDocumentType::LoadAdviceNote);
}
\Classes\PrintMgmtNode_Sales:
Method: getDocumentTypes()
if (isConfigurationkeyEnabled(configurationKeyNum(LedgerBasic)))
{
docTypes.addEnd(PrintMgmtDocumentType::SalesAdvancePayment);
}
\Classes\PrintMgmtNode:
Method: construct()
case PrintMgmtNodeType::SalesAdvancePayment:
return new PrintMgmtNode_Sales();
case PrintMgmtNodeType::PurchAdvancePayment:
return new PrintMgmtNode_Purch();
case PrintMgmtNodeType::LoadAdviceNote:
return new PrintMgmtNode_Purch();

Class: PrintMgmtDocType
\Classes\PrintMgmtDocType\getDefaultReportFormat
case PrintMgmtDocumentType::SalesAdvancePayment:
return ssrsReportStr(AdvSettlPayment, Report);
case PrintMgmtDocumentType::PurchAdvancePayment:
return ssrsReportStr(AdvSettlPayment, Report);
case PrintMgmtDocumentType::LoadAdviceNote:
return ssrsReportStr(AdvSettlPayment, Report);

\Classes\PrintMgmtDocType:
Methods: 
getDefaultReportFormat():
case PrintMgmtDocumentType::SalesAdvancePayment:
            return ssrsReportStr(AdvSettlPayment, Report);

        case PrintMgmtDocumentType::PurchAdvancePayment:
            return ssrsReportStr(AdvSettlPayment, Report);

        case PrintMgmtDocumentType::LoadAdviceNote:
            return ssrsReportStr(AdvSettlPayment, Report);

getQueryTableId():
case PrintMgmtDocumentType::SalesAdvancePayment:
tableId = tableNum(SalesTable);
break;
case PrintMgmtDocumentType::PurchAdvancePayment:
tableId = tableNum(PurchTable);
break;
case PrintMgmtDocumentType::LoadAdviceNote:
tableId = tableNum(CTMContractLoads);
break;

getQueryRangeFields()
case PrintMgmtDocumentType::SalesAdvancePayment:
fields.addEnd(fieldNum(SalesTable, InvoiceAccount));
fields.addEnd(fieldNum(SalesTable, SalesId));
break;
case PrintMgmtDocumentType::PurchAdvancePayment:
fields.addEnd(fieldNum(PurchTable, InvoiceAccount));
fields.addEnd(fieldNum(PurchTable, PurchId));
break;
case PrintMgmtDocumentType::LoadAdviceNote:
fields.addEnd(fieldNum(CTMContractLoads, LoadId));
break;
About controller class for your report:
Now extend your controller class with "SrsPrintMgmtController"

After all of the above set Up I am facing an issue that:
If I open the print management settings from “SalesLedger/Setup/Forms/Form setup/button: Print management” 
And do the setting here it’s working fine, my report is picking the print destination setting correctly from here.
But if I delete the settings from the above path and do the same setting from the other path which is “Sales ledger/Common/Customers/All customers/General tab/ SetUp/Print management button”
The report is not considering the print management settings here and running on screen only.

Solution for this will be:
You have to find the PrintMgmtSettings table based on its relation with the PrintMgmtDocInstance for the customer or vendor and then pass it's "PrintJobSettings" field value which is a container to the "SRSPrintDestinationSettings"
class.
You can find this code in the "runReport" method of my controller class below:

Controller class:
public class AdvSettlPaymentPrintController extends SrsPrintMgmtController
{
    int                         numOfOrders;
    AdvSettlPaymentContract     advSettlPaymentContract;
    CTMPaymentType              ctmpaymentType;
    List                        ordersToProcessList;
    UsePrintMgmt                advSettlPaymentUsePrintMgmt;
    SRSPrintDestinationSettings destnationSettings;

    #define.PurchAdvance('PurchAdvance')
    #define.PurchSettlement('PurchSettlement')
    #define.SalesAdvance('SalesAdvance')
    #define.SalesSettlement('SalesSettlement')
    #define.LoadAdviceNote('LoadAdviceNote')
}
public void getFromDialog()
{
    SrsReportDataContract   dataContract = this.parmReportContract();

    destnationSettings = dataContract.parmPrintSettings();

    super();
}

//This method will gives you the power if you don't want to run the print management settings and run normal report (Added a new Check box on the dialog "Use print management destination")


public UsePrintMgmt parmUsePrintMgmt(UsePrintMgmt _advSettlPaymentUsePrintMgmt = advSettlPaymentUsePrintMgmt)
{
    AdvSettlPaymentContract     advSettlPaymentContractLocal;
    SrsReportDataContract       dataContract = this.parmReportContract();

    advSettlPaymentContractLocal = dataContract.parmRdpContract();

    if (_advSettlPaymentUsePrintMgmt == advSettlPaymentContractLocal.parmAdvSettlPaymentUsePrintMgmt())
    {
        advSettlPaymentUsePrintMgmt = _advSettlPaymentUsePrintMgmt;
    }
//If the check box on the dialog is off then run "current print destination"
    else
    {
        advSettlPaymentUsePrintMgmt = advSettlPaymentContractLocal.parmAdvSettlPaymentUsePrintMgmt();
    }

    return advSettlPaymentUsePrintMgmt;
}

protected void preRunModifyContract()
{
    SrsReportDataContract           dataContract = this.parmReportContract();

    advSettlPaymentContract = dataContract.parmRdpContract();
    advSettlPaymentContract.callerPaymentType(this.parmPaymentType());
    advSettlPaymentContract.parmListofOrders(this.listOfOrders());
    advSettlPaymentContract.parmNumOfRecToProcess(this.parmNumofOrders());

    super();
}
//Construct the printMgmtReportRun class in the runPrintMgmt method based on the conditions.
protected void runPrintMgmt()
{
    if (ctmpaymentType == CTMPaymentType::SalesAdvance)
    {
         printMgmtReportRun = PrintMgmtReportRun::construct(PrintMgmtHierarchyType::Sales, PrintMgmtNodeType::SalesAdvancePayment, PrintMgmtDocumentType::SalesAdvancePayment);
    }
    else if (ctmpaymentType == CTMPaymentType::SalesSettlement)
    {
        printMgmtReportRun = PrintMgmtReportRun::construct(PrintMgmtHierarchyType::Sales, PrintMgmtNodeType::SalesAdvancePayment, PrintMgmtDocumentType::SalesAdvancePayment);
    }
    else if (ctmpaymentType == CTMPaymentType::PurchAdvance)
    {
        printMgmtReportRun = PrintMgmtReportRun::construct(PrintMgmtHierarchyType::Purch, PrintMgmtNodeType::PurchAdvancePayment, PrintMgmtDocumentType::PurchAdvancePayment);
    }
    else if (ctmpaymentType == CTMPaymentType::PurchSettlement)
    {
        printMgmtReportRun = PrintMgmtReportRun::construct(PrintMgmtHierarchyType::Purch, PrintMgmtNodeType::PurchAdvancePayment, PrintMgmtDocumentType::PurchAdvancePayment);
    }
    else if (ctmpaymentType == CTMPaymentType::LoadAdviceNote)
    {
        printMgmtReportRun = PrintMgmtReportRun::construct(PrintMgmtHierarchyType::Purch, PrintMgmtNodeType::LoadAdviceNote, PrintMgmtDocumentType::LoadAdviceNote);
    }
    printMgmtReportRun.parmReportRunController(this);

    printMgmtReportRun.load(this.parmArgs().record(), this.parmArgs().record(), Global::currentUserLanguage());

    this.outputReports();
}

//This method used to find the PrintMgmtSettings table value and pass it explicitely into SRSPrintDestinationSettings class if you need to pass the print management settings for a customer or vendor.
//I have added conditions like 
if Print management settings present on the Sales or Purchase Ledger, then use them, otherwise check for the print management settings for a customer or vendor and pass them.
public void runReport()
{
    SrsReportDataContract       dataContract = this.parmReportContract();
    SRSPrintDestinationSettings printDestinationSettings;
    PrintMgmtReportFormat       printMgmtReportFormat;
    PrintMgmtDocInstance        printMgmtDocInstanceCust;
    PrintMgmtDocInstance        printMgmtDocInstanceSales;
    PrintMgmtDocInstance        printMgmtDocInstancePurch;
    PrintMgmtDocInstance        printMgmtDocInstanceVend;
    PrintMgmtSettings           printMgmtSettings;
    PurchTable                  purchTable;
    SalesTable                  salesTable;
    CustTable                   custTable;
    VendTable                   vendTable;

    if (this.parmArgs().dataset() == tableNum(PurchTable))
    {
        purchTable = this.parmArgs().record();

        select firstOnly printMgmtDocInstancePurch
            where printMgmtDocInstancePurch.DocumentType  == PrintMgmtDocumentType::PurchAdvancePayment
            &&    printMgmtDocInstancePurch.NodeType      == PrintMgmtNodeType::Purch
            &&    printMgmtSettings.ParentId              == printMgmtDocInstancePurch.RecId
            &&    printMgmtSettings.Description           != "";

        if (!printMgmtDocInstancePurch.RecId)
        {
            // For Supplier print management settings
            printMgmtSettings.clear();

            select firstOnly DocumentType, ReferencedRecId, ReferencedTableId, RecId from printMgmtDocInstanceVend
                join  RecId, AccountNum from vendTable
                join PrintJobSettings from PrintMgmtSettings
                    where printMgmtDocInstanceVend.DocumentType         == PrintMgmtDocumentType::PurchAdvancePayment
                &&        printMgmtDocInstanceVend.ReferencedRecId      == vendTable.RecId
                &&        printMgmtDocInstanceVend.ReferencedTableId    == tableNum(vendTable)
                &&        vendTable.AccountNum                          == purchTable.OrderAccount
                &&        printMgmtSettings.ParentId                    == printMgmtDocInstanceVend.RecId
                &&        printMgmtSettings.Description                 != "";
        }
    }
    else if (this.parmArgs().dataset() == tableNum(salesTable))
    {
        salesTable = this.parmArgs().record();

        select firstOnly printMgmtDocInstanceSales
            join PrintJobSettings from PrintMgmtSettings
            where printMgmtDocInstanceSales.DocumentType  == PrintMgmtDocumentType::SalesAdvancePayment
            &&    printMgmtDocInstanceSales.NodeType      == PrintMgmtNodeType::Sales
            &&    printMgmtSettings.ParentId              == printMgmtDocInstanceSales.RecId
            &&    printMgmtSettings.Description           != "";

        if (!printMgmtDocInstanceSales.RecId)
        {
            printMgmtSettings.clear();
            // For customer print management settings
            select firstOnly DocumentType, ReferencedRecId, ReferencedTableId, RecId from printMgmtDocInstanceCust
                join  RecId, AccountNum from custTable
                join PrintJobSettings from PrintMgmtSettings
                    where printMgmtDocInstanceCust.DocumentType         == PrintMgmtDocumentType::SalesAdvancePayment
                &&        printMgmtDocInstanceCust.ReferencedRecId      == custTable.RecId
                &&        printMgmtDocInstanceCust.ReferencedTableId    == tableNum(custTable)
                &&        custTable.AccountNum                          == salesTable.CustAccount
                &&        printMgmtSettings.ParentId                    == printMgmtDocInstanceCust.RecId
                &&        printMgmtSettings.Description                 != "";
        }
    }
    if (PrintMgmtSettings.PrintJobSettings)
    {
        printDestinationSettings = new SRSPrintDestinationSettings(printMgmtSettings.PrintJobSettings);
        printDestinationSettings.overwriteFile(true);
        dataContract.parmPrintSettings(printDestinationSettings);
    }

    if (!advSettlPaymentUsePrintMgmt)
    {
        dataContract.parmPrintSettings(destnationSettings);
    }
    super();
}
Finally this is how it looks :
For Customer:

I hope this will be useful for someone.

Best Regards
Pranav

2 comments:

  1. https://shayanarshi.blogspot.com/2020/01/retrieving-report-name-set-in-print.html
    Just for Finding Report name

    ReplyDelete
  2. Found this blog helpful..... Thanks.

    ReplyDelete

Insert/Update or remove the default dimension value in D365 FSCM via x++

Use below method to insert/update the dimension values, just pass the parameter values to the method and it will return the updated value: p...