Saturday, May 30, 2015

DMF Error on import the data into staging table: Exception from HRESULT: 0xC0048021 at Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelper.DMFEntity.ShowPreview(Boolean isComposite)

I have been trying to import data from an Excel file using Data Import Export Framework. The mapping and validation works but when I try to import the data into staging table – I get the below error:

Exception from HRESULT: 0xC0048021  at Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelper.DMFEntity.ShowPreview(Boolean isComposite)  at Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelperService.Service.ServiceHelper.ShowPreview(DMFEntity entity)

Error:
Exception from HRESULT: 0xC0048021
at Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelper.DMFEntity.ShowPreview(Boolean isComposite)
at Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelperService.Service.ServiceHelper.ShowPreview(DMFEntity entity)

Solution:

The problem is caused by the DMConfig XML file.
Go to the DMConfig.xml file in the “C:\Program Files\Microsoft Dynamics AX\60\DataImportExportFramework” folder and replace the PipelineComponentInfo_Multicast, PipelineComponentInfo_ExcelSource and   nodes by the following:

    {33D831DE-5DCF-48F0-B431-4D327B9E785D}
 
 
    {9F5C585F-2F02-4622-B273-F75D52419D4A}
 
 
    {90E2E609-1207-4CB0-A8CE-CC7B8CFE2510}
 

Happy Daxing !!!!


Thursday, March 19, 2015

CompanyInfo VatNum or any other field Unretrieved issue

Recently I came across one strange issue related to Service Order > Worker description report, I got exception every time when I run this report, after doing some investigation I found that the VatNum field is used in DP class but when i open CompanyInfo table from AOT, I got 'Unretrieved' values of this VatNum for all rows. VatNum basically a string field and it should be either BLANK or having some values. After trying so many trick from google (restart AOS, refresh cache) i still got the 'Unretrieved' issue. I than decided to set this field explicitly from backend DB, in Dynamics AX 2012 R2 databases, it appears that the CompanyInfo table (for example) exists in the AOT but not in the actual SQL database. The columns & data that are supposedly contained in CompanyInfo (according to the AOT) are actually found in the DirPartyTable. This is in contrast to AX 2012 databases. So after manually delete 'NULL' value from VATNum on DirPartyTable to BLANK i than able to run the report successfully. So TWO key point here are :
  • To overcome the 'Unretrieved' issue you can directly replace column value from NULL to BLANK.
  • You can find CompanyInfo table in AOT but not from SQL DB, use DirPartyTable instead to fix your desired 'Unretrieved' field issue.

Happy DAXing !!!!

Thursday, November 27, 2014

Copy Custom field from PO line to Invoice line

Sometime we have a scenario where we have to copy custom field value from PO to invoice, to do this you have create similar field in VendInvoiceInfoLine table and set/copy the value from PO line to invoice line on VendInvoiceInfoLine.defaultRaw() method or in class VendDocumentLineType_Invoice.

Happy DAXing !!!!

Monday, November 24, 2014

Add Action pane AxActionPaneControl to EP form

To add Action pane with default Save and Close buttons, here are the steps:

Create two web menus in AX
Add following code on ASP.NET script:
<%@ Register Assembly="Microsoft.Dynamics.Framework.Portal, Version=6.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
 Namespace="Microsoft.Dynamics.Framework.Portal.UI.WebControls" TagPrefix="dynamics" %>
<%@ Register Src="AxBaseUserControl.ascx" TagName="AxBaseUserControl" TagPrefix="Ax" %>
<%@ Register Assembly="Microsoft.Dynamics.Framework.Portal.SharePoint, Version=6.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
Namespace="Microsoft.Dynamics.Framework.Portal.SharePoint.UI.WebControls" TagPrefix="dynamics" %>

dynamics:AxDataSource ID="youDS" runat="server" DataSetName="youDS"
    ProviderView="yourTable">
dynamics:AxDataSource

