Microsoft Dynamics AX development

Goal: how to manage the printer settings for reports in AX 2012.

The following example is based on the new report Quality Orders in the Invent Module.

STEP 1

Create the SSRS Report

  • Report name:          InventQualityOrder
  • Contract name:       InventQualityOrderTableContract
  • Controller name:    InventQualityOrderTableController

STEP 2

Add new values to the BaseEnums:

  • PrintMgmtNodeType; add “QualityOrders”
  • PrintMgmtDocumentType; add “QualityOrders”

STEP 3

Create an extension of the PrintMgmtNode class:

public class PrintMgmtNode_QualityOrder extends PrintMgmtNode

public List getDocumentTypes()
{
    List docTypes = new List(Types::Enum);
 
    docTypes.addEnd(PrintMgmtDocumentType::QualityOrders);
 
    return docTypes;
}
 
public RefTableId getReferencedTableId()
{
    return tablenum(InventQualityOrderTable);
}

STEP 4

Modify the following classes:

PrintMgmtNode

1) Add the following code to the method “construct”:

case PrintMgmtNodeType::QualityOrdersWCH:
return new PrintMgmtNode_QualityOrderWCH();

A PrintMgmtNode class defines a level at which Print Management information can be associated.

PrintMgmtDocType

1) Method getDefaultReportFormat()

case PrintMgmtDocumentType::QualityOrders:
return ssrsReportStr(InventQualityOrder, Report);

2) Method getQueryRangeFields()

case PrintMgmtDocumentType::QualityOrders:
fields.addEnd(fieldNum(InventQualityOrderTable, QualityOrderId));
break;

3) Method getQueryTableId()

case PrintMgmtDocumentType::QualityOrders:
tableId = tableNum(InventQualityOrderTable);
break;

The PrintMgmtDocType class represents the document types that are available in print management.

PrintMgmtHierarchy_Invent

1) Method getNodesImplementation()

supportedNodes.addEnd(PrintMgmtNodeType::QualityOrders);

2) Method getParentImplementation()

case PrintMgmtNodeType::QualityOrders:
result.parmReferencedTableBuffer(null);
result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::Invent));
break;

PrintMgmtNode_Invent

1) Method getDocumentTypes()

docTypes.addEnd(PrintMgmtDocumentType::QualityOrders);

The PrintMgmtNode_Invent class is responsible for managing print management settings at the module level in the inventory module. Add the new document type in the method getDocumentTypes().

STEP 5

Create an extension of the FormLetterReport class:

class InventFormLetterReport_QualityOrder extends FormLetterReport
{
    InventTransType transType;
}
 
protected container getDefaultPrintJobSettings(PrintSetupOriginalCopy _printCopyOriginal)
{
    return new PrintJobSettings().packPrintJobSettings();
}
 
protected PrintMgmtDocumentType getPrintMgmtDocumentType()
{
    return PrintMgmtDocumentType::QualityOrders;
}
 
protected PrintMgmtHierarchyType getPrintMgmtHierarchyType()
{
    return PrintMgmtHierarchyType::Invent;
}
 
protected PrintMgmtNodeType getPrintMgmtNodeType()
{
    return PrintMgmtNodeType::QualityOrders;
}

STEP 6

Modify the FormLetterReport class:

1) Method construct()  

case PrintMgmtDocumentType::QualityOrders:
return new InventFormLetterReport_QualityOrder();

The FormLetterReport class controls the printing of documents.

STEP 7

Create the controller, which extends the TradeDocumentReportController class, which allows to manage multiple prints.

The following dialog aims to provide the possibility to choose printer settings that are different from the ones defined in the standard configuration (Inventory and warehouse management > Setup > Inventory and warehouse management parameters > Print management):

The dialog offers two scenarios:

– “Use print management destination” is flagged – in this case the system takes the settings from Inventory and warehouse management parameters

– Otherwise, the system takes the printer settings from the dialog (“Current print destination”).

In any case, it is necessary to overwrite the following methods in the controller:

initFormLetterReport()

