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 (see my earlier post AX for Retail 2012: Working with Custom Fields for an example working with 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))
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)
decimal qty = 0.0m;
foreach (SaleLineItem s in theTransaction.SaleItems)
qty += s.Quantity;
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 (I like to print my receipts to Microsoft OneNote or XPS files for testing):
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:
After this setup, we only need to add these two lines to the PreSale() method:
public void PreSale(IPreTriggerResult preTriggerResult, ISaleLineItem saleLineItem, IPosTransaction posTransaction)
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))
returnValue = saleLine.TaxGroupId;
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.
Hi Shane Erstad
Thank you very much for your very helpful blog.
I got a stuck problem, I have a new receipt (Daily Sales grouping by product category) and have to print it from a button. How can I send data from a POS button (BlankOperations.dll) to POS Printing component (Printing.dll)?
Thank you in advance.
There are a couple of ways that you could approach this.
First of all, if you want to calculate and create the report directly in C#, you could do it like we do with the X report and the Customer Transaction report. Take a look at the Print() method in Customer\TransactionReport.cs for an example of how that could be done.
If you actually want to print a true "receipt" layout that you have created in HQ, you would have to call the Application.Services.Printing.PrintReceipt method from the Printing plug-in with a temporary transaction that you have create and the formtype that you are printing.
If it's a very simple report, I would recommend the first approach.