dynamics:AxActionPaneControl ID="AxActionPaneControlTop" runat="server"
DataMember="yourDS_Current" DataSourceID="yourDS"
WebMenuName="axToolBarInfo" EnableMenuItemHelpText="True" EnableTheming="True"
dynamics:AxActionPaneControl ID="AxActionPaneControlEdit" runat="server" EnableTheming="True"
DataMember="youDS_Current" DataSourceID="youDS" EnableMenuItemHelpText="True" WebMenuName="axToolBarCreate"

Now write following code in C# code behind:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.Dynamics.Framework.Portal.UI;
using Microsoft.Dynamics.Framework.Portal.UI.WebControls;
using Microsoft.Dynamics.AX.Framework.Services.Client;
using Microsoft.Dynamics.AX.Framework.Portal.Data;
using Proxy = Microsoft.Dynamics.Framework.BusinessConnector.Proxy;
using ApplicationProxy = Microsoft.Dynamics.Portal.Application.Proxy;
using Microsoft.Dynamics.Framework.BusinessConnector.Adapter;
using Microsoft.Dynamics.Framework.Portal;
using Microsoft.Dynamics.Portal.Application.Proxy;
using Microsoft.Dynamics.Framework.BusinessConnector.Session;
using Microsoft.Dynamics.Framework.Portal.UI.WebControls.WebParts;

public partial class Form1: System.Web.UI.UserControl
{
    protected const string axToolbar_Info = "axtoolbarinfo";
    protected const string axtoolbar_Create = "axtoolbarcreate";
    private const string MENU_ITEM_SaveAndClose = "epsaveandclose";
    private const string MENU_ITEM_Close = "epclose";

    protected void Page_Load(object sender, EventArgs e)
    {
        this.SetupMode();
    }

    void Page_Init(object sender, EventArgs e)
    {
        this.AxActionPaneControlTop.SetMenuItemProperties += new EventHandler(AxActionPaneControlTop_SetMenuItemProperties);
        this.AxActionPaneControlTop.ActionMenuItemClicking += new EventHandler(AxActionPaneControlTop_ActionMenuItemClicking);
        this.AxActionPaneControlTop.ActionMenuItemClicked += new EventHandler(AxActionPaneControl_ActionMenuItemClicked);

        this.AxActionPaneControlEdit.SetMenuItemProperties += new EventHandler(AxActionPaneControlTop_SetMenuItemProperties);
        this.AxActionPaneControlEdit.ActionMenuItemClicking += new EventHandler(AxActionPaneControlTop_ActionMenuItemClicking);
        this.AxActionPaneControlEdit.ActionMenuItemClicked += new EventHandler(AxActionPaneControl_ActionMenuItemClicked);
    }
    ApplicationProxy.EPFormAction FormMode
    {
        get
        {
            return (ApplicationProxy.EPFormAction)Convert.ToInt16(
            this.Page.Request.QueryString.Get("mode")); // This mode is the param set in web menu item url, i.e. mode=1
        }
    }

    private ISession AxSession
    {
        get
        {
            AxBaseWebPart webpart = AxBaseWebPart.GetWebpart(this);
            return webpart == null ? null : webpart.Session;
        }
    }

    private void SetupMode()
    {
        //Proxy.Info objInfoLog = new Proxy.Info(this.AxSession.AxaptaAdapter);
        //objInfoLog.add(Proxy.Exception.Warning, Convert.ToString(this.FormMode));
        switch (this.FormMode)
        {
            case ApplicationProxy.EPFormAction.EditMode:

                this.AXForm.DefaultMode = DetailsViewMode.Edit;
                this.AXForm.AutoGenerateEditButton = true;
                this.AXForm.AutoGenerateInsertButton = false;
             
                break;

            case ApplicationProxy.EPFormAction.CreateMode:
                this.AXForm.DefaultMode = DetailsViewMode.Insert;
                this.AXForm.AutoGenerateEditButton = false;
                //this.AXForm.AutoGenerateInsertButton = true;
                this.AxActionPaneControlTop.Visible = false;
                this.AxActionPaneControlEdit.Visible = true;
               
                break;

            default:
                this.AXForm.DefaultMode = DetailsViewMode.ReadOnly;
                this.AXForm.AutoGenerateEditButton = false;
                this.AXForm.AutoGenerateInsertButton = false;
                this.AxActionPaneControlTop.Visible = true;
                this.AxActionPaneControlEdit.Visible = false;
                break;
        }
    }
 