protected void initFormLetterReport()
{
    printCopyOriginal = this.parmArgs().parmEnum();
 
    this.initializeJournalLists(this.parmArgs());
 
    formLetterReport = FormLetterReport::construct(PrintMgmtDocumentType::QualityOrders);
 
    formLetterReport.parmPrintType(printCopyOriginal);
 
    if (printCopyOriginal == PrintCopyOriginal::OriginalPrint)
    {
        // Always use the print mgmt destinations when reprinting for the OriginalPrint case.
        formLetterReport.parmUsePrintMgmtDestinations(true);
    }  
 
    super();
}

output()

This method is called from the runPrintManagement method, for every selected journal.

protected void output()
{
    InventQualityOrderTableContractWCH rdpContract = this.parmReportContract().parmRdpContract() as InventQualityOrderTableContractWCH;
 
    //If the flag is not set, I set the current print destination in case of original/copy printing
    if (!rdpContract.parmUsePrintManagementSettings())
    {
        formLetterReport.parmDefaultCopyPrintJobSettings(this.parmReportContract().parmPrintSettings()); formLetterReport.parmDefaultOriginalPrintJobSettings(this.parmReportContract().parmPrintSettings());
       formLetterReport.parmUsePrintMgmtDestinations(false);
    }
 
   // load the new setup for printing the report
   formLetterReport.loadPrintSettings(inventQualityOrderTable, inventQualityOrderTable, CompanyInfo::languageId());
   this.parmReportContract().parmRdlContract().parmLanguageId(CompanyInfo::languageId());
 
   super();
}

STEP 8

Go to method populate() in table PrintMgmtReportFormat and add this line of code:

addAx(PrintMgmtDocumentType::QualityOrders);

Finally go to:
Inventory and warehouse management > Setup > Inventory and warehouse management parameters > Print management
Here add a new node for the new report and set the print management settings.

For further information see also:

– SalesQuotationController class – for example

http://msdn.microsoft.com/en-us/library/tradedocumentreportcontroller.aspx

http://dynamicsaxgyan.wordpress.com/2011/08/19/learn-quick-first-ssrs-report-in-dynamics-ax-2012/ – create a new SSRS report

Advertisements

