Thursday 10 March 2016

Dynamics AX 2012 - Workflow Development in 2 Hrs.

Hi Friends,

First of all would like to wish you all Very "Happy and Dynamics new year -2012".

You all might be aware/heard of new changes related to worklow architecture and development.
So this post basically addresses,

1. Workflow Architecture changes
2. Workflow Development  wizards
3. Generic class for submit/resubmit events on all workflows in AX.


1. Workflow Architecture changes

In 2012, AOS service has gone tremendous changes like

- Now you can directly host WCF services on AOS.
- Earlier version we were using IIS to interact with WWF(Windows workflow foundation) and    
           WCF (Windows communication foundation).
- Because of above change, now no need to install workflow component separately
- Just run the workflow configuration wizard (available in System administration->Setup)
- Workflow templates/configuration were made available across companies/per company level.
- Workflow template is renamed to Workflow types

2. Workflow Development through wizards.

Let us develop workflow for
        'Customer approval- New created customer should be approved through workflow'

Step 1:
          Create a query for custTable say 'CustApprWorkflowQry' in AOT->Queries

Step 2:
          Duplicate enum 'PurchReqWorkflowState' and rename it to 'CustApprWorkflowState' and drag it to CustTable Table.

Step 3:
          Override 'canSubmitToWorkflow' method on Table->CustTable and paste below code.

  //BP Deviation Documented
                public boolean canSubmitToWorkflow(str _workflowType = '')
                {
                    boolean ret;

                    ret = this.RecId != 0 && this.CustApprWorkflowState ==
                    CustApprWorkflowState::NotSubmitted;

                    return ret;
                 }


Create new method on CustTable as below to update worklow state during its life cycle.

                //BP Deviation documented
                public static void UpdateCustWorkflowState(RefRecId _recId, CustApprWorkflowState _state)
                {
                    CustTable custTable = CustTable::findRecId(_recId, true);

         ttsBegin;

         custTable.CustApprWorkflowState = _state;
         custTable.update();

         ttsCommit;
  }


Step 4:
            Create workflow type (template/configuration) through wizard available in 2012.

  Run wizard as below:

  AOT->Workflow-> Workflow types  (Right click ->Add-Ins-> workflow type wizard...

  Specify values as shown in below image







  Click on next, as shown in below image wizard will create workflow eventhandlers class and menu items for you.




  Paste below code to update workflow state.

  //BP Deviation Documented
  public void started(WorkflowEventArgs _workflowEventArgs)
  {
      CustTable::UpdateCustWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(), CustApprWorkflowState::Submitted);
  }

  //BP Deviation Documented
  public void completed(WorkflowEventArgs _workflowEventArgs)
  {
     CustTable::UpdateCustWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(), CustApprWorkflowState::Completed);
  }

  //BP Deviation Documented
  public void canceled(WorkflowEventArgs _workflowEventArgs)
  {
  CustTable::UpdateCustWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(),   CustApprWorkflowState::PendingCancellation);
  }


Step 5:
           Create workflow approval through wizard available in 2012.
 
  Run wizard as below:

  AOT->Workflow-> Approvals  (Right click ->Add-Ins-> Approval wizard...

  Specify values as shown in below image




  Click on next, as shown in below image wizard will create workflow element eventhandlers and menu items for you.




  Paste below code to update workflow state.

  //BP Deviation Documented
  public void started(WorkflowElementEventArgs _workflowElementEventArgs)
  {
     CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),   CustApprWorkflowState::Submitted);
  }

  //BP Deviation Documented
  public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
  {
     CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),  CustApprWorkflowState::Returned);
  }

  //BP Deviation Documented
  public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)
  {
          CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),  CustApprWorkflowState::ChangeRequest);
  }

  //BP Deviation Documented
  public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), CustApprWorkflowState::Approved);
  }

  //BP Deviation Documented
  public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
  {
         CustTable::UpdateCustWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),  CustApprWorkflowState::PendingCancellation);
  }

Step 6:
          Enable workflow on CustTableListPage form and alos drag field CustApprWorkflowstate on form overview grid, as below

          CustTableListPage->Design, set properties as below




Step 7:
          Download below class to activate workflow on submit and resubmit.

          This is generic class and with little modification can be used for all different worklow's in AX.
          Download Class XPO :
       
         Once you download and import class,  change below menu-items associated with submit and resubmit actions.




Step 8:
          Run Incremental CIL generation, AOT->Right click-> Incremental CIL generation

You are done with development and can configure workflow in AR->Setup
After activating above workflow configuration test it by creating new customer in CustTableListPage form.

Hope you enjoyed this new style of  workflow development which will take 1-2 hours for any new basic  workflow approval :)










Happy DAXing
........

Increase report running time to fix time out issue



Happy DAXing
...........

How to handle SSRS reports which will take long time

Error: Running the report has been cancelled due to the time it will take to run. Adjust the parameters of the report and retry.

We know that there are/will be some reports which will take more time to render due to the many rows/transactions. This post will help you to show appropriate warning/error messages to the end user while running the report. 

The number of records that are processed by report might be large and the user experience will be affected, because the client will be locked up if printing to the screen. 

In this case, you might want to return a warning message to the user that indicates that time to process the report might be long and confirm that they want to run the report. 