    void AxActionPaneControlTop_ActionMenuItemClicking(object sender, ActionMenuItemClickingEventArgs e)
    {
        e.RunMenuItem = false;
    }

    void AxActionPaneControl_ActionMenuItemClicked(object sender, ActionMenuItemEventArgs e)
    {

        switch (e.MenuItem.MenuItemAOTName.ToLower())
        {
            case MENU_ITEM_SaveAndClose:
                this.AXForm.InsertItem(true);
                DialogHelper.Close(CloseDialogBehavior.RefreshDataSource);
                break;
            case MENU_ITEM_Close:
                this.AXForm.DoCancel();
                DialogHelper.Close(CloseDialogBehavior.CloseOnly);
                break;
        }
    }

    void AxActionPaneControlTop_SetMenuItemProperties(object sender, SetMenuItemPropertiesEventArgs e)
    {
        string menuItemName = e.MenuItem.MenuItemAOTName.ToLower(System.Globalization.CultureInfo.InvariantCulture);

        switch (menuItemName)
        {
            case MENU_ITEM_Close:
                // Close should not trigger validation
                ((AxActionMenuItem)e.MenuItem).CausesValidation = false;
                break;
            //case MENUITEMNAME_SaveAndClose:
        }
    }
     protected override void OnInit(EventArgs e)
    {
        this.SetupMode();
        base.OnInit(e);
    }
}



Add Grid and AxToolbar in Dynamics AX EP details form

Here are the steps you can follow to add Grid with AxToolbar in any EP detail form:

  1. Create new WebActionMenu for Add and Delete (i.e. YourDetailFormAdd), Label=‘Add’, NormalImage= 11421)
  2. Create new Web menu YourDetailForm and drag both action menus to this web menu
  3. In your MasterDetail form in VS where you wants to place this detail grid, add new AxToolBar control and set WebMenuName= YourDetailForm, ID= YourDetailFormToolBar
  4. Add AxGridView control and set DS, AllowDelete,AllowEdit,AllowInset to True. And set Datasource and DataMember. Finally set DataKeyName=RecId.
  5. Open .cs file of your Form and declare two constants for menu items you created in AX:
  6. protected const string YOURDETAILForm_ADD= “yourdetailformadd";
  7. protected const string YOURDETAILFORM_DELETE= “yourdetailformdelete";
  8. Create new property to get your CurrentRow of your datasource.
  9. For Grid, we have to write event for (and called from Page_Load):
  10. RowUpdated
  11. RowEditing
  12. RowDeleting
  13. RowInserted
  14. RowCreated
  15. RowCancelingEdit
  16. For ToolBar, we have to write following event and called from OnInit
  17. ActionMenuItemClicking
  18. ActionMenuItemClicked
  19. SetMenuItemProperties
Here is the example of C# code behind:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.Dynamics.Framework.Portal.UI;
using Microsoft.Dynamics.Framework.Portal.UI.WebControls;
using Microsoft.Dynamics.AX.Framework.Services.Client;
using Microsoft.Dynamics.AX.Framework.Portal.Data;
using Proxy = Microsoft.Dynamics.Framework.BusinessConnector.Proxy;
using ApplicationProxy = Microsoft.Dynamics.Portal.Application.Proxy;
using Microsoft.Dynamics.Framework.BusinessConnector.Adapter;
using Microsoft.Dynamics.Framework.Portal;
using Microsoft.Dynamics.Portal.Application.Proxy;
using Microsoft.Dynamics.Framework.BusinessConnector.Session;
using Microsoft.Dynamics.Framework.Portal.UI.WebControls.WebParts;