Comments on: "Manage printer settings for SSRS Report in AX 2012" (38)

  1. Martin Mikes said:

    Hello Martina,
    really nice instructions thanks for it.
    I followed you steps, but after run report I got message “No print management settings are applicable so no document is produced.”
    Did I something wrong?
    My report is really similar salesQuatiton, only I’m confused at methods initFormLetterReport and output at class controller, so this is reason why I used your manuall.
    Do I understandt correctly when I extended class TradeDocumentReportController I must overload all this classes?

    • Hi!
      Have you set the “Print management setup”?
      Inventory and warehouse management > Print Management (on the left) > Print management (button) > here you must add a new node as the picking list.
      And then you must define a print destination.

      • Martin Mikes said:

        Hi,
        I have report after sales so it shoud be at Account receivable/setup/forms/Form setup button Print management node Documents but I dont see new node:(

    • You should add code in the class PrintMgmtNode_Sales; the method name is: getDocumentTypes().

      docTypes.addEnd(PrintMgmtDocumentType::YourDocumentType);

      • Martin Mikes said:

        It’s help great thanks 😉 Only I would like to have a dialog with some parameter from my extends class from TradeDocumentReportController and it looks like it;s not supported, I must overload method templateForm, param method show dialog and etc didnt’t help. Didn’t you have similar problem?
        Thanks
        Martin

      • MarkKopan said:

        I have followed the instructions, added everything to the AR Node rather than the Invent node. I see my PM settings for my DocType, but can not select the SSRSReport from the drop-down list as my DefaultSettingReportFormat. It shows nothing. Did i miss a reference in the code?

      • Have you add a new record in the table: PrintMgmtReportFormat? This table contains all the reports with the print management settings.
        Add a new record and set it as system report(the flag in the table).

      • THANKS That was it… grrr. Why do they have to make so difficult. I also had to add Edit Classes so that my Document types show up in PrintMgmt & also modify PrintMgmtReportFormat Table method populate() . reference must be added so that any report designs will show up on PrintMgmt select Design addOther(PrintMgmtDocumentType, ssrsReportStr(), ssrsReportStr() , LanguageId or #NoCountryRegionId) for EACH Design template for your Report

  2. Martin Mikes said:

    I mean my new node

  3. I get this error after exactly following your steps :

    PrintMgmtPrintSettingDetail object not initialised.

    Stack trace

    (C)\Classes\TradeDocumentReportController\outputReport – line 5
    (C)\Classes\MSTARemittanceAdviceController\outputReport – line 28
    (C)\Classes\MSTARemittanceAdviceController\runPrintMgmt – line 71

  4. and neither parameter dialog pops up where we apply prin settings. infact it directly takes to printing the repotrt

  5. I keep getting this Error… WHY?
    TradeDocumentReportContract object not initialized.

    Stack trace

    (C)\Classes\TradeDocumentReportController\preRunModifyContract – line 11
    (C)\Classes\INSMedClaim837FormLetterController\preRunModifyContract – line 6
    (C)\Classes\SrsPrintMgmtController\outputReports – line 65
    (C)\Classes\TradeDocumentReportController\output – line 6
    (C)\Classes\INSMedClaim837FormLetterController\output – line 14
    (C)\Classes\INSMedClaim837FormLetterController\runPrintMgmt – line 3
    (C)\Classes\SrsPrintMgmtController\run – line 14
    (C)\Classes\SysOperationController\startOperation – line 10
    (C)\Classes\SrsReportRunController\startOperation – line 12
    (C)\Classes\SrsPrintMgmtController\startOperation – line 14
    (C)\Classes\SrsPrintMgmtFormLetterController\startOperation – line 14
    (C)\Classes\INSMedClaim837FormLetterController\main – line 9
    (C)\Classes\FormFunctionButtonControl\Clicked

    • Can you post, please, the class declaration of your contract (INSMedClaim837FormLetterContract) and the method INSMedClaim837FormLetterController.output ?
      Thanks

      • Mark Kopan said:

        [DataContractAttribute]
        public class INSMedClaim837FormLetterContract extends TradeDocumentReportContract
        {
        INSMedClaimId claimId;
        SalesId claimNumber;
        PrintMgmtDocInstanceType printMgmtDocInstanceType;
        PrintMgmtIdentificationTxt printMgmtIdentificationTxt;
        INSMedClaimHeader claimHeader;
        PrintCopyOriginal printCopyOriginal;
        }

        protected void output()
        {

        INSMedClaim837FormLetterContract rdpContract = this.getTradeReportContract() as INSMedClaim837FormLetterContract;
        formLetterReport.parmDefaultCopyPrintJobSettings(this.parmReportContract().parmPrintSettings());
        formLetterReport.parmDefaultOriginalPrintJobSettings(this.parmReportContract().parmPrintSettings());
        formLetterReport.parmUsePrintMgmtDestinations(false);
        formLetterReport.loadPrintSettings(INSMedClaimHeader,INSMedClaimHeader,CompanyInfo::languageId());
        this.parmReportContract().parmRdlContract().parmLanguageId(CompanyInfo::languageId());

        super();
        }

      • It seems ok! Another test you can do is: open the report with Visual Studio, make “Refresh” on datasource and re-deploy.

  6. Hey Martina, here’s one for you: I want to print my SRS “Report A” with it’s PM settings, then while still in the run, print all supporting documentation DocuRef stored documents (PDF’s). The supporting pdf documents have their own PM settings. Scenario: SSRS Report A prints on Printer 1, Tray 2 (because it’s pre-printed form stock). The additional docs may print to the same printer, Tray 1 or another printer. This is similar to Bank Check printing on a MICR printer, but statement/letters print to separate non-MICR printer. I must be making the call in the wrong place because Infolog shows the correct printer, but physically prints on Printer 1. So, the re-assignment of srsPrintDestinationSettings isn’t saved. Thanks in advance

  7. Hi Martina, even though this post i a bit old. But is it possible that you explain step 7. I have my own custom report, and i would like to implement print mgmt settings to the report but how?

    In step 7 you do it to standard ax 7 report?

    • I mean ind step 7 you do it with a standard ax report? How can implement my custom report to use printmgmt settings?

      • I’ve used the TradeDocumentReportController because a print my report from a journal (as the Invoice). Print you the report from a journal?

      • Thanks for the quick answer. Ok, now i understand. No i dont use a journal. I only use my custom report, with a controller, contract and a DP.

        I am trying to implement the print mgmt to my custom report.
        I can’t do the step 7 to my own controller?

      • Ok also you can extend the controller from SrsPrintMgmtController and the DP class from SrsReportDataProviderPreProcess.

        In the main of the controller:
        public static void main(Args _args)
        {
        YourReportController controller = new YourReportController();

        controller.parmReportName(ssrsReportStr(YourReportName, YourDesignName));
        controller.parmArgs(_args);
        controller.startOperation();
        }
        And then you have to override this method in the controller:
        protected void runPrintMgmt()
        {
        printMgmtReportRun = PrintMgmtReportRun::construct(PrintMgmtHierarchyType::YourModule, PrintMgmtNodeType::YourNodeType, PrintMgmtDocumentType::YourDocumentType);

        printMgmtReportRun.parmReportRunController(this);
        printMgmtReportRun.load(this.parmArgs().record(), this.parmArgs().record(), CompanyInfo::find().LanguageId);

        this.outputReports();
        }

        Write me in case you need help!

    • When i try to change the class declaration, it fails when i try to run the report.
      Message:
      Error executing code: wrong Argument types in variable assignment.
      The debugger window show the Classes\SRSPrintMgmtController\unpack method:
      public boolean unpack(container packedState)
      {
      container packedSuper;
      int version;

      if (inGetLast)
      {
      version = conPeek(packedState,1);
      switch (version)
      {
      case #CurrentVersion:
      –****—IT STOPS HERE–****—[version, #CurrentList, packedSuper] = packedState;

      return super(packedSuper);

      default:
      return false;
      }
      }
      else
      {
      return super(packedState);
      }

      return false;

      The class declaration i had before was SrsReportRunController

      • Try to delete the usage data.

      • A step closer. But i now i get this error, even though the node is created:
        PrintMgmtNode object not initialized.

        Stack trace

        (S)\Classes\PrintMgmtHierarchy\getParent – line 31
        (S)\Classes\PrintMgmt\getNodeInstances – line 80

      • Have you already implemented step 3 and 4?

      • I have, and i can change my print mgmt settings on inventory and warehouse – parameters – print mgmt.

      • Ran a Cil compile, and now i think it works

      • Hi Martina, suddenly when i tried to run my report, i get this error message.
        PrintMgmtNode object not initialized.

        Stack trace

        (S)\Classes\PrintMgmtHierarchy\getParent – line 31
        (S)\Classes\PrintMgmt\getNodeInstances – line 80
        (S)\Classes\PrintMgmt\getSettings – line 105
        (S)\Classes\PrintMgmt\getSettings_Server – line 20
        (C)\Classes\PrintMgmtReportRun\load – line 31

        I can see when it first tries to fint getParent it finds my node. But when it hits a while loop, the node is null. Do you know what i may be missing?

      • Hi! I need some information. Have you written a subclass of the PrintMgmtNode? What methods have you overwritten? What PrintMgmtNodeType have you used? A new one?

      • Hi Martina

        I have created a subclass PrintMgmtNode, and the methods overwritten is:
        protected str getDisplayCaptionImplementation(Common _tableBuffer)
        {
        str ret;

        return ret;
        }


        public List getDocumentTypes()
        {
        List docTypes = new List(Types::Enum);

        docTypes.addEnd(PrintMgmtDocumentType::Med_StdItemLabels);

        return docTypes;
        }

        public int getIconImageResNum()
        {
        int ret;

        return ret;
        }

        public PrintMgmtNodeType getNodeType()
        {
        return PrintMgmtNodeType::myNode;
        }

        public RefTableId getReferencedTableId()
        {
        return tablenum(MyTable);
        }

        —————————-

        I think the error came from step 4 PrintMgmtNodeInstance (getParentImplementation)
        I changed the switch case to:
        case PrintMgmtNodeType::MyNode:
        //result.parmReferencedTableBuffer(_nodeInstance.parmReferencedTableBuffer());
        //inventTable = _nodeInstance.parmReferencedTableBuffer();

        //result.parmReferencedTableBuffer(_nodeInstance.parmReferencedTableBuffer());
        //result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::MyNode));
        result = null;

        break;

        Then it went through, but i does’nt print anything out. Maybe because its empty?

        How do i feed the printMgmtReport with data?

        It jumps over this while, which i guess is the reportPrinter.

        protected void runOutputReports()
        {
        SrsPrintMgmtExecutionInfo executionInfo = reportContract.parmReportExecutionInfo();

        // if printMgmt is intialized run it.
        if(!printMgmtReportRun)
        {
        throw error(“@SYS328344”);
        }

        // keep count of print settings for each document. Will be used for raising the rendered complete event.
        executionInfo.parmPrintSettingsCount(printMgmtReportRun.getPrintSettingsCount());
        documentPrintCountMap.insert(executionInfo.parmDocumentId(), executionInfo.parmPrintSettingsCount());
        —————- Jumps over this section HERE
        while(printMgmtReportRun.next())
        {
        this.outputReport();
        }
        —————- Jumps over this section HERE
        }

      • Hi! Why do you want to return null here? Null is only for the root node.
        In what module you want to append your node?

        case PrintMgmtNodeType::MyNode:
        //result.parmReferencedTableBuffer(_nodeInstance.parmReferencedTableBuffer());
        //inventTable = _nodeInstance.parmReferencedTableBuffer();

        //result.parmReferencedTableBuffer(_nodeInstance.parmReferencedTableBuffer());
        //result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::MyNode));
        result = null;

        break;

        In my example, my report is in Invent module. Also my code is:
        case PrintMgmtNodeType::MyNodeType:
        result.parmReferencedTableBuffer(null);
        result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::Invent));
        break;

      • Hi

        When i use this code
        case PrintMgmtNodeType::MyNodeType:
        result.parmReferencedTableBuffer(null);
        result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::Invent));
        break;

        it won’t run because it says that the ReferencedTableBuffer is empty

      • Where exactly you receive this error (ReferencedTableBuffer is empty)?

      • At the moment i can’t replicate the error. But now it just jumps over this section. As if the report i empty:

        (When reinserting your code:
        case PrintMgmtNodeType::MyNodeType:
        result.parmReferencedTableBuffer(null);
        result.parmNodeDefinition(PrintMgmtNode::construct(PrintMgmtNodeType::Invent));
        break;)

        protected void runOutputReports()
        {
        SrsPrintMgmtExecutionInfo executionInfo = reportContract.parmReportExecutionInfo();
        // if printMgmt is intialized run it.
        if(!printMgmtReportRun)
        {
        throw error(“@SYS328344”);
        }
        // keep count of print settings for each document. Will be used for raising the rendered complete event.
        executionInfo.parmPrintSettingsCount(printMgmtReportRun.getPrintSettingsCount());
        documentPrintCountMap.insert(executionInfo.parmDocumentId(), executionInfo.parmPrintSettingsCount());
        —————- Jumps over this section HERE
        while(printMgmtReportRun.next())
        {
        this.outputReport();
        }
        —————- Jumps over this section HERE
        }

      • Here in this PrintMgmtHierarchyContext (Class) Method Validate
        When i set the ref. to be null. It gets stopped here:
        public void validate()
        {
        PrintMgmtHierarchy hierarchy;
        PrintMgmtNode startingNode;
        SetEnumerator enumerator;

        if (Debug::debugMode())
        {
        // Validate settings
        hierarchy = PrintMgmtHierarchy::construct(hierarchyType);

        if (hierarchy == null)
        {
        Debug::assert(false);
        }

        startingNode = PrintMgmtNode::construct(startingNodeType);

        if (startingNode == null)
        {
        Debug::assert(false);
        }

        // Ensure all document types are valid for the node
        enumerator = documentTypeFilterList.getEnumerator();
        while (enumerator.moveNext())
        {
        if (!startingNode.isValidDocumentType(enumerator.current()))
        {
        Debug::assert(false);
        }
        }

        // Validate the node type is valid for the hierarchy
        if (!hierarchy.isValidNodeType(startingNode.getNodeType()))
        {
        Debug::assert(false);
        }

        // Validate that the referenced buffer is set correctly
        if (startingNode.doesReferenceTable())
        {
        //// Here It stops
        if (referencedTableBuffer == null)
        {
        Debug::assert(false);
        }

        // Validate the referenced buffer is the correct table
        if (startingNode.getReferencedTableId() != referencedTableBuffer.TableId)
        {
        Debug::assert(false);
        }
        }
        }
        }

      • Hi! Ok, have you seen with the debugger the call stack? You have the error when you run the report. Can you control in the call stack (with the debugger)from which method of your class the call start? For example, in my report the call start from the method runPrintMgmt method of the controller.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Tag Cloud

%d bloggers like this: