AX for Retail 2012 R2: Working with Custom Fields for Receipts
Note: (2013-May-31): We recently published a hotfix that backports this functionality from AX 2012 R2 to AX 2012 R1 (Feature Pack). Please contact your Partner or Microsoft Dynamics Support for this hotfix (KB 2852548) if you would like to use this functionality.
In the initial release of AX for Retail 2012 we introduced the ability to add custom fields to sections of the till layout.
In the recently-released AX for Retail 2012 R2 we have added custom fields for receipt layouts as well. This is a nice addition to the product; in order to accomplish this in previous releases you had “repurpose” infrequently-used fields (Euro Auth Code, Pharmacy Dosage Type??) and replace their value in the Printing service. While the new functionality still requires a little coding, it results in a much more maintainable customization.
This article will show you how to add two fields to your receipt: a line item field that shows the time that an item was added to a transaction and a header field that shows the total quantity of the entire transaction (similar to what you would see on a receipt at a warehouse club retailer).
Step 1: Creating the Custom Fields
Like the custom fields for till layout, receipt fields are defined in Headquarters on the Custom Fields form (Retail > Setup > POS > Profiles > Custom fields). For our example we will create two fields, both of type Receipt: TotalQty and TimeScanned.
A couple things to note here. First, any fields that you create are available in all three sections of the receipt format designer: Header, Lines, and Footer. Secondly, the Caption text ID is a unique identifier for the text that is going to show in the receipt format designer itself (unlike the custom fields for till layout which use the Caption text ID in the POS itself). The ID is still stored in the RetailLanguageText table but is only used at Headquarters. See the AX for Retail: Modifying POS Labels and Strings article for more information about labels and strings.
Since there is no form for adding strings to the RetailLanguageText table, we will populate the values directly in the AOT. Open a new developer workspace and navigate to Data Dictionary > Tables > RetailLanguageText. Right-click and select Open. Create two records by populating the languageID, Text and textID fields:
Step 2: Adding the Custom Fields to the Receipt Layout
After the fields are created they can immediately be added to any receipt format. Go to Retail > Setup > POS > Receipt formats and click on the Designer button for any receipt format:
If the fields and labels were created properly, you should be able to easily find them in the field list for any of the three sections:
Note: If you see something that looks like (22000)??Missing String?? you did not create the RetailLanguageText record correctly.
Find a place to drag the Total Quantity field onto the header section and add the Time Scanned to the lines section. Give each a hard-coded text label. Make sure to hit the Save button when you are finished (I tend to forget that step – in fact I just did so in writing up this article). Run the A-1090 or N-1090 job to push the new receipt to your POS database.
Step 3: Hook up the Custom Fields in Code
Now you need to write some code to translate the two fields into actual values. This happens in the FormModulation.cs file in the Printing service. The logic for this is pretty simple: the requested field name is passed in and a large switch statement is called to translate the field to a value. There are a number of “GetInfo” methods: values for the header and footer fields are handled in the GetInfoFromTransaction() method; for lines it is the GetInfoFromSaleLineItem() method. Since we are ultimately printing text to the receipt, the developer is responsible for converting any values into a string variable.
Here is the switch statement for GetInfoFromTransaction():
switch (itemInfo.Variable.ToUpperInvariant().Replace(" ", string.Empty)) { case "DATE": return ((IPosTransactionV1)theTransaction).BeginDateTime.ToShortDateString(); case "TIME24H": return ((IPosTransactionV1)theTransaction).BeginDateTime.ToString("HH:mm");
To print a value for your custom field, all you have to do is add your field name to the switch statement (note that we strip out all spaces and convert to upper case):
GetTotalQuantity() is a very simple helper method that you can add elsewhere in FormModulation class:
private string GetTotalQuantity(RetailTransaction theTransaction) { try { decimal qty = 0.0m; foreach (SaleLineItem s in theTransaction.SaleItems) { qty += s.Quantity; } return qty.ToString(); } catch { return string.Empty; } }
Step 4: Testing the Receipt
That’s all there is to it. Once you compile your Printing.dll service and copy it to the /Services subfolder in your POS installation, you can test it by running a transaction:
Step 5: Using PartnerData Fields for Line Items
Our header example used a simple calculated field to print a value. The real power is being able to extend the RetailTransaction object itself to store extended values which can then be printed on the receipt. This is done with the PartnerData object which was introduced in AX for Retail 2012 Feature Pack.
The PartnerData object is a generic collection that can be defined at runtime instead of compile time; fields can be stored at the transaction level, the sales line level, or the payment line level. These fields are then stored in transaction object and can be used in triggers or services. In our example we will create a field called “TimeAdded” on the sales line and then use it when printing the receipt.
Open the Triggers solution in Visual Studio and go to the ItemTriggers project. We have to add a few things to the project before adding our code:
- The PartnerData object relies on a feature introduced in C# 4.0. To use PartnerData in any of your POS code, your project needs to add a reference to Microsoft.Csharp
- Our example uses the SaleLineItem POS object which is in the Transaction class. Your project also needs a reference to the Transaction.DLL file from the POS installation folder. Make sure to set the Copy Local property to False when you add this reference.
- Finally, a using LSRetailPosis.Transaction.Line.SaleItem; line needs to be added to the top of your ItemTriggers.cs file
After this setup, we only need to add these two lines to the PreSale() method:
[...] public void PreSale(IPreTriggerResult preTriggerResult, ISaleLineItem saleLineItem, IPosTransaction posTransaction) {
SaleLineItem s = (SaleLineItem)saleLineItem; s.PartnerData.TimeAdded = System.DateTime.Now.ToString(“HH:mm:ss”);
Note that we are converting it to a string as we store it to PartnerData – we could have just as easily stored it as a DateTime value and converted it in the Printing plug-in. If we were doing calculations on the value (average time to scan an item??) we would have left it as a DateTime value.
Compile your ItemTriggers dll and copy it to the /Triggers subfolder in your POS installation.
Now we just need to read the TimeAdded value when printing sales lines on our receipt. This is done in the FormModulation.cs again, this time in the GetInfoFromSaleLineItem() method. Note that since we are now using PartnerData we also need to add a reference to Microsoft.CSharp in this project.
switch (itemInfo.Variable.ToUpperInvariant().Replace(" ", string.Empty)) {
case “TIMESCANNED”: returnValue = saleLine.PartnerData.TimeAdded;
break; case "TAXID": returnValue = saleLine.TaxGroupId; break;
Our updated receipt now also shows our scanned time:
As you can see by the small amount of code in this article, there really isn’t much development work involved in adding custom fields to receipts in AX for Retail 2012 R2. In discussions with Partners and Customers this topic comes up very frequently; I think this will be a popular feature of the product.
See the attached .zip file for customized ItemTriggers and Printing projects with the code samples mentioned above.