POS not showing offline data jobs

In Dynamics 365 the offline story on the MPOS has been significantly improved since AX 2012. Now it’s more or less a click on the register in Dyn365, install the POS and distribute data. A bit simplified approach to life but anyways.

Here’s something I’ve seen a couple of times now. There’s just no jobs and nothing to process …No offline jobs

The event log gives it away a bit:

Failed to get offline sync data in offline database due to Exception. Error Details: Data Source=localhost\SQLEXPRESS;Initial Catalog=RetailOfflineDatabase;Integrated Security=True;Persist Security Info=False;Pooling=True;Encrypt=True;TrustServerCertificate=True

offline error 1

And in the details it’s clear that we’re facing a rights issue here. But in SQL Express with no management tools on the POS machine we don’t have many configuration options and even less when we’re in a setup with a large number of registers.

All you need to do is add the user logged in to Windows to these two groups on the local machine:

User groups

Log off and on again to activate the changes. Start your POS and check the database connection status. Hopefully, you should see a lot of jobs now:

Offline jobs

Error when pushing catalog data to the retail server

While implementing at a retail customer we were stuck for a while with an occasional error in the data distribution of job 1150 (Catalog). Going through the looong error message it indicated that it couldn’t truncate a text field on the RetailPubCatalog table.

I’ve added the error message in the bottom of this post as reference.

When looking at the table definitions on the SQL server we quickly discovered that on the D365O table the ModifiedBy field on the RetailPubCatalog was a 20 characters field and on the Retail server side it was only 8 characters long.

Going through the content of the data package we saw why it wasn’t failing every time. Only some of the catalogs where modified by a user with more than 8 characters meaning that when only a given user was the last to modify the job failed.

The fix is simple. Run this on the retail server database to expand the field:

alter table [ax].RETAILPUBCATALOG alter column MODIFIEDBY nvarchar(20) not null

You can’t change the field size through the designer, so you need to script your way out of this.

Hopefully, this error will be fixed in a future update. Going through the database it didn’t have the ModifiedBy field on any other table than this.