public partial class YourForm: System.Web.UI.UserControl
{
    protected const string COSTTYPE_ADD = "hrminjuryincidentcosttypeadd";
    protected const string COSTTYPE_DELETE = "hrminjuryincidentcosttyperemove";
    
 
    protected void Page_Load(object sender, EventArgs e)
    {
        this.SetupMode();

        if (this.WebPart != null)
        {
            // Cost type
            AxCostGrid.RowUpdated += new GridViewUpdatedEventHandler(CostGrid_RowUpdated);
            AxCostGrid.RowCancelingEdit += new GridViewCancelEditEventHandler(CostGrid_RowCancelingEdit);
            AxCostGrid.RowEditing += new GridViewEditEventHandler(CostGrid_RowEditing);
            AxCostGrid.RowDeleting += new GridViewDeleteEventHandler(CostGrid_RowDeleting);

        }
        
    }

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);

        // Cost Type
        this.InjuryCostToolBar.ActionMenuItemClicking += new EventHandler(InjuryCostToolBar_ActionMenuItemClicking);
        this.InjuryCostToolBar.ActionMenuItemClicked += new EventHandler(InjuryCostToolBar_ActionMenuItemClicked);
        this.InjuryCostToolBar.SetMenuItemProperties += new EventHandler(InjuryCostToolBar_SetMenuItemProperties);
        this.AxCostGrid.RowInserted += new EventHandler(CostGrid_RowInserted);
        this.AxCostGrid.RowCreated += new GridViewRowEventHandler(CostGrid_RowCreated);
        this.AxCostGrid.RowEditing += new GridViewEditEventHandler(CostGrid_RowEditing);

    }

    ApplicationProxy.EPFormAction FormMode
    {
        get
        {
            return (ApplicationProxy.EPFormAction)Convert.ToInt16(
            this.Page.Request.QueryString.Get("mode")); // This mode is the param set in web menu item url, i.e. mode=1
        }
    }
    private ISession AxSession
    {
        get
        {
            AxBaseWebPart webpart = AxBaseWebPart.GetWebpart(this);
            return webpart == null ? null : webpart.Session;
        }
    }
    private void SetupMode()
    {
        //Proxy.Info objInfoLog = new Proxy.Info(this.AxSession.AxaptaAdapter);
        //objInfoLog.add(Proxy.Exception.Warning, Convert.ToString(this.FormMode));
        switch (this.FormMode)
        {
            case ApplicationProxy.EPFormAction.EditMode:
                
                this.HRMInjuryIncidentForm.DefaultMode = DetailsViewMode.Edit;
                this.HRMInjuryIncidentForm.AutoGenerateEditButton = true;
                this.HRMInjuryIncidentForm.AutoGenerateInsertButton = false;
                break;
            
            case ApplicationProxy.EPFormAction.CreateMode:
                this.HRMInjuryIncidentForm.DefaultMode = DetailsViewMode.Insert;
                this.HRMInjuryIncidentForm.AutoGenerateEditButton = false;
                this.HRMInjuryIncidentForm.AutoGenerateInsertButton = true;
                break;

            default:
                this.HRMInjuryIncidentForm.DefaultMode = DetailsViewMode.ReadOnly;
                this.HRMInjuryIncidentForm.AutoGenerateEditButton = false;
                this.HRMInjuryIncidentForm.AutoGenerateInsertButton = false;
                
                this.AxCostGrid.AllowEdit = false;
                this.AxCostGrid.AllowDelete = false;
                break;
        }
    }

    /// COST TYPE
    private DataSetViewRow CostInjuryCurrentRow
    {
        get
        {
            try
            {
                DataSetView dsv = this.AxHRMInjuryIncidentDS.GetDataSet().DataSetViews[this.AxCostGrid.DataMember];
                return (dsv == null) ? null : dsv.GetCurrent();
            }
            // CurrentRow on the dataset throws exception in empty data scenarios
            catch (System.Exception)
            {
                return null;
            }
        }
    }

    private AxBaseWebPart WebPart
    {
        get { return AxBaseWebPart.GetWebpart(this); }
    }

    void CostGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
    {
        addClicked = false;
    }

          
    void CostGrid_RowEditing(object sender, GridViewEditEventArgs e)
    {
        addClicked = false;
    }
     
    void CostGrid_RowCreated(object sender, GridViewRowEventArgs e)
    {
        addClicked = false;
    }

    void CostGrid_RowInserted(object sender, GridViewInsertedEventArgs e)
    {
        addClicked = false;
    }
    
    void InjuryCostToolBar_SetMenuItemProperties(object sender, SetMenuItemPropertiesEventArgs e)
    {
        long record = 0;

        AxCostGrid.AllowEdit = this.FormMode != ApplicationProxy.EPFormAction.InfoMode;// true;
        
        if (this.CostInjuryCurrentRow != null)
            record = (long)this.CostInjuryCurrentRow.GetFieldValue("RecId");

        // Set the properties on the toolbar
        switch (e.MenuItem.MenuItemAOTName.ToLower())
        {
            case COSTTYPE_DELETE:
                e.MenuItem.Disabled = !(this.HRMInjuryIncidentDS.GetDataSet().DataSetViews[this.AxCostGrid.DataMember].Count > 0 ? true : false);
                break;

            case COSTTYPE_ADD:
                if (addClicked)
                {
                    e.MenuItem.Disabled = true;
                }
                else
                {
                    if (this.AxCostGrid.AllowEdit)
                    {
                        e.MenuItem.Disabled = false;
                    }
                    else
                    {
                        e.MenuItem.Disabled = true;
                    }
                }
                break;
        }
    }

    void InjuryCostToolBar_ActionMenuItemClicked(object sender, ActionMenuItemEventArgs e)
    {
        switch (e.MenuItem.MenuItemAOTName.ToLower())
        {
            // The add button 
            case COSTTYPE_ADD:
                try
                {
                    this.AxCostGrid.AllowInsert = true;

                    this.AxCostGrid.CreateRow();

                    addClicked = true;

                    // Disable the add button
                    e.MenuItem.Disabled = true;
                }
                catch (System.Exception exception)
                {
                    AxExceptionCategory exceptionCategory;
                    // Check if the exception was a fatal exception
                    if (!AxControlExceptionHandler.TryHandleException(this, exception, out exceptionCategory))
                    {
                        // Fatal exception, throw so as to be handled
                        throw;
                    }
                }
                break;

            // The delete button 
            case COSTTYPE_DELETE:
                try
                {
                    int selectedIndex = this.AxCostGrid.SelectedIndex;
                    if (selectedIndex != -1)
                    {
                        this.AxCostGrid.DeleteRow(selectedIndex);
                    }
                }
                catch (System.Exception ex)
                {
                    AxExceptionCategory exceptionCategory;
                    // This returns true if the exception can be handled here
                    if (!AxControlExceptionHandler.TryHandleException(this, ex, out exceptionCategory))
                    {
                        // The exception was fatal - in this case we re-throw.
                        throw;
                    }
                }
                break;
        }
    }

    void InjuryCostToolBar_ActionMenuItemClicking(object sender, ActionMenuItemClickingEventArgs e)
    {
        switch (e.MenuItem.MenuItemAOTName.ToLower())
        {
            case COSTTYPE_ADD:
            case COSTTYPE_DELETE:
                e.RunMenuItem = false;
                break;
        }
    }

    
    void CostGrid_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
    {
        try
        {
            // Only call CancelEdit when new row since we are manually adding it
            if (this.CostInjuryCurrentRow.IsNew)
                this.CostInjuryCurrentRow.CancelEdit();
        }
        catch (System.Exception exception)
        {
            AxExceptionCategory exceptionCategory;
            // Check if the exception was a fatal exception
            if (!AxControlExceptionHandler.TryHandleException(this, exception, out exceptionCategory))
            {
                // Fatal exception, throw so as to be handled
                throw;
            }
        }

        CancelRowEdit();
    }

    private void CancelRowEdit()
    {
        AxCostGrid.EditIndex = -1;
        AxCostGrid.AllowEdit = false;
    }


    void CostGrid_RowUpdated(object sender, GridViewUpdatedEventArgs e)
    {
        if (e.Exception == null)
        {
            DataSetViewRow dsvr = this.CostInjuryCurrentRow;

            if (dsvr != null)
            {
                bool rowSaved = true;
                try
                {
                    if (dsvr.IsNew)
                        dsvr.EndEdit();
                }
                catch (System.Exception ex)
                {
                    rowSaved = false;

                    AxExceptionCategory exceptionCategory;
                    // This returns true if the exception can be handled here
                    if (AxControlExceptionHandler.TryHandleException(this, ex, out exceptionCategory))
                    {
                        // If non fatal run error compensation logic
                        if (exceptionCategory == AxExceptionCategory.NonFatal)
                        {
                            // Keeps the current row editable i.e. reverts to the previous UI state
                            e.KeepInEditMode = true;
                        }
                    }
                    else
                    {
                        // The exception is system fatal - in this case we re-throw.                                    
                        throw;
                    }
                }

                if (rowSaved)
                {
                    CancelRowEdit();
                }
            }
        }
    }


    protected AxBoundField GetField(string name)
    {
        AxBoundField attendeeField = null;

        // Get the field which needs to have the customized lookup
        foreach (DataControlField field in this.AxCostGrid.DataControlFieldCollection)
        {
            AxBoundField boundField = field as AxBoundField;
            // If the field is not null and has the required data field
            if (boundField != null && String.Compare(boundField.DataField, name, true) == 0)
            {
                attendeeField = boundField;
                break;
            }
        }

        return attendeeField;
    }
}

