Friday, March 12, 2010

Using the .NET Business Connector to Export Sales Orders with Multiple Sales Lines into AX from a .NET Application: Part 1

One requirement that had been given to me was the ability for an existing .NET application to be enhanced to interface with AX. The existing application’s sole purpose was to decode and parse messages being sent to a specified email account, and to export data from these messages into an database. Since the old database and its parent application was going to be slowly phased out with the implementation of AX, the exporting application would need to be enhanced to be able to export key fields of these messages into AX as a Sales Order with multiple Sales Lines. After some thought, I concluded that the solution to this requirement was rather simple in concept, and would need to include an AX Class with one method (used to do the import into the SalesTable and SalesLine tables), as well as an upgrade to the .NET application, utilizing the .NET Business Connector (used to call and execute the AX method).

The basis for my AX method was inspired by a German Dynamics AX Blog, with a title that roughly translates to “Microsoft Dynamics AX API - Part 1: Creating Orders” , by Mathias Füßler. This gave me a good starting point for how to programmatically insert Sales Orders with a related Sales Line. As expected, I needed to make some modifications to the example code for it to work in Dynamics AX 2009, as well as to make it to do exactly what I needed it to do.

The first part of my derived solution for example, was to create a Class in AX, which we will call ImportToAX. This class would contain one key method that we will call ImportSalesOrder. Each Sales Order required a Customer Account number, and three Sales Lines including Total, Taxes, Fees; therefore, the ImportSalesOrder method should accept these required pieces of information as base type parameters.

// This is the only method in the ImportToAX Class
str ImportSalesOrder (str CustAccount, real Total, real Taxes, real Fees)
{

SalesTable salesTable;
SalesLine salesLine;
InventDim inventDim;
NumberSeq NumberSeq;
str retval;
;

retval = "";

try
{

// Obtain the next SalesId (Next Number Sequence)...

NumberSeq = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId().numberSequence);
salesTable.SalesId = NumberSeq.num();

// Create the Sales Order...

salesTable.initValue();
salesTable.CustAccount = CustAccount;
salesTable.deliveryDate = today();
salesTable.PurchOrderFormNum = "Imported Data";

salesTable.initFromCustTable();

salesTable.insert();

// Create the first Sales Line...

salesLine.clear();

salesLine.SalesId = salesTable.SalesId;

// The following three lines were added, because AX was requiring a defined site for inventory dimensions…
inventDim = salesLine.inventDim();
inventDim.InventSiteId = "01";
salesLine.setInventDimIdFromInventDim(inventDim);

salesLine.ItemId = ' Total ';
salesLine.SalesQty = 1;
salesLine.SalesUnit = 'EA';
salesLine.SalesPrice = Total;
salesLine.LineAmount = Total;

salesLine.createLine(NoYes::No, NoYes::Yes, NoYes::No, NoYes::No, NoYes::No, NoYes::No);

// Create the second Sales Line...

salesLine.clear();

salesLine.SalesId = salesTable.SalesId;
inventDim = salesLine.inventDim();
inventDim.InventSiteId = "01";
salesLine.setInventDimIdFromInventDim(inventDim);
salesLine.ItemId = 'Taxes';
salesLine.SalesQty = 1;
salesLine.SalesUnit = 'EA';
salesLine.SalesPrice = Taxes;
salesLine.LineAmount = Taxes;

salesLine.createLine(NoYes::No, NoYes::Yes, NoYes::No, NoYes::No, NoYes::No, NoYes::No);

// Create the third Sales Line...

salesLine.clear();

salesLine.SalesId = salesTable.SalesId;
inventDim = salesLine.inventDim();
inventDim.InventSiteId = "01";
salesLine.setInventDimIdFromInventDim(inventDim);
salesLine.ItemId = 'Fees';
salesLine.SalesQty = 1;
salesLine.SalesUnit = 'EA';
salesLine.SalesPrice = Fees;
salesLine.LineAmount = Fees;

salesLine.createLine(NoYes::No, NoYes::Yes, NoYes::No, NoYes::No, NoYes::No, NoYes::No);

retval = salesTable.SalesId;
}
catch
{
retval = "";
}

return retval;
}


The second part of the solution was to create a .NET Class utilizing the .NET Business Connector (which requires a reference to C:\Program Files\Microsoft Dynamics Ax\50\Client\Bin\Microsoft.Dynamics.BusinessConnectorNet.dll). The following .NET Class (C#) contains one core function which is used simply to connect to Dynamics AX, and then to execute the AX method with its required parameters:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Dynamics.BusinessConnectorNet;

namespace ImportToAXExample
{
public class ImportToAXClass
{

static public bool ImportOrder(string CustomerAccount, decimal Total, decimal Tax, decimal Fees)
{
Axapta ax;

bool Success = true;

try
{
ax = new Axapta();
ax.Logon(null, null, null, null);

AxaptaObject Import;
Import = ax.CreateAxaptaObject("ImportToAX");

object[] param = new object[4];
param[0] = CustomerAccount;
param[1] = Total;
param[2] = Tax;
param[3] = Fees;
Object retval = Import.Call("ImportSalesOrder", param);

if (retval.ToString() == "")
{
Success = false;
}

ax.Logoff();
}
catch()
{
Success = false;
}

return Success;
}

}
}

To tie it all together, this .NET Class could then be added to the existing .NET Application, and its only function, ImportOrder, could then be called from the application for each of the records that the application processes. Each time this function is called, required records within the SalesTable and SalesLine tables are created in AX.

1 comment: