Skip to main content

Creating sales orders from XML

This document has been migrated from TechNet.Navision.com - In this article we will show how a sales order may be created using the XML interface. We show a simple XML file containing the sales order, and describe how it ends up as a sales order in Axapta.
Consider a scenario where an application needs to create a sales order in Axapta. This application could be an MS office application (e.g a spreadsheet containing the sales order lines) or a web site created in another environment, that needs to access Axapta to do create a sales order. This sort of integration is easily done with XML, as we show in this example.
Consider a sales order:

4010
4012


OL-1000
3


OL-1500
4


PL-2500/Art
5

In this sales order, the customer with account number 4010 is ordering 4 Ol-1000, 4 OL-1500 and 5 PL-2500/ART. Although this is a simplified sales order, it will suffice for the presentation herein.Consider now the job below, where the XML document is read, the information extracted and then used to create the salesorder. Note carefully, that the code presented below is designed to show the how the sales order information is extracted from XML; it is not designed to show how to create sales orders as such. Better methods may exist for doing that, but the one presented here is reasonably simple, and does not clutter the picture with issues that are irrelevant to the XML content of this article. 1 static void Job5(Args _args)
2 {
3 SalesBasketLine salesBasketLine;
4 SalesBasket salesBasket;
5 SalesBasketId salesBasketId;
6 SalesAutoCreate_Basket salesAutoCreate;
7
8 XMLDocument doc;
9 XMLNode rootNode;
10 XMLNode custAccountNode, contactPersonIdNode, salesLineNode;
11 XMLNodeList salesLines;
12 XMLParseError xmlError;
13 int i;
14
15 // Get the XML document
16 doc = new XMLDocument();
17 doc.async(FALSE);
18 doc.load("salesorder.xml");
19 xmlError = doc.parseError();
20
21 if (xmlError && xmlError.errorCode() != 0)
22 {
23 print "Error: " + xmlError.reason();
24 pause;
25 return;
26 }
27
28 rootNode = doc.documentElement();
29
30 ttsbegin;
31
32 // At this point we have an xml document containing the sales order.
33 // Get the customer account from the document
34 custAccountNode = rootNode.selectSingleNode("//CustomerAccount");
35 contactPersonIdNode = rootNode.selectSingleNode("//ContactPersonId");
36
37 salesBasket.initValue();
38 salesBasket.custAccount = custAccountNode.text();
39 salesBasket.initFromCustTable();
40
41 salesBasket.salesBasketId = NumberSeq::newGetNum(ECPParameters::numRefSalesBasketId()).num();
42 salesBasket.ContactPersonId = contactPersonIdNode.text();
43
44 salesBasket.insert();
45
46 // Select all the sales lines into a nodelist
47 salesLines = rootNode.selectNodes("//SalesOrderLine");
48
49 for (i = 0; i < salesLines.length(); i++)
50 {
51 salesLineNode = salesLines.item(i);
52 salesBasketLine.clear();
53 salesBasketLine.initValue();
54
55 salesBasketLine.initFromSalesBasket(salesBasket);
56
57 salesBasketLine.itemId = salesLineNode.selectSingleNode("ItemId").text();
58 salesBasketLine.configId = '';
59 salesBasketLine.salesQty = str2num(salesLineNode.selectSingleNode("Qty").text());
60
61 salesBasketLine.insert();
62 }
63
64 ttscommit;
65
66 // Create the sales order from the basket info.
67 select forupdate salesBasketLine where salesBasketLine.salesBasketId == salesBasket.SalesBasketId;
68
69 salesAutoCreate = new SalesAutoCreate_Basket(salesBasketLine);
70 salesAutoCreate.create();
71
72 pause;
73 }
Let's walk through the code and see what happens. In line 16, after we have declared the objects we need and started a transaction, we create an XMLDocument variable and load the salesorder.xml file, with the sales order given above. The load call will read in the file and build an internal tree representation of the sales order. If this fails (because of syntax errors) the load method will return FALSE and an object (of type XMLParseError) is retrieved (using the parseError() method, in line 19). This object may then be used to diagnose what the problem is. There are several methods on the XMLParseError class that may be used to pinpoint precisely what went wrong, and where the error occurred. Once the document is correctly loaded, from line 28 and onwards, we may begin extracting information from it. We start off by storing the document's rootElement in the rootNode variable (in line 28). The rootNode will represent the toplevel node of the document, i.e. the node. We then proceed to fetch the node representing the customer account and contact person (lines 34 and 35). This is done by querying the tree, asking: "return the first node having the name CustomerAccount" and "return the first node having the name ContactPersonId". This is a simple application of the query language called XPath, that may be used to query the tree using arbitrarily complex search criteria. Once we have thes nodes in hand, we may call the text() method (lines 38 and 42), to retrieve the text values ("4010" and "4012" repectively). These values are used to initialize the salesBasket parameters. After we have created the sales basket (in line 44), we're ready to start adding items to it. We do this by selecting all the nodes named "SalesOrderLine" and collecting them in a list (called salesLines). This is what goes on in line 47. This list is then traversed in the for loop starting at line 49: The individual nodes are retrieved from the list using the item method (in line 51). Again, the selectSingleNode method is used to reference the ItemId (line 57) and the quantity fields (line 59). The item is then inserted in the sales basket (line 61). After this, we only have to actually generate the sales order from the sales basket, which is what goes on from line 66.As it may be seen from this example it is actually quite easy to use the XML classes to retrieve the information needed to perform a task in the application. All you need to do is to load the file into an XMLDocument (which performs error checking), and then you may use XPath queries to retrieve the nodes in the tree. In fact, the XML need not even be stored in a file, in which case you would use the loadXML method to load the tree from a string representing the XML.Remember, that the XML classes used in this example are written in the application layer (and not in the kernel), so they do not require any specific version of Axapta.

www.dynamic-ax.co.uk

Popular posts from this blog

Dynamics Axapta: Sales Orders & Business Connector

Well, again folllowing my same idea of writting close to nothing and pasting code, I'll paste in some code to create a sales order from some basic data and the invoice it. I'll try to explain more in the future. AxaptaObject axSalesTable = ax.CreateAxaptaObject("AxSalesTable"); AxaptaRecord rcInventDim = ax.CreateAxaptaRecord("InventDim"); AxaptaRecord rcCustTable = ax.CreateAxaptaRecord("CustTable"); rcCustTable.ExecuteStmt("select * from %1 where %1.AccountNum == '" + MySalesOrderObject.CustAccount + "'"); if (MySalesOrderObject.CurrencyCode.Trim().Length == 0) MySalesOrderObject.CurrencyCode = rcCustTable.get_Field("Currency").ToString().Trim(); string sTaxGroup = rcCustTable.get_Field("taxgroup").ToString().Trim(); //set header level fields axSalesTable.Call("parmSalesName", MySalesOrderObject.SalesName.Trim()); axSalesTable.Call("parmCustAccount", M

Passing values between form and class

Class name is EmplDuplication and Form is EmplTable . void clicked() {    MenuFunction mf;    args args = new Args();    ;     args.record(EmplTable);     mf = new menufunction(identifierstr(EmplDuplication), MenuItemType::Action); mf.run(args); } Meanwhile, in the main() method of the EmplDuplication class, we need to put this Axapta x++ code to get the datasource: static void main(Args args) {     EmplDuplication EmplDuplication; EmplTable localEmplTable; ;     if(args.record().TableId == tablenum(EmplTable)) localEmplTable = args.record();     ... }