Wednesday, 5 September 2018

AX : Work flow in Ax 2012


Few days back I got a chance to work on Ax2012 work flow, so I decided to document it for future reference and other user can also have an idea about it so here we start with what the work flow is.
What is Work flow :  A workflow represents a business process. A workflow defines how a business document flows through the system by indicating who must process and approve it.
Life Cycle:  Developer design the workflow based on customer requirements
System administrator configures the workflow.
End user run the workflow.


Bird's-eye view  :


Artifacts:
Work flow is revolve around the following artifacts 

  •          Workflow query
  •          Workflow category
  •          Workflow type
  •      Workflow approval 
  •      Enabling workflow on a form
  •      Work flow Configuration 
      Scenario : 
     scenario I need to implement work flow is :Create a custom document for submitting travelling allowance.
We Need to Cater Following Conditions in it
Assign workflow to If total amount is Less than $2500 than Line Manager Approval Required.
If Total Amount > 50,000 CFO Approval is required
If Amount > 1 Lac CEO Approval is required
Submitter can submit the workflow, approver can approve / Reject / Cancel the workflow.
TO implement above scenario I have taken / performed following task In order to accomplish it
Challenge:
If HOD of worker exists than it will go to HOD for Approval. Work flow will never through error in any case 
First thing First
Query

We must first create a query that will access the table fields for the workflow document. As shown in below image.

Category :
A workflow category is used to determine the module in which the workflow will
Be available. Refer to the image below

Type: It is the basic building block that can be used to create customized workflows that enforce business policies. A Work Flow type defines :
The Work Flow document to use.
Tasks and approvals that can be configured by the User.
Workflow categories used to assign a workflow type to a specific module.
Example of Work flow Type Properties is shown below
Approval :
Approvals are specialized workflow elements designed to support approval scenarios. Approvals have a set of fixed outcomes that the workflow supports. These outcomes are as follows:
§   Approve - Outcome type Complete.
§   Reject - Outcome type Return to the originator of the workflow.
§   RequestChange  Outcome type Change Requested to a specific person in the workflow process.

Example of Work Flow Approval is as shown in below image 

Enabling Work flow on Form:
Design:

Workflow Condition:


Important thing to remember:

Note there is a form named as “Tutorial_WorkflowProcessor” we Need to Start it while submitting / or taking any action on workflow Refer to below Image


Development Aspects:

Common Tables Involve in workflow development like if we want to get below information
Get Approval Date
 Get Approver Name
  • WorkflowTrackingStatusTable   
  • WorkflowTrackingTable;
  • WorkflowVersionTable
  • WFElementTble
  • WFStepTable 








Tuesday, 4 September 2018

AX : XDS Extensible Data Security frame work


In this Blog post we will learn about Extensible Data Security frame work and how to implement security using XDS in ax 2012
What is XDS :
Extensible Data Security (XDS) is a framework in MicrosoftDynamics AX that allows developers and system administrators to deny access to subsets of data and only share a subset of data with appropriate users. XDS replaces the Record level security framework in previous MicrosoftDynamics.

XDS Artifacts

       Query
       Primary Table
       Constrained Table
       Policy
       Context

Primary table: This is the main table in the query on which the policy is imposed. In our case, cust table is the primary table where we have to define the said range.
Constraint table: These tables have foreign key relation on the primary table and their contents will be secured based on range defined in primary table.  In our case, it will be Sales table where the customer display will be limited to the values defined in primary table.
       Policy query: Every XDS policy has a query where the constraints (ranges) are defined. You can nest multiple data sources in the query.
Policy Context: Context type in the policy. It can be one of the following – Role Property/ Role Name/Context string.
Context String: You specify a value here and this will be matched with the Context string property defined for a role.
Role Name: This specifies the role for which the policy is applied.
Role property: This is used in combination with ContextString to specify multiple roles context.
Scenario:
Lets take a scenario in which we need to restrict user that it can only view the specific customer group sales Order. Let say cust group 20.
To implement the scenario follow the following steps
Step 1 : Create Query:
First thing first, Create AOT Query  with CustTable as a datasource of our Query as Shown in Figure (a)
 Figure (a)

Step 2 : Create Role
Create Role from AOT > Security > Roles, Specify the Label and description of created Role as shown in below image




Step 3 :  Create Policy
Now create policy and specify all the relevant properties as shown in figure (c). note:  do not leave any essential property blank here as these are very crucial in implementing XDS
Essential Properties of Policy are:
i)                    Primary Table  : in Our scenario its custTable
ii)                   Constrained Table : Select it as Yes or Leave it No according to your Requirement
iii)                 Context Type : select RoleName here
iv)                 RoleName : Select Role created in Step 2

Step 4 : Assign XDS Role to User


Assign XDS Role Created in step 2 to any user in which you need to test XDS. Refer to the below image 
Step 5 : Execution
When Login through a user which we have assigned our created XDS Role you will get the only customer record having custgroup = 20 as shown in below image 





Thursday, 10 May 2018

SSRS : Load Control based on Other parameter Control


Recently I came through a scenario in which I need to fill Invoice Lookup according to the selected Sales Order. To achieve this problem statement I have perform following task to accomplish this
First lets create the sales order and Invoice Lookup Parameter in Contract Class
Class declaration code is like below
{
    FromDate                    fromDate;
    ToDate                      toDate;
    List                        listSO,listInvoice,listCustomer;
}

Note here I am using SO and Invoice as a List type. it is because we are creating a multi select lookup for both.
Now the sales Order Parameter code in contract class is below

[
    DataMemberAttribute('Sales Order'),
      AifCollectionTypeAttribute("Sales Order", Types::String),
    SysOperationLabelAttribute(literalStr("Sales Order")),
    SysOperationHelpTextAttribute(literalStr("Please Select Sales Order")),
    SysOperationDisplayOrderAttribute('05')
]
public List parmSO(List _listSO=listSO)
        {
            listSO=_listSO;
            return listSO;
        }

Similarly invoice parameter code is like

[
    DataMemberAttribute('Invoice'),
    AifCollectionTypeAttribute("Invoice", Types::String),
    SysOperationLabelAttribute(literalStr("Invoice")),
    SysOperationHelpTextAttribute(literalStr("Please Select Invoice")),
    SysOperationDisplayOrderAttribute('04')
]
public List parmInvoice(List _listInvoice=listInvoice)
        {
            listInvoice=_listInvoice;
            return listInvoice;
        }


We are done with the contract class now lets move to the UI Builder Class

In UI Class first we write the method responsible for sales Order lookup but wait before we jump into the code we need to create the AOT Query which is going to be used by the code we are going to write for Lookup below Image is the Sales Order Lookup AOT Query



On the datasource Node drag the salesTable and set the Dynamic property “No” of the datasource fields Node as highlighted in above Image and than Add the SalesId field under the fields node by right clicking on field node click New than Add -> Field.   Refer to Image below. Select the salesId field here


After creating SO Lookup AOT Query now we will create a Lookup Method in UI Builder class which call above AOT query and display sales Order Lookup. Code of SO Lookup is as below
private void LookUpSO(FormStringControl _control)
        {
          Query       query;
          SysLookupMultiSelectGrid    sysLookupSO;

                    sysLookupSO = SysLookupMultiSelectGrid::construct(_control, _control);
                    query = new query("SL_SOLookup");
                    sysLookupSO.parmQuery(query);
                    sysLookupSO.run();
        }

If you look Lookup Code its query Object is initializing with our created sales Order Lookup AOT Query as “SL_SOLookup”

Now Repeat the above AOT Query creation steps and create a Invoice Lookup AOT Query similar to Sales Order Lookup Below is the InvoiceLookup snap shot for reference



Note I have used the custInvoiceJour as datasource and InvoiceId in fields of datasource as dynamic property set to “No”

Let’s create Lookup Invoice method which will call InvoiceLookup AOT Query created above
private void LookupInvoice(FormStringControl _control)
 {
     Query                      query;
     container                  socontainer;
     str                        selectedRecId;
     SalesId                    selectedSalesId;
     SysLookupMultiSelectGrid    sysLookupInvoice;
     int          counter;

        sysLookupInvoice = SysLookupMultiSelectGrid::construct(_control, _control);
     if (sysLookupSO)
     {
         socontainer = sysLookupSO.getSelected();
     }
         query = new query("SL_InvoiceLookup");

         for(Counter=1; Counter<=conLen(socontainer); Counter++)
         {
             selectedSalesId = this.getSalesId(conPeek(socontainer,counter));
             query.dataSourceTable(tableNum(CustInvoiceJour)).addRange(fieldNum(CustInvoiceJour,SalesId)).value(SysQuery::value(selectedSalesId));
         }

        sysLookupInvoice.parmQuery(query);
         sysLookupInvoice.run();

 }