Happy DAXing !!!!!

Dynamics AX EP form in Edit and Insert mode

Generally when we worked on designing detail EP form we have two options to open EP form in Insert and Edit mode, either design two separate EP forms with same piece of code except Designmode property set to Inset or Edit. Other way is to create single EP form and write code behind to open form in either mode. to do this design your EP form and create two web menu items and set parameters as follow:

mode=1 :- edit
mode=2 :- insert

Open your fom C# code behind and write following code:

    protected void Page_Load(object sender, EventArgs e)
    {
        this.SetupMode();
        
    }      

    ApplicationProxy.EPFormAction FormMode
    {
        get
        {
            return (ApplicationProxy.EPFormAction)Convert.ToInt16(
            this.Page.Request.QueryString.Get("mode")); // This mode is the param set in web menu item url, i.e. mode=1
        }
    }
    private ISession AxSession
    {
        get
        {
            AxBaseWebPart webpart = AxBaseWebPart.GetWebpart(this);
            return webpart == null ? null : webpart.Session;
        }
    }
    private void SetupMode()
    {
        //Proxy.Info objInfoLog = new Proxy.Info(this.AxSession.AxaptaAdapter);
        //objInfoLog.add(Proxy.Exception.Warning, Convert.ToString(this.FormMode));
        switch (this.FormMode)
        {
            case ApplicationProxy.EPFormAction.EditMode:
                
                this.Form1.DefaultMode = DetailsViewMode.Edit;
                this.Form1.AutoGenerateEditButton = true;
                this.Form1.AutoGenerateInsertButton = false;
                break;
            
            case ApplicationProxy.EPFormAction.CreateMode:
                this.Form1.DefaultMode = DetailsViewMode.Insert;
                this.Form1.AutoGenerateEditButton = false;
                this.Form1.AutoGenerateInsertButton = true;
                break;

            default:
                this.Form1.DefaultMode = DetailsViewMode.ReadOnly;
                this.Form1.AutoGenerateEditButton = false;
                this.Form1.AutoGenerateInsertButton = false;
                break;
        }
    }

You are all set to see this dynamic behavior.  just to recap here are the steps:


  1. Design and deploy new form with default ReadOnly mode 
  2. Create separate web menu items for Edit and Insert operations and set property Parameter=‘mode=1’ for Edit or ‘mode=2’ for insert.
  3. Get the session object by creating property AxSession
  4. Create FormMode() method in Form1.aspx.cs to get mode via a query string.
  5. Create SetupMode() method in Form1.aspx.cs 


Happy DAXing !!!!