Another case could be where the number of records being processed is very large and a time-out might occur in report processing and clearly we should not run this report.
In this case, we should not run the report and therefore, should return an SrsReportPreRunState::Error enumeration value with the error message. 
In AX 2012, SSRS reports , through SrsReportRunController we can easily let the user know that the report will take more time with warnings or error messages through preRunValidate method. 


Example-1 : Trial balance report

Take the standard example of Trial balance report from General Ledger >> Reports >> Transactions >> Trial balance.

Use standard LedgerTrialBalanceController class to help you understand preRunValidate method: this validates container before running the report. Override this method to do custom pre-validation for any report. Typical use of this method will be to validate if the time taken to run the report is acceptable.
In this standard example: If the query is going to retrieve more than 1000 rows, a confirmation Box will be displayed to the user as shown below.

Clearly in the below standard example : warning limit is 1000 and error limit is 100000.
 

Run this report as shown below...
 

Here comes the confirmation Box: 
If your report is long running, it may time-out. Do you want to continue? 

Note: In order to resolve/by pass this confirmation Box, a developer can change the macro #define.warningLimit to greater value 
Example : #define.warningLimit(2000); 

image

Let us run the report One more time as shown below. 


Here comes the error message: Running the report has been cancelled due to the time it will take to run. Adjust the parameters of the report and retry. 
In order to resolve this problem, Increase the ErrorLimit macro value from 100000 to 150000 or 250000 in the preRunValidate method. 
Please note, it is not recommended to increase as it will take more time and your box cannot handle load. 

Example : #define.ErrorLimit(250000); 

image


I would recommend that to be Compiled forward this LedgerTrialBalanceController class and then run Generate Incremental CIL and then restart SSRS services. Now run the Trial balance report, it should give output. 
In case, above error is still occurring then run Generate Full CIL and then restart SSRS services. Now run the Trial balance report, it must give output.

Example-2 : General Journals report 

Take the standard example of Print journal from General Ledger >> Reports >> Journal >> Print journal. 

Use standard LedgerJournalController class to help you understand preRunValidate method: this validates container before running the report. Override this method to do custom pre-validation for any report. Typical use of this method will be to validate if the time taken to run the report is acceptable. 
In this standard example: If the query is going to retrieve more than 1000 rows, a confirmation Box will be displayed to the user as shown below. 

To get the confirmation box and for the sake of the demo/understanding: I have hardcoded the rows count to 1001 as shown below. There is a new static method in QueryRun::getQueryRowCount that will get the row Count of the query. 

Please note: Remove hardcoded values later. This is hardcoded only for the sake of demo/Walk through 
Clearly in the below standard example : warning limit is 1000 and error limit is 100000.

image

Run this report as shown below...

image

Here comes the confirmation Box: 
If your report is long running, it may time-out. Do you want to continue? 

Note: In order to resolve/by pass this confirmation Box, a developer can change the macro #define.warningLimit to greater value 
Example : #define.warningLimit(2000); 

image

you can increase the row count : to 1000001. 

image

Let us run the report One more time as shown below. 

image

Here comes the error message: Running the report has been cancelled due to the time it will take to run. Adjust the parameters of the report and retry
In order to resolve this problem, Increase the ErrorLimit macro value in thepreRunValidate method. 
Please note, it is not recommended to increase as it will take more time and your box cannot handle load. 

Example : #define.ErrorLimit(150000); 

image

Happy DAXing
.............

SSRS Report – Timeout error for Long running queries in AX2012

A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 202.xx.xx.xx:80

Posted on August 6, 2013 by Siva Kumar
There is a process to change long running jobs so that they are run in a Pre-Processing way, so that all the data is prepared before the SSRS Report Window is started. This prevents the timeout problem, sometimes shown by the message
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
To change the report to run in this pre-processing way (Similar to Sales confirmation, Sales Invoice, etc. reports).
see this example below for the Fixed Asset movement report on how to change this:
1. To find which object you need to modify, first look in the AOT >> Menus, for the Menu where the report is
2. View the properties on this to see the associated menu item. You can see below the menu item is “AssetBalancesPeriod”.
3. Find this menu item in AOT >> Menu Items >> Output and look at the properties, make a note of the “LinkedPermissionObject”, in this case “AssetBalancesPeriod”
4. Next in the AOT >> SSRS Reports >> Reports, locate AssetBalancesPeriod, then expand this out until you see the Server Methods. Make a note of the Server Method class, in this case “AssetBalancesPeriodDP”
5. In the AOT >> Classes, locate and open class AssetBalancesPeriodDP.
6. In the AssetBalancesPeriodDP\classDeclaration, change the extend class to SrsReportDataProviderPreProcess instead of SrsReportDataProviderBase
7. Make a note of the Temp table used in the report, as above this is AssetBalancesPeriodTmp.
8. Next, change the method AssetBalancesPeriodDP\processReport to add the following line after the contract:
contract.parmFromDate();
contract.parmtodate();
AssetBalancesPeriodTmp.setConnection(this.parmUserConnection());
9. Next, in AOT > Data Dictionary > Tables, locate the table you made a note of in point 7, so in this case the AssetBalancesPeriodTmp. Change the table properties as follows:
• TableType = Regular
• CreatedBy = Yes
• CreatedTransactionId = Yes
10. Opened AssetBalancesPeriod report in Visual Studio and refreshed the data source to include new field (CreatedTransactionId).
11. Deployed the new AssetBalancesPeriod report.
12. In AX did a Generate Incremental CIL.
13. Restart SSRS
Now this report can run without timeout error.



Happy DAXing
................