Microsoft Dynamics AX Support

This blog contains posts by the Microsoft Dynamics AX Support teams Worldwide

AX for Retail: Customizing the Retail Transaction Service

AX for Retail: Customizing the Retail Transaction Service

Rate This
  • Comments 6

[Update: April 18, 2012 - This ability to customize the Transaction Service has been greatly enhanced in AX for Retail 2012.  Please see this article for information.]

A common request that we get from customers wanting to extend the AX for Retail is how to customize the Retail Transaction Service to send custom data back and forth between the POS and Headquarters.  While the Retail Transaction Service is not designed to be customizable, there is a way to piggy-back on existing functionality to extend its functionality.  While this is not a supported method, it’s very powerful.

Before digging into the details, a little background on the Retail Transaction Service.

All communication between the POS and Headquarters (The Dynamics AX Application Object Server or AOS) is handled by the Retail Transaction Service (RTS).  Examples of this communication of calls from the POS to Headquarters might be adding a new customer, querying a gift card balance, and adding points to a customer’s loyalty card.  Anything that needs to be handled from a central location (HQ) in real time goes through the Transaction Service.

If you were to dig into the RTS, you would see that the architecture is relatively simple.  RTS is a standard Windows Service and is configured to listen on a specified TCP/IP port.  All communication from each POS comes through standard TCP/IP calls (no domain authentication necessary!).  In turn, the RTS communicates to the Dynamics AX AOS via the standard .Net Business Connector.  This communication is handled like any other AX Business Connector client.

The RTS itself pretty much just handles the traffic.  It has a pre-defined set of methods that can be called by the POS.  Each of these methods then uses the Business Connector to call a matching method in the PosIsTransactionService class in AX.  This is done synchronously, so the POS waits until RTS returns a result (success or failure) along with any data associated with it.

The interesting thing about the calls from the POS to the AOS (via the RTS) [yikes] is in how data is passed back and forth.  In Dynamics AX 2009 there isn’t a great way to match up AX objects with .Net objects.  This means that a Sales Order object (for instance) might get converted to a large delimited string in the POS before getting passed to AX.  AX would then parse out this string and populate whatever objects it needs with the data.

This is a lot of information to answer a simple question:  how can I customize the RTS?

As mentioned, RTS is not truly customizable.  There is a pre-defined set of the methods that POS uses and you cannot add your own.  However, as is the case with all X++ code in AX, you can modify the code on the AX side of things.  And there are two RTS methods used by the POS to handle inventory transactions, each of which could be modified to handle different types of data and different business needs.

The two methods are ExportStoreInventoryData (get information from AX) and ImportStoreInventoryData (send information to AX).  These are multi-purpose methods, meaning one parameter (“cmd”) is used to tell the X++ code which branch of logic to take.  The basic idea is to add your own “cmd” parameter, call one of these methods with a specific string representing data, and then create new logic in X++ to handle that data.

Each of these commands use the same parameters:
•    succeeded (bool, reference variable): Whether the call to Transaction Service was successful
•    comment (string, reference variable):  The main "payout" of the call to the Transaction Service. 
•    cmd (string):  The command that Terminal Services will execute on the variable passed in.
•    hhtId (string):  The Terminal ID of the POS client making the call.  This can be found in the ApplicationSettings.Terminal.TerminalId application variable.
•    Entrytype (String):  First variable that can be sent to the command.
•    DocType (String): Second variable that can be sent to the command.

When calling either of these commands, you can use the parameters in the following manner: One parameter to identify the command (cmd), one parameter returned to note whether the call was succesful (succeeded), two input parameters (Entrytype and DocType), and one output parameter containing any data returned (comment).

Note that since the input parameters and main output parameter are string variables, you may need to be creative in passing data back and forth. Since you can do whatever you want with the string in the X++ code, you can use any logic to convert data to string and back to data again. For example, if you have multiple columns and rows of data, you can send the data as an XML string or as a tab-delimited set of values with a newline separating lines.

To create your own command ("cmd" parameter), you modify the following methods the HHTStoreInventoryService class in the AOT: ExportHHTData() and ImportHHTData(). Simply add a new case to the switch statement (this is the ExportHHTData method):

        case #HHT_STOCKCOUNT:
output = fileWriter.writeStockCount(HHTHandheldSetup::find(hhtId));
output = "This is the output from mycommand.";

To test your new method, use the following code (C#) in your POS plugin to call the Retail Transaction Service:

            bool succeeded = false;
string returnstring = string.Empty;
string cmd = "MYCOMMAND";
string terminal = LSRetailPosis.Settings.ApplicationSettings.Terminal.TerminalId;
string string1 = string.Empty;
string string2 = string.Empty;
LSRetailPosis.TransactionServices.ExportStoreInventoryData(ref succeeded, ref returnstring, cmd, terminal, string1, string2);
if (succeeded)
//Do something with the "returnstring" variable
//Return an error to the user that Transaction Service call failed
As previously mentioned, there is quite a bit of work involved in the details of getting this to work, and it’s not supported, but as it the case with all customizations, once you have a way to do something, as a developer you can support this along with your other customizations.
Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post
  • How to  get the logs of retail transaction service am getting an error at POS while processing payment against sales order as fulfillment warehouse not found. Am not able to find any such configuration in warehouse. am using ax retail r2 refresh. It will be a great help

  • Hi shrine,

    am struggling with below given issue,  i will be able to add successfully the Sales orders to POS application. I can create a packing list as well from POS.

    After adding the transaction to POS , during tendering provides an error full fulfillment warehouse not specified. If i go to ax client and invoice the same . It is posting successfully.

    Could you please help me on this, i am trying to find a method to get the transaction service log to find the log error coming from ax. How to trace the logs in transaction service i put the log mode to debug but where can i find the result logs for this.

    Your help is highly appreciated, am struggling from my end for last 4 days. Please help me if u can.

  • Hi Sajeer, here are a couple of recent articles that may be able to help you:

    If you're still having the "fulfillment warehouse not specified" issue, please open a support incident and we'll see if we can help you out.

  • Hi All,

    I have been facing the same error for ling time,The main casue as nothing to do with the error message"fullfillment warehouse not specified "! there is one number sequence which has in consisitancy and it is name is Ledger1 ,attached to the customer payment journal used to post the POS sales order.

    You need to keep cleaning this number sequence and delete the free list of that number sequence to resolve this issue



  • Hi Shane,

    I am doing customization on AX 2012 R2, the requirement is create bulk upload orders received from many customers and they should be processed automatically by clicking on a button "Upload Orders". But my problem is how to create a Retail Transaction object for every order (i.e. what are the prerequisite, or what fields I have to set in that object). after creating transaction object it should also calculate discount, tax and price for that and after this when I call payment method, it should be save in database in transaction (default) tables.

  • The issue is entirely different than the message shown on scree. It happened because of locking ledger account associated with the advance payment, any how we completed this implementation few years back successfully

Page 1 of 1 (6 items)