Above Invoice Lookup Method is calling private Method in UI builder class as “getSalesId” which is as below
private SalesId getSalesId(RecId _recId)
{
    SalesTable                  salesTable;

    select firstOnly salesTable where salesTable.recId == _recId;

   return salesTable.salesId;

}
After we done with the Lookup Code now move to the postBuild()
 Method and its code will be as below
postBuild()
{

dfSO = this.bindInfo().getDialogField(dataContract, methodStr(SL_SalesTaxInvoiceContract, parmSO));
           if (dfSO)
            {
                dfSO.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(SL_SalesTaxInvoiceUI, LookUpSO), this);
                dfSO.lookupButton(FormLookupButton::Always);

            }

             
               dfInvoice = this.bindInfo().getDialogField(dataContract, methodStr(SL_SalesTaxInvoiceContract, parmInvoice));
           if (dfInvoice)
            {
                dfInvoice.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(SL_SalesTaxInvoiceUI, LookUpInvoice), this);
                dfInvoice.lookupButton(FormLookupButton::Always);

            }


}

In above post build method dfSO and dfInvoice are the dialog field declare in class declaration of UI builder class as below

{
DialogField             dfSO,dfInvoice,dfCustomer,dFromDate,dTodate;
   
}

Do not forget to add Build Method in UI Builder class. Build Method Looks Like Below :
Public void build()
{
    dataContract          = this.dataContractObject() as TK_SalesTaxInvoiceContract;


            dFromDate     = this.addDialogField(methodStr(TK_SalesTaxInvoiceContract, parmFromDate), dataContract);
            dToDate       = this.addDialogField(methodStr(TK_SalesTaxInvoiceContract, parmToDate), dataContract);
            dfSO          = this.addDialogField(methodstr(TK_SalesTaxInvoiceContract, parmSO), dataContract);
            dfInvoice     = this.addDialogField(methodstr(TK_SalesTaxInvoiceContract, parmInvoice), dataContract);
            dfCustomer    = this.addDialogField(methodStr(TK_SalesTaxInvoiceContract , parmCustomer),dataContract);

}
We are done with the code part when Running Report and selecting the SO-000014 the Invoice against it populated in Invoice Lookup as shown Below



And Changing the SO selection will change the invoice population too as shown in below image



Remember one good thing we have made the sales Order and Invoice Lookup as multi select parameter so that we can select multi Sales Order and according to selected multiple sales order multiple invoice will be displayed as shown in below image






So that s all i have for this post. do let me know for any feed back or any confusion/ suggestion  

Tuesday, 24 April 2018

SSRS : Enable/ Disable contract class Control Based on other contract parameter control


In this blog we will see how to enable / disable contract class parameter control based on the modification of other contract class parameter. This all is going to be happened in UI Builder class
So here we go
1.       First write the Method which is responsible to perform actual functions like enabling and disabling control
In this blog I will be using Enum Control and based on its modification disabling lookup controls
Where in below image Report Type is Enum Control and WindMast and Sensor are the lookup controls


Enable/ Disable Method should be written in UI Builder class will be like

private boolean EnableControls(FormComboBoxControl _control)
{
   
   
    if(_control.valueStr() == enum2str(TK_TurbineSummary::Production))
    {
    dWindMast.enabled(false);
    dSensor.enabled(false);
    }
    else
    {
       dWindMast.enabled(true);
    dSensor.enabled(true);

    }
    return true;
}

In above piece of code I have disable the lookup controls On “Production” Report Type and make them enable on Wind Speed Report Type


Where dWindMast and dSensors are the dialog field define in Build method of UI Class like Below



Now In Post Build Method of UI Class we need to register our above created method “EnableControls”  Like below

public void postBuild()
{

 dReportType = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(TK_TurbineSummaryContract, parmReportType));
            dReportType.registerOverrideMethod(methodStr(FormComboBoxControl, modified), methodStr(TK_TurbineSummaryUI, EnableControls), this);
            dShowProduction = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(TK_TurbineSummaryContract, parmShowProduction));
}

When we Run Report and change the Report type Drop down value Result will be as below
Disable Controls :


Enabling Control on drop down selection changed

That is how we can enable/ disable controls. 
Last but not the least Happy daxing :)