Error message:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> Microsoft.Dynamics.Retail.CommerceDataExchange.ProcessDataPackageException: Error occurred when running SqlTargetRequestHandler. —> Microsoft.Dynamics.Retail.CommerceDataExchange.SqlMergeRequestRunException: Failed to merge data into table [AX].[RETAILPUBCATALOG]. Query: MERGE [AX].[RETAILPUBCATALOG] AS dstUSING (SELECT [CREATEDDATETIME],[ENABLESNAPSHOT],[MODIFIEDBY],[MODIFIEDDATETIME],[ORIGIN],[OWNER],[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO],[RECID],[STATE],[VALIDFROM],[VALIDFROMDATETIME],[VALIDTO] FROM [#AX_RETAILPUBCATALOG_ea4a00d0-7897-4567-9e8f-ae569c284074]) AS srcON (dst.[RECID]=src.[RECID])WHEN MATCHED THEN  UPDATE SET [CREATEDDATETIME]=src.[CREATEDDATETIME],[ENABLESNAPSHOT]=src.[ENABLESNAPSHOT],[MODIFIEDBY]=src.[MODIFIEDBY],[MODIFIEDDATETIME]=src.[MODIFIEDDATETIME],[ORIGIN]=src.[ORIGIN],[OWNER]=src.[OWNER],[PUBLISHEDDATETIME]=src.[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM]=src.[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO]=src.[PUBLISHEDVALIDTO],[STATE]=src.[STATE],[VALIDFROM]=src.[VALIDFROM],[VALIDFROMDATETIME]=src.[VALIDFROMDATETIME],[VALIDTO]=src.[VALIDTO]WHEN NOT MATCHED THEN  INSERT ([CREATEDDATETIME],[ENABLESNAPSHOT],[MODIFIEDBY],[MODIFIEDDATETIME],[ORIGIN],[OWNER],[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO],[RECID],[STATE],[VALIDFROM],[VALIDFROMDATETIME],[VALIDTO])  VALUES (src.[CREATEDDATETIME],src.[ENABLESNAPSHOT],src.[MODIFIEDBY],src.[MODIFIEDDATETIME],src.[ORIGIN],src.[OWNER],src.[PUBLISHEDDATETIME],src.[PUBLISHEDVALIDFROM],src.[PUBLISHEDVALIDTO],src.[RECID],src.[STATE],src.[VALIDFROM],src.[VALIDFROMDATETIME],src.[VALIDTO]);DROP TABLE [#AX_RETAILPUBCATALOG_ea4a00d0-7897-4567-9e8f-ae569c284074]; —> Microsoft.Dynamics.Retail.CommerceDataExchange.SqlWriteRequestRunException: Failed to run SqlWriteRequestRunner for table [AX].[RETAILPUBCATALOG]. Query: MERGE [AX].[RETAILPUBCATALOG] AS dstUSING (SELECT [CREATEDDATETIME],[ENABLESNAPSHOT],[MODIFIEDBY],[MODIFIEDDATETIME],[ORIGIN],[OWNER],[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO],[RECID],[STATE],[VALIDFROM],[VALIDFROMDATETIME],[VALIDTO] FROM [#AX_RETAILPUBCATALOG_ea4a00d0-7897-4567-9e8f-ae569c284074]) AS srcON (dst.[RECID]=src.[RECID])WHEN MATCHED THEN  UPDATE SET [CREATEDDATETIME]=src.[CREATEDDATETIME],[ENABLESNAPSHOT]=src.[ENABLESNAPSHOT],[MODIFIEDBY]=src.[MODIFIEDBY],[MODIFIEDDATETIME]=src.[MODIFIEDDATETIME],[ORIGIN]=src.[ORIGIN],[OWNER]=src.[OWNER],[PUBLISHEDDATETIME]=src.[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM]=src.[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO]=src.[PUBLISHEDVALIDTO],[STATE]=src.[STATE],[VALIDFROM]=src.[VALIDFROM],[VALIDFROMDATETIME]=src.[VALIDFROMDATETIME],[VALIDTO]=src.[VALIDTO]WHEN NOT MATCHED THEN  INSERT ([CREATEDDATETIME],[ENABLESNAPSHOT],[MODIFIEDBY],[MODIFIEDDATETIME],[ORIGIN],[OWNER],[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO],[RECID],[STATE],[VALIDFROM],[VALIDFROMDATETIME],[VALIDTO])  VALUES (src.[CREATEDDATETIME],src.[ENABLESNAPSHOT],src.[MODIFIEDBY],src.[MODIFIEDDATETIME],src.[ORIGIN],src.[OWNER],src.[PUBLISHEDDATETIME],src.[PUBLISHEDVALIDFROM],src.[PUBLISHEDVALIDTO],src.[RECID],src.[STATE],src.[VALIDFROM],src.[VALIDFROMDATETIME],src.[VALIDTO]);DROP TABLE [#AX_RETAILPUBCATALOG_ea4a00d0-7897-4567-9e8f-ae569c284074]; —> Microsoft.Dynamics.Retail.CommerceDataExchange.PerformWriteOperationException: Error when writing data to table [AX].[RETAILPUBCATALOG]. Query: MERGE [AX].[RETAILPUBCATALOG] AS dstUSING (SELECT [CREATEDDATETIME],[ENABLESNAPSHOT],[MODIFIEDBY],[MODIFIEDDATETIME],[ORIGIN],[OWNER],[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO],[RECID],[STATE],[VALIDFROM],[VALIDFROMDATETIME],[VALIDTO] FROM [#AX_RETAILPUBCATALOG_ea4a00d0-7897-4567-9e8f-ae569c284074]) AS srcON (dst.[RECID]=src.[RECID])WHEN MATCHED THEN  UPDATE SET [CREATEDDATETIME]=src.[CREATEDDATETIME],[ENABLESNAPSHOT]=src.[ENABLESNAPSHOT],[MODIFIEDBY]=src.[MODIFIEDBY],[MODIFIEDDATETIME]=src.[MODIFIEDDATETIME],[ORIGIN]=src.[ORIGIN],[OWNER]=src.[OWNER],[PUBLISHEDDATETIME]=src.[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM]=src.[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO]=src.[PUBLISHEDVALIDTO],[STATE]=src.[STATE],[VALIDFROM]=src.[VALIDFROM],[VALIDFROMDATETIME]=src.[VALIDFROMDATETIME],[VALIDTO]=src.[VALIDTO]WHEN NOT MATCHED THEN  INSERT ([CREATEDDATETIME],[ENABLESNAPSHOT],[MODIFIEDBY],[MODIFIEDDATETIME],[ORIGIN],[OWNER],[PUBLISHEDDATETIME],[PUBLISHEDVALIDFROM],[PUBLISHEDVALIDTO],[RECID],[STATE],[VALIDFROM],[VALIDFROMDATETIME],[VALIDTO])  VALUES (src.[CREATEDDATETIME],src.[ENABLESNAPSHOT],src.[MODIFIEDBY],src.[MODIFIEDDATETIME],src.[ORIGIN],src.[OWNER],src.[PUBLISHEDDATETIME],src.[PUBLISHEDVALIDFROM],src.[PUBLISHEDVALIDTO],src.[RECID],src.[STATE],src.[VALIDFROM],src.[VALIDFROMDATETIME],src.[VALIDTO]);DROP TABLE [#AX_RETAILPUBCATALOG_ea4a00d0-7897-4567-9e8f-ae569c284074]; —> System.Data.SqlClient.SqlException: Violation of UNIQUE KEY constraint ‘I_-1981983829_-162312163’. Cannot insert duplicate key in object ‘ax.RETAILPUBCATALOG’. The duplicate key value is (5637145329).The statement has been terminated.   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlWriteRequestRunner.PerformWriteOperation(SqlConnection connection)   — End of inner exception stack trace —   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlWriteRequestRunner.PerformWriteOperation(SqlConnection connection)   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlWriteRequestRunner.Run(SqlConnection connection)   — End of inner exception stack trace —   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlWriteRequestRunner.Run(SqlConnection connection)   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlMergeRequestRunner.Run(SqlConnection connection)   — End of inner exception stack trace —   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlMergeRequestRunner.Run(SqlConnection connection)   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlTargetRequestHandler.ProcessWriteRequest(SqlConnection connection)   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlTargetRequestHandler.ProcessDataPackage(DataPackage dataPackage)   — End of inner exception stack trace —   at Microsoft.Dynamics.Retail.CommerceDataExchange.SqlTargetRequestHandler.ProcessDataPackage(DataPackage dataPackage)   at Dynamics.AX.Application.RetailCdxChannelDbDirectAccess.runDownload() in xppSource://Source/Foundation\AxClass_RetailCdxChannelDbDirectAccess.xpp:line 215   — End of inner exception stack trace —

Background images on AX POS

The POS UI in AX can be customised in many ways and one of the more dramatic ones are changes in the background images. The steps are few and goes like this:

Open the Images form



Create the images in the Images table. In this case we create two. This may vary in your situation


Open the Visual profiles form


Create a visual profile and add the images here


Create a register and device and add the visual profile to the register


To get this running on the POS you need to distribute data. Job 1090 should be sufficient. When the data is applied you are ready to enjoy the results:




This is just the basics of what you can do, but I hope you get the idea of what is possible.

Running the CRT samples on AX7

The RetailSDK delivered with AX7 includes a lot of great sample code making it easier to get things rolling when learning how to customise the solution.

One of the sample projects is the CommerceRuntimeSamples. Before you are able to run it you need to do a couple of tweaks though. If not it will crash and burn with error messages that do point you in the right direction on how to fix it. This blog post is made to safe you some time and getting it fixed without having to go troubleshooting.

The first error that pops up is this one:


A configuration error in the Microsoft.Dynamics.Commerce.Runtime.dll. The reason is that it cannot find the right Operation Unit Id. It is specified in the commerceruntime.config and all you have to do is put in the operating id of the channel you would like to work with. In this case I use Houston, which has the id 039:


Next is this error:


A storage exception in the same dll and same piece of code. This time we have to look in the app.config file. In here we have a list of connection strings that all point at database names as they appeared in AX 2012 Retail. In AX7 demo servers all data for all channels is in the AxDB database so the fix is to change the database names in the connection strings to AxDB:


Now you are able to run the samples and start debugging to learn.




“Invalid package number range” error in AX Retail CDX

I stumbled across the above error running the P-jobs in an AX 2012 R2 installation the other day. It popped up in a test environment and to be honest we had been a bit rough to the message database; but nothing that should mess things up. The reason behind the error was probably a conflict between the current package number and a previously handled package number.

Starting the troubleshoot we quickly realise that there is no number sequence to pull the package numbers from (the package number is added to the records in the message database to identify the messages).

The quick (and dirty) solution was to manually increase the highest package number in both in- and outgoing to a number a certain amount higher. Make sure to mark the records with an error as finished, restart the service and start the distribution from AX again.

The service will now pull the next package number based on the new highest number + 1. If that does not do the trick try increasing the number even more.


Added 26th of April 2016:

Here’s a sql script in case you need to do a complete renumbering of the package numbers:

-- Add column for temporary package number
ALTER TABLE IncomingMessages ADD PackageNo2 INT NULL

-- Fill temp package number. In this case start it of by 2000000
SET @id = 2000000

UPDATE IncomingMessages
SET @id = PackageNo2 = @id + 1

-- Overwrite the package number on the outgoing packages using the old package number as reference
-- Notice: if you start the new numbering too low you can mix up the package numbers on the outgoing table
UPDATE outgoing
SET outgoing.PackageNo = incoming.PackageNo2
FROM OutgoingMessages AS outgoing
INNER JOIN IncomingMessages incoming ON outgoing.packageNo = incoming.PackageNo

-- Update the package number on the incoming messages
UPDATE IncomingMessages
SET PackageNo = PackageNo2

-- Get rid of the temporary column
ALTER TABLE dbo.IncomingMessages

Annoying error when configuring the Commerce Data Exchange service

Sometimes it is easy peasy … and sometimes it is not. This one leans towards the not and does it in an annoying way.

I was running the PowerShell script for configuring the Commerce Data Exchange. It prompts you for user, password, path for the binaries and the certificate thumbprint … not anything complicated. And although I had knew that I had done it successfully before I was stuck with this error:

Get-Content : Cannot find path 'C:\inetpub\DynamicsAxRetail\CommerceDataExchangeRealtimeService\Web.config' because it does not exist.
At C:\Program Files (x86)\Microsoft Dynamics AX\60\Commerce Data Exchange\Real-time Services\6.2\Sample Deployment Scripts\InstallCommerceDataExchangeRealtimeService.ps1:713 char:34
+         $WebConfigXML = [XML] (gc <<<<  $WebConfigFilePath)
    + CategoryInfo          : ObjectNotFound: (C:\inetpub\Dyna...vice\Web.config:String) [Get-Content], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand

I tried several times. Restarted. Tried again. Tried as another user. Tried beating my head against the wall. Nothing seemed to be working.

The solution was deleting one character from the binary path. I just used

C:\Program Files (x86)\Microsoft Dynamics AX\60\Commerce Data Exchange\Real-time Services\6.2

instead of

C:\Program Files (x86)\Microsoft Dynamics AX\60\Commerce Data Exchange\Real-time Services\6.2\

and after removing the backslash at the end of the path string it installed without any problems …. Grrrrrrr …..

Troubleshooting the Commerce Data Exchange

In AX 2012 troubleshooting the Commerce Data Exchange is necessary. It’s somewhat a blackbox but we do have a few tools in the belt and handles to pull.

This post describes a couple of these in AX 2012 R2. The following versions are a bit more informative; but some of the tips are still relevant.


What’s in the queues?

The communication flow is passed through the SQL server and during installation you are asked for a message box database. When looking into this database two of the tables are showing you the flow of messages and a few related (general) pieces of information. I use the following SQL statements as a standard approach to these tables:

SELECT JobID, Status, TryCount, ErrorNo, ServerMsg, FinishedDateTime, PackageNo, ServiceName 
FROM [RetailMsgDB].[dbo].[IncomingMessages]
ORDER BY FinishedDateTime DESC
SELECT JobID, Status, TryCount, ErrorNo, ServerMsg, FinishedDateTime, PackageNo, ServiceName 
FROM [RetailMsgDB].[dbo].[OutgoingMessages]
ORDER BY FinishedDateTime DESC

delete from IncomingMessages
delete from OutgoingMessages

The result of the query looks something like this:


The first result set shows the messages going in to the server and the second result set shows the outbound. As long as the ErrorNo is 0 you are good. If it does show up with an error you need to start digging a bit. The JobID column shows you in which job to look.

Notice that I have to delete statements disabled by comment-tags. These are nice when you would like to reset the contents of the queue-tables. To execute the you need to mark them (without the /* and */) and execute.


Getting info from the log file and packages

The data exchange service offers a couple of tricks regarding its log file and the packages. The level of informations is setup in the Service Settings:


This offers lot of settings for the service but in this post I will only be touching a couple of them.


First, make sure you customize the right service and click Next until you get access to the Working Directory. This is where the files are dumped for processing by the service.


Moving on we can change the settings for the log file.


We have several relevant settings in this part. First of all the directory for the log file and the Log Level. As default it logs the errors only and that is often enough. If you want it to be more chatty you just click in what you want to know from the service. Notice, that the log file does get a bit overwhelming to look at if you click on everything.

Reading the log file can give you a very specific error to work with. With a field mismatch it could look a bit like this:

2016.2.24 9:40:27:412 (17528) [1] CSockConn::Listen: bind failed
2016.2.24 9:40:27:417 (17528) [1] AdminThread: ERROR: Listen failed on port 23. Check the Retail Store Connect setup for server HJHVIN02
2016.2.24 9:44:43:318 (14236) [1] CCommMgr::HandleException: Target request handler failed to process target request header: Microsoft.Dynamics.Retail.StoreConnect.Request.SQLHandler.ProcessTargetRequestHeaderException: ProcessTargetRequestHeader failed to execute all write requests. ---> Microsoft.Dynamics.Retail.StoreConnect.Request.SQLHandler.ProcessWriteRequestException: Write request on table:[dbo].[RETAILPOSITIONPOSPERMISSION] failed to execute. ---> Microsoft.Dynamics.Retail.StoreConnect.Request.SQLHandler.RunException: Run() failed while creating temporary table. ---> Microsoft.Dynamics.Retail.StoreConnect.Request.SQLHandler.CreateTempTableException: Query: SELECT TOP 0 [ALLOWBLINDCLOSE],[ALLOWCHANGENOVOID],[ALLOWCREATEORDER],[ALLOWEDITORDER],[ALLOWFLOATINGTENDERDECLARATION],[ALLOWMULTIPLELOGINS],[ALLOWMULTIPLESHIFTLOGON],[ALLOWOPENDRAWERONLY],[ALLOWPASSWORDCHANGE],[ALLOWPRICEOVERRIDE],[ALLOWRESETPASSWORD],[ALLOWRETRIEVEORDER],[ALLOWSALESTAXCHANGE],[ALLOWTENDERDECLARATION],[ALLOWTRANSACTIONSUSPENSION],[ALLOWTRANSACTIONVOIDING],[ALLOWXREPORTPRINTING],[ALLOWZREPORTPRINTING],[MANAGERPRIVILEGES],[MAXIMUMDISCOUNTPCT],[MAXLINEDISCOUNTAMOUNT],[MAXLINERETURNAMOUNT],[MAXTOTALDISCOUNTAMOUNT],[MAXTOTALDISCOUNTPCT],[MAXTOTALRETURNAMOUNT],[NAME],[POSITION],[POSPERMISSIONGROUP],[RECID],[USEHANDHELD] INTO [#dbo_RETAILPOSITIONPOSPERMISSION_6a5067cd-ba66-41c4-bf8f-da7dc918b25e] FROM [dbo].[RETAILPOSITIONPOSPERMISSION];
 ---> System.Data.SqlClient.SqlException: Invalid column name 'ALLOWPASSWORDCHANGE'.



Another feature is the “Keep Packages Files”. It keeps the files in the working folder for later review. Again, this will leave you with a lot of data in the directory.

With the Keep Package Files set you get a couple of files in the work folder with the .tmp extension. One that ends with an I and one that ends with an R. The I file is the definition of the data model and the R file is the actual data. As is they are close to unreadable. So to get the result we can use the Pack Viewer tool. It is started from the Start menu next to the Service Settings.


Select the file you want to convert. The target folder is automatically filled in. You can change it without any problems. Mark the Open Folder to open the target folder when done and click the Convert button.

The I file gives you one file that looks like this:


Converting the R file you get a multiple files depending on the number of tables in the package:


They are named with the table name for easy access. The SCTargetRequestHeader file is a content and action overview. The data files are easy(-ish) read XML files with the complete data set to be transferred.


Remember to disable the keep package flag when done and restart the service.


This is not the full and complete troubleshooting guide but a quick intro to a couple of entry points when struggling with an AX 2012 R2 Retail.